Build a one page portfolio website with WordPress

WordPress

one page

No doubt that the one page portfolio website is more and more popular in this year. It seems that it’s simple and clean, however, it’s not very easy to intergrate the one page system in WordPress, because you must think about how to sync the navigation menu and each page sections, this is one of a big nodus, and the other nodus is how to call the loop of each page sections on the home page. I will discuss how to make an one page portfolio WordPress Theme in the following tutorials, I’m emphasizing the most important steps.

First of all, nothing will make it easier than using a Ready One Page WordPress Theme, actually, we only need the one page framework, so whatever how about the appearance of this theme. For example, you can looking for a free or premium One Page WordPress Theme on google or Themeforest. All codes in this tutorials are from SimpleKey Theme. Well, let’s get down to bussiness!

First step: Sync the navigation and each page sections

We must improve the navigation, change all menu hyperlink to anchors, for example, change “http://domain.com/about” to “http://domain.com/#about”, so please put the following codes in functions.php

class description_walker extends Walker_Nav_Menu{
      function start_el(&$output, $item, $depth, $args){
           global $wp_query;
           $indent = ( $depth ) ? str_repeat( "t", $depth ) : '';
           $class_names = $value = '';
           $classes = empty( $item->classes ) ? array() : (array) $item->classes;
           $class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item ) );
           $class_names = ' class="'. esc_attr( $class_names ) . '"';
           $output .= $indent . '<li id="menu-item-'. $item->ID . '"' . $value . $class_names .'>';
           $attributes  = ! empty( $item->attr_title ) ? ' title="'  . esc_attr( $item->attr_title ) .'"' : '';
           $attributes .= ! empty( $item->target )     ? ' target="' . esc_attr( $item->target     ) .'"' : '';
           $attributes .= ! empty( $item->xfn )        ? ' rel="'    . esc_attr( $item->xfn        ) .'"' : '';
           if($item->object == 'page')
           {
                $varpost = get_post($item->object_id);
                if(is_home()){
                  $attributes .= ' href="#' . $varpost->post_name . '"';
                }else{
                  $attributes .= ' href="'.home_url().'/#' . $varpost->post_name . '"';
                }
           }
           else
                $attributes .= ! empty( $item->url )        ? ' href="'   . esc_attr( $item->url        ) .'"' : '';
            $item_output = $args->before;
            $item_output .= '<a'. $attributes .'>';
            $item_output .= $args->link_before . apply_filters( 'the_title', $item->title, $item->ID );
            $item_output .= $args->link_after;
            $item_output .= '</a>';
            $item_output .= $args->after;
            $output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
     }
}

At the meanwhile, you must set walker argument to new Description_walker in wp_nav_menu function as below:

<?php
   wp_nav_menu(array(
   'theme_location' => 'primary_navi',
   'echo' => true,
   'walker'=> new Description_Walker,
   'depth' => 4) );
?>

Then, all pages you have added to the navigation menu with custom menu will be changed to anchor links.

Second step: call the page loop in the home page

In this step, you must display all pages which you have added to the navigation menu. You’d better create a new home page, for example home.php,  add the pages loop first:

<?php 
query_posts('post_type=page');
while(have_posts() ) : the_post();
?>
     <div id="<?php echo $post->post_name;?>">//Add page content here</div>
<?php endwhile;?>

Then it will display all pages in your website, but we only need to call the pages which we have added to the navigation menu, so we should add the following codes in front of the query_posts() method.

if (($locations = get_nav_menu_locations()) && $locations['primary_navi'] ) {
        $menu = wp_get_nav_menu_object( $locations['primary_navi'] );
        $menu_items = wp_get_nav_menu_items($menu->term_id);
        $pageID = array();
        foreach($menu_items as $item) {
            if($item->object == 'page')
                $pageID[] = $item->object_id;
        }
    query_posts( array( 'post_type' => 'page','post__in' => $pageID, 'posts_per_page' => count($pageID), 'orderby' => 'post__in' ) );
}
        while(have_posts() ) : the_post();
        //Loop here.
        endwhile;

Looking at “primary_navi“, this is the custom menu name you have defined. That’s it, a basic one page theme is finished, you can try it. If you want to get the compete theme source, you can purchase and download the SimpleKey here.

