WordPress Page with Loops and PHP Cloning

This is a follow up of a quick note I sent to the wp-hackers list about multiple loops and page templates. I thought I would expand on the subject a little bit.

WordPress uses the Loop to process and display posts. It sounds like a simple enough process, but there is alot that happens before, after, and during the Loop; Objects get created, global variables get set, and special functions get executed. It gnashes, it gnaws until it finally gets the job done interacting with your theme.

I had an old Sandbox based theme with a page template that performed a specialized WordPress query based on a custom field called page_category. ThisĀ  page template was designed to show the orginal page content followed by a secion of posts using the category set by the page_category custom field. To make matters more complicated the original page template was built on a PHP4 server and my test server is PHP5.

There are several methods to perform multiple loops. I’m going to illustrate two that I worked with for this problem there are others and my original research comes from the Loop documentation in the WordPress Codex. I am going to paste in the entire source for both page templates, so be aware that they are based on a Sandbox theme, so they still contain depencies on some Sandbox functions.

Custom WP_Query

The first supplied by Mark Jaquith in answer to my original post to wp-hackers uses a custom WP_Query object. It works great if you want to grab some of the post and it’s related data, but I needed a little more. The only thing that does not work is the comments_popup_link function, so it won’t show the number of comments. Everything else seems to work fine. Also note that I set the $more variable inside the while loop to properly show read more links for the individual posts. Setting it outside the loop does not work. This could be customized to make it do what I want, but I am lazy by nature.

<?php
/*
Template Name: Page with Posts from Category
*/

/*
Usage:

Custom Field Name:
	page_category

Custom Field Values:
	category name

*/
?>
<?php get_header() ?>

	<div id="container">
		<div id="content">
		
<?php the_post() ?>
			<div id="post-<?php the_ID(); ?>" class="<?php sandbox_post_class() ?>">
				<h2 class="entry-title"><?php the_title(); ?></h2>
				<div class="entry-content">
<?php the_content() ?>

<?php wp_link_pages("\t\t\t\t\t<div class='page-link'>".__('Pages: ', 'sandbox'), "</div>\n", 'number'); ?>

<?php edit_post_link(__('Edit', 'sandbox'),'<span class="edit-link">','</span>') ?>

				</div>
			</div><!-- .post -->

<?php 
if ( ( $page_category_name = get_post_custom_values( 'page_category' ) ) ) {

	
	$custom_loop = new WP_Query( array(
		'category_name' => $page_category_name[0],
		'showposts' => get_option('posts_per_page')
		));
	
?>
			<div id="page-posts">
	
	<?php while ( $custom_loop->have_posts() ) : $custom_loop->the_post() ?>
	
<?php 
	global $more;
	// set $more to 0 in order to only get the first part of the post
	$more = 0;
?>
				<div id="post-<?php the_ID() ?>" class="<?php sandbox_post_class() ?>">
					<h3 class="entry-title"><a href="<?php the_permalink() ?>" title="<?php printf(__('Permalink to %s', 'sandbox'), wp_specialchars(get_the_title(), 1)) ?>" rel="bookmark"><?php the_title() ?></a></h3>
					<div class="entry-date"><abbr class="published" title="<?php the_time('Y-m-d\TH:i:sO'); ?>"><?php unset($previousday); printf(__('%1$s &#8211; %2$s', 'sandbox'), the_date('', '', '', false), get_the_time()) ?></abbr></div>
					<div class="entry-content">
	<?php the_content(''.__('Read More <span class="meta-nav">&raquo;</span>', 'sandbox').''); ?>
	
					<?php wp_link_pages('before=<div class="page-link">' .__('Pages:', 'sandbox') . '&after=</div>') ?>
					</div>
					<div class="entry-meta">
						<span class="author vcard"><?php printf(__('By %s', 'sandbox'), '<a class="url fn n" href="'.get_author_link(false, $authordata->ID, $authordata->user_nicename).'" title="' . sprintf(__('View all posts by %s', 'sandbox'), $authordata->display_name) . '">'.get_the_author().'</a>') ?></span>
						<span class="meta-sep">|</span>
						<span class="cat-links"><?php printf(__('Posted in %s', 'sandbox'), get_the_category_list(', ')) ?></span>
						<span class="meta-sep">|</span>
						<?php the_tags(__('<span class="tag-links">Tagged ', 'sandbox'), ", ", "</span>\n\t\t\t\t\t<span class=\"meta-sep\">|</span>\n") ?>
	<?php edit_post_link(__('Edit', 'sandbox'), "\t\t\t\t\t<span class=\"edit-link\">", "</span>\n\t\t\t\t\t<span class=\"meta-sep\">|</span>\n"); ?>
						<span class="comments-link"><?php comments_popup_link(__('Comments (0)', 'sandbox'), __('Comments (1)', 'sandbox'), __('Comments (%)', 'sandbox')) ?></span>
					</div>
				</div><!-- .post -->
	
	<?php endwhile ?>
	
			</div>

<?php
} // end if ( ( $page_category_option = get_post_custom_values( 'page_category' ) ) )
?>


		</div><!-- #content -->
	</div><!-- #container -->

<?php get_sidebar() ?>
<?php get_footer() ?>

The Loop and Cloned Objects

