A Custom WP Category Template

Filed Under Coding &Design | Comments (1) | Page Tools

This blog has become schizophrenic; rather than blogging about one thing, it’s covering many aspects of my life. So I thought I’d find a way to present different views. I had already categorised my posts into general areas, now I needed a way to present the different views with some commentary. The best way was a set of category-based pages, with some text at the top describing the area of interest and then the category-based listing of posts below.

This post describes how I implemented a set of category-based page templates in WordPress, covering the design and implementation.

Requirements and Design

In summary what I needed was a set of pages with some text at the top and the category-based post listing below. There were a number of options:

  • I could have created unique page templates for each, with the commentary text hardcoded into the template (like in the home.php), but this wouldn’t have been very scalable.
  • I could have found a plugin to call a category-based post list from within a normal page (I didn’t see anything that would suit this need).
  • I could have written a plugin to do the same (not up to that yet).
  • I could have created a single custom page template that could be used by a series of category-based pages that included both the commentary text and the category-based listing.

I chose the last option. This would allow me to add a new page using the standard “add page” mechanism in WordPress and associate the page with the custom template.

The next two challenges were 1) getting the category name from the page to the template, and 2) coding the template. The first was easy; the page custom fields could be accessed within the code in the page template.

The latter was more of a challenge. The custom template, like all page templates needed “The Loop” to receive and display the page content. But it also needed a secondary loop to display all the posts matching the new category. So the page structure needed to be:

  1. Main Loop – to receive and present the text from the page
  2. Process Category – get the category name from the page and setup for the second (category-based post listing) loop
  3. Post-list Loop – using the category name from the page, run a secondary loop to list all of the posts belonging to the category.

The relationship between the page content, the page-category template file (page-category.php) and the final page on the blog is shown below (it may be easier to click the image link and see a larger version).

custom-template

As can be seen in the figure, I decided to use a meta tag of my_page_category that would be used by the custom template to determine the category for the second loop.

There was one last design challenge that popped up during development; the page navigation plugin I’m using with this theme (WP-PageNavi) does not work properly with the second loop. I had to build a custom page navigation mechanism to page through the second loop entries.

Build

I created a new template file called page-category.php. I added all the usual stuff to make it fit my theme. The important stuff is the code relating to the three parts; the Main Loop, the Process Category section, and the second loop (the Post-list Loop). There was also some custom code for the page navigation. These will be detailed in the following sections.

Main Loop

The main loop is processing and presenting the page content. It is the same as used in all the other page templates:

<?php if ($posts) : foreach ($posts as $post) : start_wp(); ?>
  <div class="post">
    <div class="content-head-info"></div>
    <div class="clear"></div>
    <div class="content-title">
      <h1><?php the_title(); ?></h1>
      <p>By <?php the_author(); ?>
        <?php edit_post_link('Edit page',' | '); ?>
      </p>
    </div>
    <?php the_content(); ?>
  </div>
<?php endforeach; else: ?>
  <div class="content-head-library"></div>
  <div class="clear"></div>
  <div class="content-title">
    <h1>Not found</h1>
    <p>This page doesn't exist!</p>
  </div>
<?php endif; ?>

Most of the code relates to how my theme is laid out. It uses the normal functions to display the page, such as the_title(), the_author() and the_content().

Processing the Category Name

The pages include a meta tag of my_page_category, with the tag value being the name of a top-level category (it could be any category name). I needed to access this value in the code and use it to build a new query for the second loop. The code to do this is shown below:

<?php
  $key="my_page_category";
  $my_cat_title = get_post_meta($post->ID, $key, true );
  $query1= 'category_name=' . $my_cat_title . '&orderby=date&order=ASC';
  query_posts($query1);
  $query2= 'category_name=' . $my_cat_title . '&numberposts=5&paged=' .$paged;
?>

