Create one page loop from separate pages in index.php

Hi there,

I’m having a go at creating a one-page template using Roots using Skrollr.js (or something similar), but before I start digging into the whole anchor links/scrollTo stuff, I need to create a one-page loop.

I would like to manage the different pages separately in Worpdress, so I can always fallback to a normal website with separate pages. So I’m making a page loop based upon the pages in the wp_nav_menu and want to display each page with it’s own assigned template using this code in my index.php file:

// Store original ID
global $post;
$curid = $post->ID;

// Get Main Menu ID
$menu_name  = 'primary_navigation';
$locations  = get_nav_menu_locations();
$menu       = wp_get_nav_menu_object($locations[$menu_name]);
$menuitems  = wp_get_nav_menu_items($menu->term_id, array('order' => 'DESC'));

// Loop through menu items to get page ID's
foreach ($menuitems as $item):
  // Setup page
  $pageid   = get_post_meta($item->ID, '_menu_item_object_id', true);
  $post     = get_post($pageid, OBJECT);
  setup_postdata($post);
  // Get page template
  $template_file = get_page_template_slug($pageid);
  $template_slug = pathinfo($template_file, PATHINFO_FILENAME);
  $template      = str_replace('template-', '', $template_slug);
  // Get template parts  
  if ($template) {
    get_template_part('template', $template);
  } else {
    get_template_part('page');
  }
  wp_reset_postdata();			
endforeach;

Which works great!

However;
In my template-custom.php and page.php templates the output of get_the_ID() is correct, but the the_title() & the_content() will still display content from the index.php template. But as soon as I remove the_title() & the_content() outside the while (have_posts()) : the_post(); loop it is displaying correctly…

My question is; how can I prevent this? Because I want to keep the rest of the Roots templates as original as possible.

Thanks!

This isn’t really a Roots question but I’ve tangled with this exact situation before.

You have two options:

Option 1: Tweak your existing code

Consider caching the menu item ID at the start of your foreach() loop and instead of using functions like the_title() and the_content() use the equivalent functions that accept a page/post ID as an argument. Something like: $post_id = $item->object_id; should work, then you can use get_the_title($post_id);. If each individual page is meant to be visible on its own then this is your best bet. If not, keep reading…

Option 2: Create a more intuitive one page structure

It’s been my experience that this structure isn’t always intuitive for clients to manage. They’re bounced back and forth between multiple pages and even some rather savvy clients have difficulty effectively managing the page structure using WP’s menus. It also adds overhead because you need to setup at least one template_redirect to ensure visitors cannot view each page individually.

My solution to this has been to use Advanced Custom Fields to simply create multiple sections within one WordPress page. If each section contains more than a few custom fields then it looks much cleaner with ACF’s built in tab fields:

It eliminates any potentially ugly rewrites and gives clients the ability to manage a single page worth of content exactly where they expect it to be: on the Home/Front/Index Page, instead of bouncing between multiple pages and navigation menus.

The downside to option 2 is that it lacks some flexibility, but you could easily compensate for that by creating a repeater field with the tab value or a custom field within each tab called “Sort Order” which would function much like WordPress’s native Sort Order when you run your loop to output the tabs’ content.

This leaves one shortcoming: the client won’t be able to add a new section on their own. In my opinion, this is simply the cost of doing business and commissioning a custom site—that is, if they want to add additional sections they will need to hire you again (or another dev). So it’s not 100% hassle free for them, but it’s not the end of the world for you since it could mean future work down the road.

There are also some SEO considerations with your method because it could be seen as a potential sitemap hack. I.e., by creating multiple pages you’re tricking search engines into thinking your site is larger than it actually is. Sophisticated crawlers like Google will notice that when they crawl the individual pages and are redirected.

3 Likes

Thanks for your extended reply @cfx!

I know, I thought I would give it a try here anyway

Yeah, that does work. But I don’t quite understand why it needs that since the post ID in those templates are correct… I thought there could be another reason for this?

I thought about that too yes, the only disadvantage in my opinion is that if my client decides to get rid of the whole one-page setup, it’s a lot of work to convert the site into a normal website with separate pages.

Thanks, I’m gonna reconsider my options!
Cheers

I thought about that too yes, the only disadvantage in my opinion is that if my client decides to get rid of the whole one-page setup, it’s a lot of work to convert the site into a normal website with separate pages.

Again, it’s a matter of choosing between easy manageability and flexibility. Each approach has its flaws, just depends which works best for your situation.

Hi Twansparent,

I’m new user of wordpress and Roots, I would like to know, why don’t you put your code in base-front-page.php (or something similar) instead of index.php?

Anyway, good piece of code, that’s will help me to test some possibities.

Thank you

Hi Jecko,
Good question, I don’t know actually :slight_smile:
I never really used different base wrappers yet, but I think that would have been easier yes.
You’re welcome!

Hi everyone,

Maybe it can help someone, here’s my code in a wrapper way.

base-front-page.php:

 <?php get_template_part('templates/head'); ?>
<body <?php body_class(); ?>>

<!--[if lt IE 8]>
		<div class="alert alert-warning">
			<?php _e('You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.', 'roots'); ?>
		</div>
	<![endif]-->

<?php
	do_action('get_header');
	// Use Bootstrap's navbar if enabled in config.php
	if (current_theme_supports('bootstrap-top-navbar')) {
	  get_template_part('templates/header-top-navbar');
	} else {
	  get_template_part('templates/header');
	}
?>

<main class="wrap container" role="document">
	<?php
	// Get Main Menu ID
	$menu_name  = 'primary_navigation';
	$locations  = get_nav_menu_locations();
	$menu       = wp_get_nav_menu_object($locations[$menu_name]);
	$menuitems  = wp_get_nav_menu_items($menu->term_id, array('order' => 'DESC'));

	// Loop through menu items to get page ID's
	foreach ($menuitems as $item){
		// Setup page
		$page_id = $item->object_id;	
		$page_components = get_post($page_id);

		// Get page template
		$template = get_page_template_slug($page_id);

		// Get template parts
		if ($template) {

			include(locate_template($template));

		} else { ?>

			<section class="content row">
				<div class="main <?php echo roots_main_class(); ?>" role="main">

					<?php echo apply_filters('the_content', $page_components->post_content); ?>

				</div>
			</section>
		<?php }
	}
	?>
</main>

<?php get_template_part('templates/footer'); ?>

</body>
</html>

and for the template example :

<?php
/*
Template Name: Custom Template
*/

if(isset($page_components->post_content)) {
	if($page_components->post_content) { ?>
<section class="custom content row">
	<div class="main <?php echo roots_main_class(); ?>" role="main">

		<?php echo apply_filters('the_content', $page_components->post_content);?>

	</div>
</section>
<?php }
} ?>

Feel free to use it or makes comments to improve it.

Thank’s to Twansparent and CFX for your help.
Thanks to Ben Word for Roots

Enjoy coding everyone

1 Like