This is an example of saving or cloning the original post data, running a new query, and resetting the original objects. Remember this site is in production on an old PHP4 server (not my fault) and the test server is PHP5. WordPress is PHP4 compatible, and PHP4 just recently became unsupported. Someday WordPress will move to PHP5 and that will no doubt cause major changes in how the Loop funcitons. Remember the WordPress Loop does a lot of work, so for this solution I need those global variables to be reset.

The first part is a simple helper function I totaly ripped off from Drupal to help with making copies of the WordPress Objects. I called it wp_clone and put it the functions.php file for this particular theme.

/*
Helper function to clone objects for php4 and php5
*/
function wp_clone($object) {
  return version_compare(phpversion(), '5.0') &lt; 0 ? $object : clone($object);
}</pre>
The theme template is similar to the earlier one, but I am taking a copy of the original $post and $wp_query objects and restoring them.

<pre lang="php">
<?php
/*
Template Name: Page with Posts from Category
*/

/*
Usage:

Custom Field Name:
	page_category

Custom Field Values:
	category name

*/
?>
<?php get_header() ?>

	<div id="container">
		<div id="content">
		
<?php the_post() ?>
			<div id="post-<?php the_ID(); ?>" class="<?php sandbox_post_class() ?>">
				<h2 class="entry-title"><?php the_title(); ?></h2>
				<div class="entry-content">
<?php the_content() ?>

<?php wp_link_pages("\t\t\t\t\t<div class='page-link'>".__('Pages: ', 'sandbox'), "</div>\n", 'number'); ?>

<?php edit_post_link(__('Edit', 'sandbox'),'<span class="edit-link">','</span>') ?>

				</div>
			</div><!-- .post -->

<?php 
if ( ( $page_category_name = get_post_custom_values( 'page_category' ) ) ) {

	
	// duplicate post for later recovery
	
	$temp_wp_query = wp_clone( $wp_query );
	$temp_post = wp_clone( $post );

	global $more;
	// set $more to 0 in order to only get the first part of the post
	$more = 0;
	
	query_posts( 'category_name=' . $page_category_name[0] . '&showposts=' . get_option('posts_per_page') );

?>
			<div id="page-posts">

	<?php while ( have_posts() ) :  the_post() ?>
				<div id="post-<?php the_ID() ?>" class="<?php sandbox_post_class() ?>">
					<h3 class="entry-title"><a href="<?php the_permalink() ?>" title="<?php printf(__('Permalink to %s', 'sandbox'), wp_specialchars(get_the_title(), 1)) ?>" rel="bookmark"><?php the_title() ?></a></h3>
					<div class="entry-date"><abbr class="published" title="<?php the_time('Y-m-d\TH:i:sO'); ?>"><?php unset($previousday); printf(__('%1$s &#8211; %2$s', 'sandbox'), the_date('', '', '', false), get_the_time()) ?></abbr></div>
					<div class="entry-content">
	<?php the_content(''.__('Read More <span class="meta-nav">&raquo;</span>', 'sandbox').''); ?>
	
					<?php wp_link_pages('before=<div class="page-link">' .__('Pages:', 'sandbox') . '&after=</div>') ?>
					</div>
					<div class="entry-meta">
						<span class="author vcard"><?php printf(__('By %s', 'sandbox'), '<a class="url fn n" href="'.get_author_link(false, $authordata->ID, $authordata->user_nicename).'" title="' . sprintf(__('View all posts by %s', 'sandbox'), $authordata->display_name) . '">'.get_the_author().'</a>') ?></span>
						<span class="meta-sep">|</span>
						<span class="cat-links"><?php printf(__('Posted in %s', 'sandbox'), get_the_category_list(', ')) ?></span>
						<span class="meta-sep">|</span>
						<?php the_tags(__('<span class="tag-links">Tagged ', 'sandbox'), ", ", "</span>\n\t\t\t\t\t<span class=\"meta-sep\">|</span>\n") ?>
	<?php edit_post_link(__('Edit', 'sandbox'), "\t\t\t\t\t<span class=\"edit-link\">", "</span>\n\t\t\t\t\t<span class=\"meta-sep\">|</span>\n"); ?>
						<span class="comments-link"><?php comments_popup_link(__('Comments (0)', 'sandbox'), __('Comments (1)', 'sandbox'), __('Comments (%)', 'sandbox')) ?></span>
					</div>
				</div><!-- .post -->
	
	<?php endwhile ?>
	
			</div>

<?php

	$post = wp_clone( $temp_post );
	$wp_query = wp_clone( $temp_wp_query );

} // end if ( ( $page_category_option = get_post_custom_values( 'page_category' ) ) )
?>


		</div><!-- #content -->
	</div><!-- #container -->

<?php get_sidebar() ?>
<?php get_footer() ?>

The cloning method is more of a hack. It would be more appropriate to make a custom query and set functions or write special functions to get the data you need. Of course I am pressed for time, so I will be relying on the cheap and lazy clone method for a little while longer.

2 Responses to “WordPress Page with Loops and PHP Cloning”

  1. Jess Planck says:

    I have to note that wp_clone() will be part of WordPress 2.7, so I better update my theme.

  2. [...] like this guy did what we want: I had an old Sandbox based theme with a page template that performed a specialized WordPress query [...]

Leave a Reply