This chunk of code:

  1. Defines the meta tag name
  2. Uses the get_post_meta() function to retrieve the value of the tag (such as “Web Development”). The last argument of the function tells it to return a string of the first value rather than an array.
  3. Builds the query to be passed to the query_posts() function. This will set the variable to be something like “category_name=Web Development&orderby=date&order=ASC”.
  4. Uses this query string with the query_posts() function telling it to retrieve all posts that match the category name, sort them by date ascending.
  5. Builds a second query that will be used to display the posts. The numberposts argument defines the number of posts to display on a page. The paged argument specifies what page the current display is (see below). For example the variable will be something like “category_name=Web Development&numberposts=5&paged=2″ (corresponding to /page/2 in the URL).

This is all fairly straightforward code.

Post-list Loop (Second Loop)

This section performs the loop to display the posts matching the query_posts() call in the earlier section.

<?php $posts = get_posts($query2); foreach ($posts as $post) : start_wp(); ?>
  <?php setup_postdata($post); ?>
  <div class="post">
    <?php require('post_excerpt.php'); ?>
  </div>
<?php endforeach; ?>

This chunk of code:

  1. Uses the second query argument defined earlier ($query2) with the get_posts() to display the number of posts relevant to this page.
  2. I’m not convinced that the WordPress post formatting function, setup_postdata(), is required. A number of posts on the support site recommended using it so all the attributes of the posts are usable (see “Displaying Posts Using a Custom Select Query”).
  3. I’m using an included section of code to display the post summary. The only difference between how I do it on other pages (such as the home page) is that I had to use the the_excerpt() function call rather than the_content(). For some reason the secondary loop mechanism I’m using does not recognise the more tags in the posts, so the_content() displays the entire post. I only want to show a summary so I need to use the_excerpt().

The important points here are the query used in the get_posts call and use of the_excerpt() instead of the_content().

Handling Page Navigation

As mentioned earlier, I found the page navigation plugin I use (WP-PageNavi) did not work well with the second loop. If I set the post display count to be the same as the main post display count, I would get links to the right number of pages. But the navigation function would get confused on pages other than the first.

I also tried to use the standard navigation function, posts_nav_link(), but it was having problems showing the separator character. This may have been a bug at WP 2.8.2 or something to do with the secondary loop. I ended up building the following code directly in the template:

<p align="center">
<?php
   //WORKAROUND for page links (pages_nav_link doesnt seem to work)
   //set the divider
   $divider = ' | ';
   //get the current page number
   $page_num = $paged;
   //get the number of the final page
   $max_num_pages = $wp_query->max_num_pages;
   //if its first page, just do next link
   if($page_num == ''){next_posts_link('Next »');}
   //if its not the first or last page display the divider
   if($page_num>1 && $page_num<$max_num_pages){
      previous_posts_link('« Prev');
      echo $divider;
      next_posts_link('Next »');
   }
   //if its the last page, just do prev link
   if($page_num == $max_num_pages){previous_posts_link('« Prev');}
?>
</p>

The key bits of this code are:

  • Set the devider (a vertical bar) in a variable. I could have used the “|” character rather than the ASCII representation.
  • Get the page number ($paged) from the page URL (e.g. /page/2 will put 2 in $paged) and save it as a variable.
  • Get the total number of pages for the second loop query ($max_num_pages) and save it as a variable.
  • Then check for:
    1. First page – if so use the next_posts_link() function to display “Next >>“.
    2. Not first or last page – use both the previous_posts_link() and next_posts_link() functions to display “<< Prev | Next >>“.
    3. Last page – use the previous_posts_link() function to display “<< Prev“.

This works fine, and concludes this post.

Page Tools

  • RSS
  • Email this Post
  • Print This Post

Tags: , , , ,

No related posts.

Comments

One Response

  1. Yeah, I know you’re hating me right about now. ,

    Comment by Alex61 at October 23rd, 2009 at 6:20 am

Leave a Comment

Please note: Comment moderation is enabled and may delay your comment. There is no need to resubmit your comment.