43 thoughts on “Build a one page portfolio website with WordPress

  1. this just display me:
    //Add page content here
    //Add page content here
    //Add page content here
    //Add page content here
    //Add page content here
    //Add page content here
    //Add page content here
    //Add page content here
    //Add page content here

    can you please resolve this problem.

    1. Sorry, we are just provide support service for theme buyers. If you are our users, you can create an account on support forum and ask question there.
      Thanks!

    1. I just provide Simplekey theme for this techniques, and all important points is from this theme. Actually, I have thought about share a free simple single theme if I have enough time to do it.

  2. Hi there,
    great tutorial, thank you! works perfectly, i’m just wondering about one thing – have you resolved how to redirect the classic pages that are generated? for example if page1, page2 and page3 of a site are all displayed on one single page (the home), with the links mysite.com/#page1, etc – how do you make sure that mysite.com/page1/ redirects back to it?

    Would love your input!
    best,
    -jennyb

    1. Actually, you can add mysite.com/#page1 to the menu with custom link. This is the easily way to do that.
      Or reset the walker arugment in the wp_nav_menu(array(‘walker’=> new Description_Walker))

      class description_walker extends Walker_Nav_Menu{
            function start_el(&$output, $item, $depth, $args){
                 global $wp_query;
                 $indent = ( $depth ) ? str_repeat( "t", $depth ) : '';
                 $class_names = $value = '';
                 $classes = empty( $item->classes ) ? array() : (array) $item->classes;
                 $class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item ) );
                 $class_names = ' class="'. esc_attr( $class_names ) . '"';
                 $output .= $indent . '<li id="menu-item-'. $item->ID . '"' . $value . $class_names .'>';
                 $attributes  = ! empty( $item->attr_title ) ? ' title="'  . esc_attr( $item->attr_title ) .'"' : '';
                 $attributes .= ! empty( $item->target )     ? ' target="' . esc_attr( $item->target     ) .'"' : '';
                 $attributes .= ! empty( $item->xfn )        ? ' rel="'    . esc_attr( $item->xfn        ) .'"' : '';
                 if($item->object == 'page')
                 {
                      $varpost = get_post($item->object_id);
                      if(is_home()){
                        $attributes .= ' href="#' . $varpost->post_name . '"';
                      }else{
                        $attributes .= ' href="'.home_url().'/#' . $varpost->post_name . '"';
                      }
                 }
                 else
                      $attributes .= ! empty( $item->url )        ? ' href="'   . esc_attr( $item->url        ) .'"' : '';
                  $item_output = $args->before;
                  $item_output .= '<a'. $attributes .'>';
                  $item_output .= $args->link_before . apply_filters( 'the_title', $item->title, $item->ID );
                  $item_output .= $args->link_after;
                  $item_output .= '</a>';
                  $item_output .= $args->after;
                  $output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
           }
      }
      
    1. Need jquery code for the current section. An example below

      $(window).scroll(function() {
      var currentNode = null;
      $('.page-area').each(function(){
      var currentId = $(this).attr('id');
      if($(window).scrollTop() >= $('#'+currentId).offset().top - 79)
      {
      currentNode = currentId;
      }
      });
      $('#primary-menu li').removeClass('current-menu-item').find('a[href="#'+currentNode+'"]').parent().addClass('current-menu-item');
      });
      
    1. You should output the id=”page-slug” to each page section meanwhile as below:

      <section id="<?php echo $post->post_name;?>">
      
  3. Thanks for the brilliant article, it’s exactly what I was looking for – the other guides I looked at for building a single page site all seemed to begin with “Download this theme then we’ll edit it….” which kind of defeated the object.

  4. Hi there Johnny Woo

    Thanks for the cool theme I bought it (From themeforest ) to learn more – damn but you code is really neat!

    I have a silly question – I have started building my own custom page and with nav snippits from the theme (same as above ) – but my pages (that is created from the loop) doesn’t seem reorder when I adjust in the back-end.

    Am I missing something (probably)

    Thanks once again!

    1. Hi Pieter!

      Thanks for your purchased! Have you add your custom page to the primary menu with custom menu(Appearance > menus)?

      By the way, you can submit your using troubles to the support forum and tell me more details about your question, or post your wordpress login details with private reply.

      Thank you!

  5. I tried out this tutorial and it works pretty well. It did solve one major issue I was having. That is I couldn’t figure out how to only call the pages that were in the menu. So thank you for that. There is one other issue I have I had hoped you might be able to help with. I have been trying to solve this off and on for two years with zero luck. I can’t get my loop to call a page template. If I create a test page and put “Test” in on the page content, then assign a template to that page, All I get is the “Test”. The formatting of the page template is lost. Might you have a way to solve this? I got a $20.00 bill if you can solve this for me.

    1. @jamie, In this tutorial, I just tried to put all codes into index.php, but not the page template file, it means I called all different pages content in the homepage, but if you used these php code within a page template, no doubt that it will only display itself content “test”.

      Thanks

  6. get output:

    1st code snippet :

    //Add page content here
    //Add page content here
    //Add page content here
    //Add page content here
    //Add page content here

    2nd code snippet :

    empty array

  7. If you just want to change all menu hyperlinks to anchors, try this function instead:

    function start_el( &$output, $object, $depth = 0, $args = array(), $current_object_id = 0 ) {
    $html_item = ”;
    parent::start_el( $html_item, $object, $depth, $args );

    if (“page” === $object->object) {
    $post = (get_post($object->object_id));
    $html_item = str_replace ( $post->post_name , “#{$post->post_name}” , $html_item );
    }

    $output .= $html_item;
    }

  8. Hi, First of all great post Johnny. Your code works very charm. I have one question how is that possible to covert only those pages hyperlink to anchor that set to Yes by custom meta box on page. For e.g custom meta box ask that “Is this page a Section if Yes than convert to anchor else don’t convert . Thanks again for the great post..

    1. Hi, Hussain

      I think you need to use query_posts() function to detect which pages should be converted to the section. For example, let’s say the custom metabox field name is “set_to_section”, if select “yes”, then the value is “1”, then, you should use query_posts in front of “while” loop as below.

      query_posts('post_type=page&meta_key=set_to_section&meta_value=1');
      while.......
      ......
      endwhile;

      My solution is that if you add this page to the primary menu, then it will show as the a section.

  9. Hi Johnny I did it. I was not asking about querypost I was asking about nav walker. I added pages that only set to set_to_section from metabox. Here is my code for any one who is looking for this:

    class description_walker extends Walker_Nav_Menu{
    function start_el(&$output, $item, $depth= 0 , $args = array(), $id = 0){
    global $wp_query;
    $indent = ( $depth ) ? str_repeat( “t”, $depth ) : ”;
    $class_names = $value = ”;
    $classes = empty( $item->classes ) ? array() : (array) $item->classes;
    $class_names = join( ‘ ‘, apply_filters( ‘nav_menu_css_class’, array_filter( $classes ), $item ) );
    $class_names = ‘ class=”‘. esc_attr( $class_names ) . ‘”‘;
    $output .= $indent . ‘ID . ‘”‘ . $value . $class_names .’>’;
    $attributes = ! empty( $item->attr_title ) ? ‘ title=”‘ . esc_attr( $item->attr_title ) .'”‘ : ”;
    $attributes .= ! empty( $item->target ) ? ‘ target=”‘ . esc_attr( $item->target ) .'”‘ : ”;
    $attributes .= ! empty( $item->xfn ) ? ‘ rel=”‘ . esc_attr( $item->xfn ) .'”‘ : ”;
    if($item->object == ‘page’)

    {
    $varpost = get_post($item->object_id);
    $section_page = get_post_meta($item->object_id, “set_to_section”, true) ;
    if($section_page == “No”){
    $attributes .= ! empty( $item->url ) ? ‘ href=”‘ . esc_attr( $item->url ) .'”‘ : ”;
    }
    else if(is_home()){
    $attributes .= ‘ href=”‘.home_url().’/#’ . $varpost->post_name . ‘”‘;
    }else{
    $attributes .= ‘ href=”‘.home_url().’/#’ . $varpost->post_name . ‘”‘;
    }
    }
    else
    $attributes .= ! empty( $item->url ) ? ‘ href=”‘ . esc_attr( $item->url ) .'”‘ : ”;
    $item_output = $args->before;
    $item_output .= ‘‘;
    $item_output .= $args->link_before . apply_filters( ‘the_title’, $item->title, $item->ID );
    $item_output .= $args->link_after;
    $item_output .= ‘
    ‘;
    $item_output .= $args->after;
    $output .= apply_filters( ‘walker_nav_menu_start_el’, $item_output, $item, $depth, $args );
    }
    }

    Again Thanks for your rply..

  10. Hi there,

    I know this post is old, but is there an option to add a category section to the onepage website the same way the pages are added through the menu?
    I really don’t wanna create a page section for category which is kind of redundant to me.
    Thanks.

    1. In this method, all the one page sections are based on page. If user want to show the category list or the specific category’s posts, I think the only way is use a plugin which can provide the relevant shortcode, put the shortcode into the page content.

  11. hello everyone, iam very new to wordpress and facing difficulty in adding sections to the home page in simplekey theme, please help me in code level customizations. I can’t understand properly where to put and edit which code. I want to make a website exactly like this one: http://www.allwaysprivatetours.com/
    Your help would be highly appreciated, Thanks.

    1. by far i have added 4 new pages and they are now showing in home page but without any editing i mean without background and any parallex effect… please please help me ..

      1. This article only provides a general idea. If you want to add background and parallax effect, you should add some custom options(using custom field) for the page, allow users to add background image and turn on the parallax effect, then output those options(custom field) values to the HTML part.

Leave a Reply

Your email address will not be published. Required fields are marked *

×