Sue Feng Design

‹ Back to blog

WordPress Custom Post Type Tutorial

Custom posts are post types that are different from normal posts. They appear as a separate link category in wp-admin. You can make custom posts for many different reasons, such as creating feedback posts pages that have different fields than what posts would offer, and have them display in a separate location from the normal posts. You may want a separate space for your portfolio entries, or a separate space for media posts. Those are just some ideas. I’ve had to create custom posts for three different WordPress sites, and it hasn’t been easy to do because sometimes I run into problems that are hard to find the solutions to, so I will try to compile something from my experience. I’m not claiming to have the best tutorial on WordPress custom posts by any means, but hopefully this will be useful to someone.

1. Set up your custom post in your functions.php page of your WordPress theme.

Here’s the bit of code you should add to your functions.php page:

add_action('init', 'custom_post_init', 0);
function custom_post_init() {
    $labels = array(
        'name' => _x('Custom Posts', 'post type general name'),
        'singular_name' => _x('Custom Post', 'post type singular name'),
       'add_new' => _x('Add New', 'Custom Post'),
     'add_new_item' => __('Add New Custom Post'),
     'edit_item' => __('Edit Custom Post'),
       'new_item' => __('New Custom Post'),
     'view_item' => __('View Custom Post'),
       'search_items' => __('Search Custom Posts'),
     'not_found' =>  __('No Custom Posts found'),
     'not_found_in_trash' => __('No Custom Posts found in Trash'),
        'parent_item_colon' => ''
  $args = array(
      'labels' => $labels,
       'public' => true,
      'publicly_queryable' => true,
      'query_var' => true,
       'show_ui' => true,
     'rewrite' => array( 'slug' => 'custom','with_front' => false),
     'capability_type' => 'post',
     'hierarchical' => false,
       'menu_position' => 5,
      'supports' => array('title','editor','comments'),
        'taxonomies' => array('group'),
      'has_archive' => true

You may change the code to reflect your custom post type, so replace where it says Custom Post, Custom Posts and custom_post_init with your custom post name.

$labels puts labels where they are found in the wp-admin interface. $args gives a set of instructions for the custom posts. It tells WordPress to use these labels, make it publicly visible, allow query strings to be used (though they will be redirected to the permalink structure if you’re using permalinks in Settings). For more information you may visit BetterWP.net. I thought it was more helpful than the WordPress codex.

Some things I’d like to note, though: setting menu_position to 5 makes the custom post appear directly under Posts in wp-admin. Setting the rewrite slug determines what address the posts will reside in. For example, if you set the slug to feedback, it will appear as http://yoursite.com/something/feedback. Setting with_front to false makes the url be http://yoursite.com/feedback.

Also, this bit of code shows what you would like have displayed in the post editing interface:

'supports' => array('title','editor','comments');

2. Allow custom post type to appear on your site

After setting up this function and adding it to add_action(), you’re ready to edit your index.php to include this post type. For this, you’ll want an if statement that says, if the post type is feedback, do this, otherwise, display the normal posts. That way when people go to http://yoursite.com/feedback, they will see feedback posts, and when they go to http://yoursite.com they will see your normal posts, or http://yoursite.com/blog/, however you have your posts url set up. Here’s the bit of code for that, to be placed in your index.php:

while ( have_posts() ) : the_post();
<!--enter your feedback template code here-->
<?php endwhile; ?>
     <div class="left"><?php previous_posts_link('&laquo; Newer'); ?></div>
        <div class="right"><?php next_posts_link('Older &raquo;'); ?></div>
<?php // end feedback
else: ?>
<h3><?php if (is_category()) {  echo single_cat_title()." | "; } ?>Blog</h3>
while ( have_posts() ) : the_post(); ?>
<!--enter your blog template code here-->

$big = 999999999; // need an unlikely integer

echo paginate_links( array(
   'base' => str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) ),
   'format' => '?paged=%#%',
    'current' => max( 1, get_query_var('paged') ),
   'total' => $wp_query->max_num_pages,
    'prev_text'    => __('&laquo; Newer'),
   'next_text'    => __('Older &raquo;')
) );
<?php endif; ?>

Notice the custom post bit of code has query_posts();


This bit of code tells wordpress to show 1 post per page, and show the feedback posts, and allow pagination.

The tricky part, though, is if you have set in Settings a different posts per page under Settings -> Reading -> Blog pages show at most, then the pagination will not work. The pagination will only go by what is set there. To get around that, there’s a plugin you can use called Custom Posts Per Page. Or you can come up with your own code if you’re up for it and don’t like using plugins.

Note, I used two ways to paginate in my example. You don’t have to. You also don’t have to have two different templates for custom posts and regular posts or a different number of posts to show per page.

3. Create single page for custom post

To create a page for displaying single custom posts, you’ll need to follow this naming convention for your file:

single-[slug name].php

Where [slug name] is, you’ll want to use what you put as the slug that will display, such as, in this case it would be feedback, so it would look like single-feedback.php. This is only if you want to customize the post. Otherwise, single.php should still work for custom posts. You don’t have to do anything special on the single.php file for it to work.

4. Create the categories specific to custom posts

If you want to create categories specific to the custom posts and not have them display for normal posts, update your functions.php file with this:

add_action( 'init', 'add_custom_taxonomies', 0 );
function add_custom_taxonomies() {
 // Add new "groups" taxonomy to Posts
 register_taxonomy('group', 'feedback', array(
       // Hierarchical taxonomy (like categories)
      'hierarchical' => true,
        // This array of options controls the labels displayed in the WordPress Admin UI
        'labels' => array(
         'name' => _x( 'Groups', 'taxonomy general name' ),
         'singular_name' => _x( 'Group', 'taxonomy singular name' ),
            'search_items' =>  __( 'Search groups' ),
            'all_items' => __( 'All groups' ),
           'parent_item' => __( 'Parent group' ),
           'parent_item_colon' => __( 'Parent group:' ),
            'edit_item' => __( 'Edit group' ),
           'update_item' => __( 'Update group' ),
           'add_new_item' => __( 'Add New group' ),
         'new_item_name' => __( 'New group name' ),
           'menu_name' => __( 'groups' ),
      // Control the slugs used for this taxonomy
     'rewrite' => array(
            'slug' => 'group', // This controls the base slug that will display before each term
         'with_front' => false, // Don't display the category base before "/groups/"
         'hierarchical' => true, // This will allow URL's like "/groups/boston/cambridge/"

You may change group to something else, but don’t use category or tag as the name. In this case, each category will be displayed at http://yoursite/group/group-name. It’s pretty similar to creating a custom post type in functions.php so I won’t go into details on this.

5. Create a taxonomy page for displaying custom post groups

You’ll want to name your taxonomy page taxonomy-[slug name].php. Where slug name is, put whatever you have set for the slug in rewrite. In this case, it’s group, so taxonomy-group.php. The main difference between this and the way normal categories are displayed is this:


notice the bit &group='.$term'. Change group to whatever you have your slug as. You’ll want to put this before your while loop. That’s it.

6. Display category link for each post for custom post

To display what category your post is in on your index.php, you’ll want to write something like this below. I have made it into a more flushed out example so you can see better how a post structure may look like with the query_posts() and such.

while ( have_posts() ) : the_post();
$terms = get_the_terms($post->ID, 'group');
       <article class="divider">
           <h4><?php the_title(); ?><span class="comment-bubble"><?php comments_popup_link('0', '1', '%'); ?></span></h4>
          <time class="date" datetime="<?php echo date("Y-m-d", strtotime(get_the_date())); ?>"><?php echo the_date("M d, Y"); ?></time>
          <div class="entry">
         <?php echo the_content(); ?>
            <span class="meta">
             Posted in <a href="/group/<?php foreach($terms as $term){echo strtolower($term->name);} ?>/"><?php foreach($terms as $term){echo $term->name;} ?></a>
               | <a href="<?php the_permalink(); ?>">Comment</a>
endwhile; ?>

This is the bit at the top to get the taxonomy terms/categories:

$terms = get_the_terms($post->ID, 'group');

This is where you would call it:

Posted in <a href="/group/<?php foreach($terms as $term){echo strtolower($term->name);} ?>/"><?php foreach($terms as $term){echo $term->name;} ?></a>

There may be a better way to do this, but this is what I have done. In this case, the category/group will appear after the entry as Posted in [group link].

To see your custom post type on your site, you’ll probably want to update your permalinks by going to Settings->Permalinks and saving changes. You don’t have to edit anything, but WordPress will automatically add the new slug through this method. You may do this step as you go, it doesn’t have to be the last thing you do, though if you are having trouble viewing a page and getting a page not found error, you may try it.

Also, as an important note: Do not create any pages with the same slug as your custom post type or custom taxonomy slug, or there will be a conflict.

Posted on: June 8, 2013Categories: TutorialsTags: coding, wordpress
‹ Back to blog