WordPress Posts to Pages

I’ve been using WordPress for over six years. When I began using WordPress, with version 1.2, it was a blogging platform and nothing more. With version 1.5 WordPress added a new wrinkle; it could still be used for blogging and creating blog posts, but it could also be used as a CMS-lite, with static pages that didn’t belong to the blog heirarchy. Blog posts were for a daily (or, at least, semi-frequent) updating schedule and they were accessed and read in a chronological fashion, whereas pages were more organized, they could be arranged by subpages and sub-subpages, and they could be read outside of a blog chronology.

Pages and Posts were separate things; they went in the same database, they were handled in the same basic way, but there was a wall, albeit an imaginary one, in between them and it could never be bridged. If you wrote it as a Post, it stayed as a Post — unless you went and hacked the SQL database to change it to a Page, but that’s for people who like to live on the edge.

But sometimes, one might write a blog post — as an example, a book review — and because it’s evergreen information that isn’t really tied to a chronological ordering, it should be organized as a subpage to a book review index. But there’s no easy way to do that, to place that blog post as a subpage, is there?

Oh, there are workarounds. One could, on that book review index page, place a link directly to the blog post. But more and more WordPress designs today are making use of dropdown and hover menus, so wouldn’t it be more convenient to have this as a page? An option might be to simply create a page with the book review, but then the advantages to making the review a blog post — pinging update services, letting regular readers see the post in their RSS readers — are lost. Or, after making the blog post, the post’s content could be copied to a separate page. And while the SQL editing technique I mention above is a viable tactic once the review post drops off the front page is an option, a person has to be comfortable with editing a database.

An idea occured to me.

Custom page templates.

WordPress allows a website owner to create a custom page template that is used instead of the standard page.php when the page is called. Replacing the loop in the custom page.php with a custom loop that calls a specific post would be a wordaround for the problem of displaying a post’s content in the page heirarchy. One would simply create a custom page template that calls the specific post, then create a page and use that custom page template as its base. It wouldn’t matter what was entered as the page’s content, indeed there’s not point to adding any text to the page except for the title; the custom loop would call instead the content of the blog post.

This solution is fine, if you only need a few blog posts turned into pages. But what if you need five, ten, twenty? You would have to create a custom page template for each blog post, because each custom page template would be hardcoded to call a single blog post.

What if there were a way to automate the system? WordPress allows both posts and pages to have something called “Custom Fields.” This is basically some additional data that can be used by a theme or a plugin to achieve a certain effect with a post, like a post thumbnail or a mood icon. What if a Custom Field were used to contain the Post ID (a WordPress reference number to the post’s record in the SQL database), and then the custom loop in the custom page template would pull that information from the page’s database record to populate the custom query that calls the WordPress post?

I thought that was a clever solution. I had to give it a try.

Here’s the code I came up with for my WordPress theme:

<?php
/*
Template Name: Custom -- Post to Page
*/

get_header(); ?>

<div id="content">

     <div id="contentleft">

          <div class="postarea">

          <?php include(TEMPLATEPATH."/breadcrumb.php");?>

               <?php if (have_posts()) : while (have_posts()) : the_post(); ?>
               <?php $postpage = get_post_meta($post->ID, "post-page", $single = true); ?>

               <div class="aheadline">

                    <h1><?php the_title(); ?></h1>

               </div>

               <div class="clear"></div>

               <?php endwhile; else: ?>

               <p><?php _e('Sorry, no posts matched your criteria.', 'studiopress'); ?></p><?php endif; ?>

               <?php
                    $recentPosts = new WP_Query();
                    $recentPosts->query('p='.$postpage);
               ?>

               <?php while ($recentPosts->have_posts()) : $recentPosts->the_post(); ?>

                    <?php the_content(__('Read more', 'studiopress'));?>

               <?php endwhile; ?>

               <?php comments_template('',true); ?>

          </div>

     </div>

     <?php include(TEMPLATEPATH."/sidebar.php");?>

</div>

<?php // The main column ends ?>

<?php get_footer(); ?>

I created a Custom Field called “post-page.” The custom page template runs the standard WordPress loop, with one exception — in the loop it looks to see what the value of “post-page” is and assigns that value to a variable. The standard WordPress loop is closed, then a custom loop is called. The custom loop uses the variable to call the post from the blog heirarchy. Thus, a single custom page template can be used to place any chronological blog post into WordPress’ page heirarchy.

To create your own custom Page-to-Post template, try this:

1) Make a copy of the page.php file in your theme folder and call it something like custom-page.php

2) Replace the opening “<?php get_header(); >” tag in custom-page.php with the first five lines of the code I posted above.

3) Find the start of the WordPress loop:
<?php if (have_posts()) : while (have_posts()) : the_post(); ?>

4) Follow that line with this:
<?php $postpage = get_post_meta($post->ID, "post-page", $single = true); ?>

5) Make sure the WordPress loop is closed before the <?php the_content();?>

6) Replace <?php the_content();?> with this:
<?php
$recentPosts = new WP_Query();
$recentPosts->query('p='.$postpage);
?>

<?php while ($recentPosts->have_posts()) : $recentPosts->the_post(); ?>

<?php the_content();?>

That should cover it.

One interesting side effect of this method is that the custom page template, if it calls comments, will pull the comments from the original blog post.

With this method, someone can create blog posts, and then utilize them within WordPress’ CMS-like page heirarchy.

To my surprise, my code worked properly for me the first time. :)


Originally published here.