How to Create an Archive Template for a Custom Post Type

Update!

Since this post was originally written, Genesis 2.0 was released and now includes built-in support for custom post type archives without the use of a template. Check out this tutorial for more detail.

Ok, readers. Grab your goggles and your oxygen mask because we’re going deep into some code today! I’ve been looking for a way to create an archive template for a custom post type. There are a number of good tutorials out there, but none of them were *quite* what I wanted.

In this tutorial, I’ll show you how to create a custom archive template that meets the following criteria:

  1. It’s an archive template for a custom post type (CPT)
  2. It includes page content (to be used as archive intro)
  3. It includes a loop for spitting out any posts belonging to the CPT
  4. It includes custom fields assigned to the CPT

If you’re already hyperventilating, it’s okay. You can skip the code and download the Genesis Custom Post Type Archive plugin by Travis Smith. It’s a great plugin and includes support for items 1-3 above. In my case, I needed support for item 4, plus I wanted to include custom styling.

Still with me? Let’s dive in!

Create a Custom Post Type

There are plenty of tutorials out there for creating custom post types in WordPress (here’s a great one by Justin Tadlock) or you can use a plugin like WP Types (aff link) to do it for you, so I won’t rehash that process here.

Testimonials Custom Post TypeFor this example, I’ve created a custom post type called testimonials with the end goal to show an archive page showing all my client testimonials.

Have you created your custom post type? Let’s move on.

Create some Custom Fields

If you want to create custom fields for a post, you have three basic options:

  1. Use WordPress’ built-in support for custom fields. The interface is rather ugly, but it works. (If you don’t see a Custom Fields metabox on your post edit screen, make sure it’s turned on via your Screen Options tab in the upper right corner)
  2. Use one of the many WordPress plugins to create a neat metabox with your custom fields. (I’ve used the WP Types plugin, which is overkill for just this task but does handle groups of custom fields very nicely)
  3. Roll up your sleeves and create your own custom meta box for custom fields. Bill Erickson (along with some top-notch WordPress developers) created the Custom Metaboxes and Fields code that’s super sharp and available on Github for your free use.

I’m creating my custom fields using the third option. Since my CPT is for client testimonials, I’ll create some custom fields for the client’s name and job title. The finished metabox on my post looks like this:

Custom Metabox with Fields

Create a Custom Post Type Archive Template

I’ll assume at this point that you’ve already got some posts created. WordPress has a default archive template (archive.php), but I want to create a specific archive page with a custom loop for my Testimonials CPT.

Following the WordPress template hierarchy naming protocol, I’m going to use this structure to name my template file: archive-{post_type}.php. Since my post type is testimonials, I’ll name it archive-testimonials.php and upload that to the root directory of my child theme folder.

Now we need to fill in the page content. I’ve tried to comment the main gist of the code, but leave a comment if you have a question about anything.

 

Create a Page and Apply the Archive Template

We’re on the downhill slide now!

Page Attributes - TemplateIn order to include some introductory text before the testimonials, I’ll create a regular page, give it the title Client Testimonies and add some text to the content editor.

The last step is to go the Page Attributes metabox and assign the custom template (when you create an archive page template and place it in the child theme directory, it’ll automatically show up in the Template list).

Save the page and view it using the page slug! Here’s the finished product!

Additional Resources:

This post required me to dig into (and better understand) WordPress queries, the default Genesis loop, and custom loops. I found the following articles very helpful:

Wait! Here’s an easier way. Maybe it’s right for you?

Since this post was originally written, Genesis 2.0 was released and now includes built-in support for custom post type archives without the use of a template. Check out this tutorial for more detail.

