July 20, 2015
•Last updated November 5, 2023
Mastering WordPress Custom Post Types
WordPress is everywhere. More than 25% of websites are built on the CMS that is highly customizable. Being free and completely configurable explains the popularity and many designers and developers use it for creating their websites or their clients websites, not to mention all the documentation and resources available for WordPress today.
In early 2005, the team at Automattic expanded on the platform by introducing custom post types to the world. With these added features, designers and developers could now craft WordPress to be whatever it is they wanted. This post dives deep on custom post types, why we use them, and what makes them so powerful. Iâll discuss history, best practices, and provide a real-world example.
History
A little history lesson before we get into the basics will probably help you understand where and why custom post types came to be. Custom post types are said to have shifted WordPress from a blogging platform into a full-blown content management system. History proves this as youâll read below.
In the beginning, WordPress 1.0 contained a function bundled with the platform called wp_insert_post()
. This function did what you expect and inserted the post. A no brainerâŠ
By the time, WordPress 1.5 rolled out you could now pass a parameter to define which type of post you wanted to output by using a post_type
value in the function. Obviously you needed to create more constraints and enable the functionality with the code but the potential was there if you wanted it.
WordPress 2.9 finally introduced the register_post_type()
function to the public. No longer were hacks and tons of advanced code was needed to define a custom post type. Awesome!
With WordPress 4.2 already here we can now utilize easy to install plugins to do a lot of the heavy lifting for us but being a perfectionist I still prefer to create my own for the sake of knowing exactly what is going on inside of WordPress.
There are some great code generators available to help you save some time with this as well.
What is a custom post type?
Custom post types are just posts. They are like any other post inside WordPress, but the main difference is in their definitions and parameters. If you wanted to separate different chunks of posts into a new area on your website you could do so by creating a custom post type. Inside of called them posts you could call them projects for example. Some common examples I have used are:
- Reviews
- Projects
- Portfolio Pieces
- Listings
- Case Studies
- and so many more
Why use a custom post type?
You would use a custom post type when you need to divide up the content on your website. Rather than just a typical blog you can create new posts that are of different content and focus. Doing this allows you to easily maintain the content as well as add new content in the future using the WordPress backend. Rather than editing code and updating every time you can use what WordPress was built for by offering a dynamic approach to creating and maintaining a website.
Example
Say you wanted to create a portfolio section for your creative agencyâs website. You could do this all from scratch but wouldnât it be better to tie into the power of WordPress and use a custom post type for each new project you add? Doing this is relatively simple.
To start, I would create a custom post type called projects. Doing this would allow us to create a new area on our website that would be filtered and output strictly for this type of content. To put it in perspective you would end up with a URL like http://exampleagency.com/projects/
. You could then post projects as projects or even go one step further and have different post types or taxonomies within the projects post type. Sounds confusing doesnât it? Itâs not that bad once you get the hang of it. Iâll show you a step-by-step approach later in the post so keep reading!
Plugins
I mentioned before that plugins can take care of creating these post types for you. There are a number of them available that offer both advanced and simple setup depending on your needs. I personally donât like to rely on too many plugins in my arsenal. Itâs not that they arenât powerful and future proof, but there are times where I need to get extra technical with my own code and doing this with a plugin just doesnât work. A couple of good plugins to try are:
Custom Post Type UI
The Custom Post Type UI plugin provides an easy to use interface that allows you to create and administer custom post types and taxonomies in WordPress. The plugin simply creates the types. You will need to add them to the theme yourself.
Types
Types lets you customize the WordPress admin area by adding content types, custom fields, and taxonomy. You will be able to craft the WordPress admin and turn it into your very own content management system.
Creating Your Own Custom Post Type
Before getting started, I must state that adding a custom post type requires additional code inside your theme or installed as a plugin. If you find yourself needing to use your custom post type on multiple websites or different themes then I suggest you create a plugin out of the code below. Doing this is very easy but, unfortunately, isnât the scope of this post. Iâll be sure to write about how to create a WordPress plugin in the very near future.
Getting Up and Running
If youâre new to WordPress and arenât versed in PHP yet then I invite you to follow along but also try and see if a plugin is suitable enough for you. Iâll be working on a local WordPress installation. My environment is a Mac and at this time Iâm running WordPress 4.2.2 with MAMP. I wrote another post on How to install WordPress locally or on your server if you need direction on how to do so.
For demonstration purposes Iâll be using a child theme based off the default Twenty Fifteen theme.
Child Theme Setup
By default WordPress comes with the Twenty Fifteen theme. To get started I want to create a child theme of the Twenty Fifteen theme so that if there are future updates any changes I make wonât get overwritten. Most people donât know how powerful child themes can be and if youâre using a theme you didnât produce, creating a child theme is an absolute must.
Create a new folder called twentyfifteen-child
in the wp-content/themes
directory.
Create a new folder for your child theme
inside this folder we need a stylesheet and a new functions.php file to create our custom post types. Create both of those files now. Now our file structure looks like this:
Inside our style.css
file we need to add some data to let WordPress know it exists and that itâs also extending from the default twentyfifteen
theme as a child theme. The code you enter is up to you but it should look very similar to the commented text below. Add it at the top of your style.css
file.
/*
Theme Name: My Custom Post Type Theme
Theme URI: http://www.yourdomain.com/theme/
Description: A demo theme for authoring custom post types
Author: Andy Leverenz of Web-Crunch
Author URI: http://www.web-crunch.com
Template: twentyfifteen
Version: 1.0.0
*/
@import url(â../twentyfifteen/style.cssâ);
The important things to note is that we are importing the CSS file from the default twentyfifteen theme and then allowing ourselves the ability to customize any additional styles that wonât be overwritten in our child-theme. Be sure to verify the file path as it will break the themeâs presentation layer otherwise.
Pay attention to the Template: declaration as well because this needs to be the name of the theme you are creating the child theme from.
If you navigate to your WordPress dashboard and go to Appearance/Themes
you should be able to activate the child theme. I copied the thumbnail over to the child theme directory. You can add your own custom thumbnail if you please.
Now we have the ability to adjust any styles in the theme without the fear of being overwritten.
Up next we need to pay attention to our functions.php
file. Inside this file we will create and initialize our custom post type. The code we input will allow us to add custom post types from the backend of the WordPress dashboard. Later we will create a new template for the new custom post type which will then output the content we are striving for.
Creating the custom post type
Navigate to your functions.php
file and enter the code below.
<?php
if ( ! function_exists(âprojectsâ) ) {
// Register Custom Post Type
function projects() {
$labels = array(
ânameâ => _x( âProjectsâ, âPost Type General Nameâ, âtext_domainâ ),
âsingular_nameâ => _x( âprojectâ, âPost Type Singular Nameâ, âtext_domainâ ),
âmenu_nameâ => __( âProjectsâ, âtext_domainâ ),
âname_admin_barâ => __( âProjectâ, âtext_domainâ ),
âparent_item_colonâ => __( âProject:â, âtext_domainâ ),
âall_itemsâ => __( âAll Projectsâ, âtext_domainâ ),
âadd_new_itemâ => __( âAdd New Projectâ, âtext_domainâ ),
âadd_newâ => __( âAdd Newâ, âtext_domainâ ),
ânew_itemâ => __( âNew Projectâ, âtext_domainâ ),
âedit_itemâ => __( âEdit Projectâ, âtext_domainâ ),
âupdate_itemâ => __( âUpdate Projectâ, âtext_domainâ ),
âview_itemâ => __( âView Projectâ, âtext_domainâ ),
âsearch_itemsâ => __( âSearch for a projectâ, âtext_domainâ ),
ânot_foundâ => __( âNo projects foundâ, âtext_domainâ ),
ânot_found_in_trashâ => __( âNo projects found in Trashâ, âtext_domainâ ),
);
$rewrite = array(
âslugâ => âprojectsâ,
âwith_frontâ => true,
âpagesâ => true,
âfeedsâ => true,
);
$args = array(
âlabelâ => __( âprojectsâ, âtext_domainâ ),
âdescriptionâ => __( âA custom project post for the portfolio section of the websiteâ, âtext_domainâ ),
âlabelsâ => $labels,
âsupportsâ => array( âtitleâ, âeditorâ, âexcerptâ, âauthorâ, âthumbnailâ, âtrackbacksâ, ârevisionsâ, âcustom-fieldsâ, âpage-attributesâ, ),
âtaxonomiesâ => array( âcategoryâ, âpost_tagâ ),
âhierarchicalâ => true,
âpublicâ => true,
âshow_uiâ => true,
âshow_in_menuâ => true,
âmenu_positionâ => 5,
âmenu_iconâ => âdashicons-artâ,
âshow_in_admin_barâ => true,
âshow_in_nav_menusâ => true,
âcan_exportâ => true,
âhas_archiveâ => âpast_projectsâ,
âexclude_from_searchâ => false,
âpublicly_queryableâ => true,
ârewriteâ => $rewrite,
âcapability_typeâ => âpageâ,
);
register_post_type( âprojectsâ, $args );
}
// Hook into the âinitâ action
add_action( âinitâ, âprojectsâ, 0 );
}
?>
The code above is fairly straight forward but it is a little advanced. If you read through it youâll start to get the idea that we are just defining built in parameters to both create the custom post type as well as craft the UI on the WordPress backend. The function itself is called projects
. Within it Iâve defined how I want it to appear and operate. If you head to your WordPress backend you should now see a new projects within the interface.
At this stage we have the interface working and initialized but if I went to create a new project nothing would output into our theme. To test in the near future we do require some content so Iâm going to add a couple projects so that when we incorporate it into our theme there is something to output. If youâre following along find the images and content Iâve imported in the demo files or just use your own.
Outputting the custom post type data
If you go to try to view the post youâll get a Page Not Found error which is what we are expecting. Nowhere in our theme is there a way for the new post type to output yet so we have to add this functionality. To do this in a child theme we need to create a template for the new post type. Letâs do that now. In your child-theme directory create a file called projects-template.php
. Inside the file add the comment and PHP code below:
<?php
/*
Template Name: Projects Template
*/
?>
Create a Projects Page
The next step is to create a page called Projects in WordPress so that we can output our new post type onto it. Doing this requires us to assign the new template to our page which you should now see in the template selection area on the lower right hand site of the page.
Create a new page called "Projects" and assign our newly created project page template to it.
Great, now we have a new page with a new template. If you navigate to the Projects page youâll see a white screen. Donât worry this is what we want. The template allows us to break away from the default page structure of WordPress if we want. Doing this allow you to customize the experience which for custom post types is what we want.
Letâs setup the template to get the theme displaying correctly to star things off. Inside projects-template.php
update the code to look like this:
<?php
/*
Template Name: Projects Template
*/
get_header(); ?>
<div id=âprimaryâ class=âcontent-areaâ>
<main id=âmainâ class=âsite-mainâ role=âmainâ>
// content will go here
</main><!â .site-main â>
</div><!â .content-area â>
<?php get_footer(); ?>
Updated template
The theme should be displaying at this point. Youâll notice we donât have any post yet though. This is because we are missing the back bone of WordPress which is the loop. Letâs add that now. Add the code below inside the main
container.
<?php
// Start the loop.
while ( have_posts() ) : the_post();
// Include the page content template.
get_template_part( âcontentâ, âpageâ );
// End the loop.
endwhile;
?>
Here we have added the famously known WordPress loop which is looking for any new posts we create inside our database. Inside the loop is a get_template_part
function which allows us to use different templates for each page. You can create your own template and include here as well. Iâm going to create a new template called project. It will be named content-project.php
. Add it to your child theme directory and change the code above to this:
<?php
// Start the loop.
while ( have_posts() ) : the_post();
// Include the page content template.
get_template_part( âcontentâ, âprojectâ );
// End the loop.
endwhile;
?>
If you preview the page you should still see no posts coming through. In order to get the custom post types to display we need to create a new query
which will allow us to find the post type called projects
that we created before. All we are doing is creating a couple variables and a new query and then passing it through the WordPress loop. The updated code is a little advanced but looks like this:
<?php
// set custom post type name to a variable
$args = array(âpost_typeâ=>âprojectsâ);
// set a variable to use to pass the arguments into a new WP query
$loop = new WP_Query($args);
// Display the contents of the query
while ( $loop->have_posts() ) : $loop->the_post();
// Include the page content template.
get_template_part( âcontentâ, âprojectâ );
// End the loop. Reset Query
endwhile;
wp_reset_query();
?>
See the comments above to get a better idea of whatâs going on. Essentially we are looping through all posts to find the ones with the post type of projects
. Those posts are then fed through our template and output on the page.
Customizing the output
Chances are you will want to customize the content that gets output from the loop we wrote above. You can do so by modifying code that goes within the content-project.php
file we created. I customized mine by copying and pasting the code from the default twentyfifteen parent theme file called content-page.php
. From there I tweaked it a bit to display the data I wanted.
Our content-project.php
file ends up containing the code below. Check the demo files if itâs easier for you rather than copy and pasting from this post.
<article id=âpost-<?php the_ID(); ?>â <?php post_class(); ?>>
<?php
// Post thumbnail.
twentyfifteen_post_thumbnail();
?>
<header class=âentry-headerâ>
<?php the_title( â<h1 class=âentry-titleâ>â, â</h1>â ); ?>
</header><!â .entry-header â>
<div class=âentry-contentâ>
<?php the_excerpt(); ?>
<?php
wp_link_pages( array(
âbeforeâ => â<div class=âpage-linksâ><span class=âpage-links-titleâ>â . __( âPages:â, âtwentyfifteenâ ) . â</span>â,
âafterâ => â</div>â,
âlink_beforeâ => â<span>â,
âlink_afterâ => â</span>â,
âpage linkâ => â<span class=âscreen-reader-textâ>â . __( âPageâ, âtwentyfifteenâ ) . â </span>%â,
âseparatorâ => â<span class=âscreen-reader-textâ>, </span>â,
) );
?>
</div><!â .entry-content â>
<?php edit_post_link( __( âEditâ, âtwentyfifteenâ ), â<footer class=âentry-footerâ><span class=âedit-linkâ>â, â</span></footer><!â .entry-footer â>â ); ?>
</article><!â #post-## â>
After adding some new projects you should now be able to see the working result of our integration. Hereâs a few screenshots of what Iâve built so far to give you an idea.
WordPress Project Custom Post Type Section and UI
Projects Landing Page
Indvidual Project Page
Taking things further
Your custom post type can be of virtually any type. You can take things further by having a custom post type within a custom post type or having categories or taxonomies that correspond with each. The possibilities are really endless and this is why custom post types are so powerful. You can create anything from a portfolio to a review or rating system, or even a custom portal for that new web app youâve been thinking about building.
From here I invite you to take what Iâve shown you and build upon it. Introduce it to your own themes and applications and see how you can make your website more intriguing and powerful to your users. Good luck with your journey and if you have questions feel free to leave a comment!
Categories
Products and courses
-
Hello Hotwire
A course on Hotwire + Ruby on Rails.
-
Hello Rails
A course for newcomers to Ruby on Rails.
-
Rails UI
UI templates and components for Rails.