Comments

  1. says

    Great tut Carrie,

    I was in need of creating a dedicated page for testimonials and this worked great.

    Although… after following the link to Bill Erickson’s website for the custom meta boxes. I then followed a link from his website to Justin Tadlock’s tutorials where he covered “must use” plugins. In total I spent 6 hours building a new framework for all new Genesis projects going forward. Now the ability to create custom post types with customized admin screens is much easier!

    Thanks again for the tutorial and for making reference to other people’s code. It has made my coding more efficient.

    -rick

    • says

      Rick, I’m intrigued! Is it a new base child theme of sorts or more some custom functions to re-use? Would love to read a post with your own findings. I LOVE the custom metabox functionality…slick.

      • says

        Hey Carrie,

        It’s code base that can be used with any Genesis child theme. In a nutshell… WordPress functions/customizations go into the MU plugin, Genesis functions/customizations go into custom_functions.php and theme specific go into the functions.php file. Keeping everything separated makes it easier when building the next website thanks to code re-usability and makes changing themes on an existing site easier when some customizations that aren’t theme dependent but are Genesis dependent need to survive the changeover.

        -rd

  2. says

    I’ve been using this pluign and I absolutely love it. The one change I think could be useful, would have a “custom code” section, where I could easily add code above or beneath. I went around this by adding an action on the page and hooking into Genesis instead.

  3. Thierry says

    Hi Carrie, very nice work. The only trouble I have is I upgraded to Genesis 1.9 and now this doesn’t work. Can you help me? Thanks a lot

    • says

      Hi Thierry,
      I’m running it on Genesis 1.9 with no problem, so there might be a conflict somewhere else. Can you tell me more about how/where you’re using the code and what specific problem you’re having?

      Cheers,
      Carrie

      • Thierry says

        Hi Carrie,

        In my child theme I created an file called page_listing.php and copied the codes from above. I also use the AgentPress plugin. The only modification is the following:

        echo ‘‘ . genesis_get_custom_field( ‘_listing_price’ ) . ‘‘; //retrieve custom field
        echo ” . genesis_get_custom_field( ‘_listing_sqft’ ); //retrieve custom field

        But nothing from the page_listing.php is displayed but the default loop. Can you think of anything wrong I’m doing here?

        Thanks

  4. sara11web says

    Just a little thank you for sharing. I looked all over for instructions on this and finally found yours, which were perfect and easy to follow. Used it to create a Brewers List for a beer distributor website. Thanks Carrie!

    –Sara

  5. says

    Hi Carrie,

    Thanks for this tutorial. One odd thing I ran into was that get_the_content() was not returning the content of the page for me for some reason. I changed

    echo ” . get_the_content() ;

    to

    echo ”;
    $page_object = get_page( get_the_id() );
    echo $page_object->post_content;

    and it outputs the content as expected. I noticed on your testimonials page that you did not include any text, just a title, before the testimonials. Have you tested adding content to your page?

    Thanks again for the great tut!

    • says

      I did at one point and then got rid of it. I think the code here could definitely be improved – just hadn’t had a chance to update it yet. Glad you got it to work!

    • says

      Hi Matthew & Carrie-

      I was having the same problem, and have been scouring the web for a solution to the Content not appearing on the archive page..

      Matthew – I used the coding you pasted above, and it works great — however, the initial ” keeps showing up on the page, and I am not sure how to eliminate it.. Or if you are using that in place of other coding, etc.

      I had:

      function custom_do_loop() {

      // Intro Text (from page content)
      echo ”;
      echo ”. get_the_title() .”;
      echo ” . get_the_content() ;

      and switched to:

      // Intro Text (from page content)
      echo ”;
      echo ”. get_the_title() .”;
      echo ”;
      $page_object = get_page( get_the_id() );
      echo $page_object->post_content;

      but the quote keeps coming in at the top.

      Here’s one of the custom post type pages: http://74.53.25.211/~explore/beauty-fitness/

      If someone would provide some insight into what I am doing wrong, I’d greatly appreciate it!
      Thank you for your help!!

      Sarah

      • says

        just going to ping you both… i’ve tried the coding so many different ways, and read many online articles and forums to no avail.. would really appreciate some help :) thank you!

        • Matthew Lee says

          Hi Sarah,

          I don’t get notified about new comments on here so I did not see your post until today. Just happened to be coming back to this great tut once again!

          Anyway I suspect your problem is a cut & paste related issue. The ” is 2 single quotes together. Try typing it in that way and hopefully you will be good to go!

          I have subscribed to future responses so if you have any problems, post back.

          Thanks!

  6. Thierry says

    Hi Carrie, Since a created my page_listing.php (see post from April 2 above) which works great. When I use the Search of AgentPress it returns all posts and the layout is different. Which template the Search is using and why do you thing that the query is not working? Thanks

    • Thierry says

      Hoops did not fix everything. The search result is not using my custom loop layout. Which template the Search use to return the result? How can I tell the search to use a different template? Thanks

      • says

        Hi Thierry!
        Sorry I don’t know the answer to that one. Try posting over at studiopress.com/forums – I bet somebody knows.

        Cheers,
        Carrie

  7. says

    I’m a slight bit confused. Is this what I would need to create post templates? Such as, I have a certain type of posts formatted a certain way, but different from the usual post style?

    I want to be able to choose a certain blog post template (that would include sorta like a signature or bit of text that would be at the end of every post of that type) from a drop down menu within the “add new post” editor.

    Or am I looking for something else?

    • says

      Nah, I think you’re looking to create a custom page template and then set a particular post to use that template. Depending on how crazy you’re going with formatting, you may be able to just use a custom post class.

  8. says

    Dear wonderful Carrie

    how can i use this for custom post type taxonomies?

    i have a CPT of ‘product’

    and custom taxonomy of ‘product-category’

    and a custom template called ‘taxonomy-product-category.php’ where i’ll drop in the code.

    can’t seem to get my head around displaying taxonomies :(

    i need to have the custom loop as you have done, that way i can tweak as needed.

    i know it is something simple that needs to be changed in the ‘$args = array’

    i’m using genesis 2.0 beta

    really hope you can help, it would be greatly appreciated.

  9. Martin Hadley says

    Hi great tut,
    This has been such a help, however I’d like to link the thumbnails and post titles to the original posts. I’m sure this should be simple but I’m new to php.
    Appreciate any help.
    Cheers,

    • Martin Hadley says

      All good, I just needed to learn about get_permalink( $post->ID ) I forgot to mention that I am using post excerpts. Anyway it works, I hope it’s correct.
      For anyone that has a similar issue –

      $loop = new WP_Query( $args );
      if( $loop->have_posts() ):

      while( $loop->have_posts() ): $loop->the_post(); global $post;

      echo ”;
      echo ”;
      echo ‘ID ) . ‘”>’. get_the_post_thumbnail( $id, array(257, 145) ) . ‘‘;
      echo ”;
      echo ”;
      echo ‘ID ) . ‘”>’ . get_the_title() . ‘‘;
      echo ” . get_the_excerpt() . ”;
      echo ”;
      echo ”;

      endwhile;

      endif;

      • Martin Hadley says

        Hmmm, that previous comment seems to have lost all of the html tags in the code, oh well I don’t know how to share it.

        • says

          Arg! Darn the code stripping. Try re-posting it and wrapping it in <code> </code>.

          If that doesn’t work, you can always create a gist over at Github and link from there. :)

  10. says

    Hi Carrie! This post was exactly what I was looking for. Couple of quick questions… What template would you create for a category in a custom post type? For example, if I have a custom post type of “Products” with a category named “eBooks” what would the archive file name be? Would it be archive-products-ebooks.php or would I need to setup a taxonomy template file for that like taxonomy-products-ebooks.php? Thanks for your help!

    • says

      Hey Daniel,

      If you want an archive of all Products in the eBook taxonomy, you’d want to structure your template name as taxonomy-ebooks.php (assuming ‘ebooks’ is the name of your taxonomy). Not sure what your site organization/structure is, but it might make more sense to have a taxonomy called “type” and then “ebooks” is a term within that taxonomy… In that case your template could be taxonomy-type-ebooks.php.

      On the other hand, if you want an archive of ALL products, regardless of taxonomy, then you’d use archive-products.php.

      When in doubt, I always refer back to the template hierarchy in the codex: http://codex.wordpress.org/Template_Hierarchy

      Carrie

      • says

        Hi Carrie,

        Thanks for taking the time and replying. I’m basically trying to setup an ecommerce section to my site. So I wanted to create a custom post type of “products” (to keep separate from regular posts and give the products a unique page template), categorize those products and have a template for each product category if that makes sense. : ) I haven’t done anything like this with WordPress so I might be making things harder for myself I don’t know.

        It may just take me a lot of messing around with and a lot of caffeine. : )

        Thanks again Carrie!

        • says

          Sounds like you’re on the right page! What you’re technically after is a “taxonomy archive template”. The naming structure (according to the Template Hierarchy) is really the #1 factor to make sure your theme picks up the page where you want it to. After that, you’re just tweaking the loop to get your output as you wish.

          To start, create your taxonomy archive template and just build it out with the standard genesis loop to see what it outputs. :)

          Carrie

  11. says

    Hi Carrie,

    Can I still use this tut with Genesis 2.0 if I move to HTML 5 (by adding that HTML 5 switch to the functions.php file)? I am using minimum and it has a Bill Erickson style loop built into it but it only has one type of featured thumbnail in the grid and I wanted to have 2 types (which is similar to the way that Bill does it in his tut). I was going to just dive into it but I thought that you may have played Genesis 2.0′s loop functionality a bit and could tell me whether it has changed much.

    As always, thanks for the great tutorials!

    • says

      Hey Chris,

      Here’s a list of loop changes with HTML5: http://www.briangardner.com/code/genesis-html5-loop-hooks/

      So for this tutorial, you’d need to change:

      /** Remove Post Info */
      remove_action(‘genesis_before_post_content’,'genesis_post_info’);
      remove_action(‘genesis_after_post_content’,'genesis_post_meta’);

      To be:

      /** Remove Post Info */
      remove_action(‘genesis_entry_header’,'genesis_post_info’);
      remove_action(‘genesis_entry_footer’,'genesis_post_meta’);

      I’m on the seat of my pants here, so test this.:)

      Honestly, I’d like to re-write this tutorial as there are better ways to “skin the cat” so to speak. This works, but I think there’s a better way to code it.

      One of these days!

      Cheers,
      Carrie

      • says

        Thanks for the super fast reply Carrie. I guess we’re all figuring out the changes in Genesis 2.0 so I will definitely keep an eye out for your next tutorial. Again, thanks for all of your contributions to the Genesis community.

        – Christopher

  12. says

    I have a problem with the archives of the custom post type.

    Changes to the file archive and the new post-customPost.php are only visible to admin mode while the normal user does not see the new posts and the changes made ​​to the code.

    Could you help me?

      • says

        Thanks a lot for your prompt reply.

        I am not sure if I can move to Genesis 2.0 at this stage as we already advanced by 2years in that code. I have to do a lot of testing and key things I already implemented through other plugins.

        I created post type using following way:
        register_post_type(‘discuss’,
        array(
        ‘labels’ => array(‘name’ => __(‘Discussion Forum’),
        ‘singular_name’ => __(‘Discussion Forum’)),
        ‘public’ => true,
        ‘has_archive’ => true,
        ‘hierarchical’ => true,
        ‘publicly_queryable’ => true,
        ‘capability_type’ => ‘page’,
        ‘show_in_menu’ => true,
        ‘supports’ => array(
        ‘title’,
        ‘editor’,
        ‘author’,
        ‘thumbnail’,
        ‘excerpt’,
        ‘comments’,
        ‘page-attributes’,
        ‘post-formats’,
        ),
        ));

        Then when I visit http://site.com/discuss.. It takes content from archive-discuss.php.

        Now when I access it as admin, it opens perfectly fine but when I access it as guest it shows blank page.

        Any idea what is causing this error?

        thanks in advance.

        • says

          Hmm… Can’t think of any reason why that would happen. Sounds like a permissions issue more than anything related to your CPT. Try disabling all your plugins and see if that fixes the problem. If so, re-enable one at a time until you find the culprit.

          You might try searching the forums at wordpress.org to see if anyone’s had a similar issue.

  13. says

    I am using the Genesis theme template and I am curious where I go to create the .php file? And a bit more of the 1-2-3 prior to actually creating the code. Thanks so much for your help.

    • says

      Hi Scott,
      Thanks for stopping by. This tutorial requires some “prep-requisites”, if you will. The resources mentioned at the end of the post are a good starting point understanding the loop better and how it’s being modified in this case.

      Check out the WP Codex on Template Hierarchy for a starting point on why/where for .php template files.

      http://codex.wordpress.org/Template_Hierarchy

      Cheers,
      Carrie

  14. says

    Hi Carrie, thanks for sharing!

    As others pointed in the comments, for some reason get_the_content() was not returning the content of the page. Maybe because it’s a function that, as the codex says, needs to be executed inside the/a loop.
    Please, could you please edit the tutorial code, in order to fix it?

    If it helps, in my case, this solve the problem:


    // Intro Text (from page content)
    echo '';
    echo ''. get_the_title() .'';
    echo ''
    if ( have_posts() ) : while( have_posts() ) : the_post();
    the_content();
    endwhile;
    endif;

    Cheers!

  15. says

    Thanks a ton for this Carrie, your tuts are great and easy to follow and I’ve found your code examples to be the easiest to digest. I’m used to creating WordPress templates more in front end HTML mode with each wp php snippet in it’s own tag. Typical front ender I know.

    One thing I struggle with when using a more PHP orientated approach is syntax so for example I’m using your template as an example and adding new echo lines in to add additional parts to the loop.

    I can’t for the life of me get the permalink in there with the title. It keeps jumping out of the a tag.

    Here’s the segment I’m having issues with – http://pastebin.com/AEF0c0ez

    Anyone have any ideas?

  16. says

    Why do we need our loop in the code above to specify the post type (since the file we’re using is archive-testimonials, shouldn’t “testimonials” actually be the default value there anyway?)

    Just wondered.

  17. Matt Pitts says

    Hi There, thanks for this tutorial, I’ve added the code above and now have the custom post type. I’ve added some posts to it, but when I click the archive page from within the archive setting, I simply get a 404 error. I’m sure Its something simple I’ve done wrong. Any help would be greatly appreciated.

    • says

      Hey Francisco, there’s no change to where to put the code in terms of 2.0. If you’re comfortable editing your theme’s functions.php file, that’s the simplest place. Otherwise, I suggest a plugin like Genesis Extender that allows you to insert custom functions in a little safer way through their interface instead of your functions file (eliminating the chance you could accidentally kill your site with a syntax error or such). :)

      • says

        I messed up in more than one way, Carrie – I was intending to make this comment in the other post.
        Thank you very much for your help! I’m getting the hang of this :)

  18. Peter says

    Hi

    Great tutorial. I have found it really useful.

    One question. I was wondering how I might introduce a ‘View Older Testimonials’ link after the 12th Post – i.e. to allow the visitor to view testimonials 13, 14, 15 etc

    Thanks
    Pete

  19. says

    Carrie, Thank you for showing us how to use WP_Query with the custom post type page templates. My approach is a little bit different. It doesn’t involve using a page template. I’m using the add_filter(‘the_content’, ‘callback_function’) to modify the content. My function checks for a certain custom post type and then adds content, and returns the modified content. If it’s a regular post or page, it simply returns the unmodified content. Here’s the article I wrote about it.

    http://uly.me/custom-content-in-wordpress/

    • says

      Hey Ulysses,

      Thanks for sharing! You’re right – there are a variety of ways to accomplish a similar outcome. My suggestion for your code snippet would be to throw a conditional in to determine whether you’re dealing with a post type – that way you won’t run unnecessary code on posts/pages.\

      Cheers,
      Carrie

  20. says

    This is great, Carrie. I just created a custom blog page template. The Genesis framework is only bringing in the Post type, and I want it to bring in both ‘post’ and ‘podcast’.

    What should I add to the page_blog.php to bring both types in?

    If you can help- thanks!

    -Dan

  21. says

    Oh man, this just saved me such a headache. I’m new to the Genesis Framework and can’t quite wrap my head around it yet… How do I add a sidebar to the provided code? Just looking to add the default ‘sidebar’

    Thanks! – Daniel

Trackbacks