In this article, let’s talk about custom post types. What are they, why we need them, how to create them programmatically, and have a look on its anatomy in case you want to have custom design templates for the pages generated by the custom post type.
What is custom post type and do I need it?
By default, WordPress gives us several post types: page, post, attachment, navigation menu, revisions, custom css and changesets. Among them, Pages and Posts are probably the most recognizable ones.
You would probably asks yourself several times, “Do I need a custom post type? Can things be ok with just using pages or posts?” If that question still hanging on your head, I would suggest to create custom post type if:
- You need to filter and query the post type articles separately from other post types, and have to do it frequently, via WordPress WP_Query or via Rest API endpoints
- It needs custom taxonomies which should be filtered and queried, too.
- You don’t mind creating a bunch of templates to support the custom post type’s single page, archive page and taxonomies page. It’s optional though, because without them, WordPress will use the style from the current theme. But in many cases you would want to have custom designs for those generated by custom post type, and you would need to know how to do it.
In the other side, if you just want to post articles which have some extra fields that does not yet have in Posts and Pages, then it’s easier to create custom meta fields> and attach to posts / pages instead.
Notices:
- There will be a difference in slugs. If you use WordPress built-in Pages and Posts, the slug of a single article / page can be http(s)://domainname.com/{name-of-the-article}. If you access a a custom post type single page, it will be http(s)://domainname.com/{custom-post-type-base}/{name-of-the-article}. So it would somehow affect SEO if think about how the slug that include keyword should be close to the domain name.
- The custom post type will be saved together with other post types in wp_posts table
If now you already decided that you need custom post types, not custom meta fields, then read on!
How to add custom post type programmatically in WordPress
If you don’t want to touch the code, it’s fine to just use any plugin to do this. But, creating the custom post type programmatically is pretty easy. And below is how you can do it.
To make things easier to imagine, let’s say we have a private clinic website and would need to create the new custom post type to display doctor profiles.
// WordPress suggests adding to 'init' hook and not before, so let's go with it
add_action( 'init', 'ak_create_doctor_profiles_cpt' );
function ak_create_doctor_profiles_cpt () {
register_post_type( 'doctor',
array(
'labels' => array(
'name' => 'Doctors',
'singular_name' => 'Doctors',
'description' => 'A portfolio of current doctors in the clinic'
),
'has_archive' => true,
'menu_icon' => 'dashicons-admin-users',
'supports' => array('title', 'editor', 'thumbnail'),
'public' => true,
'rewrite => array(
'slug' => '', // Add this only if you need a custom slug base
'with_front' => false
)
)
);
}
This WordPress page about custom post types explains the parameters very well so please read it.
Here, let’s go through some useful one:
- has_archive: can be set to false if you want to disable the front page http(s)://domainname.com/doctor/
- supports: by default, WordPress will give ‘title’, ‘editor’, ‘comments’, ‘revisions’, ‘trackbacks’, ‘author’, ‘excerpt’, ‘page-attributes’, ‘thumbnail’, ‘custom-fields’, and ‘post-formats’. Only some of them are necessary, so we only include here title (doctor name), editor (description), thumbnail (probably a photo).
- rewrite, slug: rewrite the base that is used in http(s)://domainname.com/{base}/{single-record-slug}. It is useful if you want it to be different language than “doctor” – the custom post type name that WordPress will use.
- dashicons: the icon that shows up in WordPress dashboard.
Creating custom taxonomies programmatically
What’s custom post types without custom taxonomies? So let’s create one also.
Supposed that we need a categorized page for doctors based on their expertise (cardiologists, dermatologists, dentists, allergists).
And so when user visits page http(s)://domainname.com/expertise/cardiologists for example, they will see a list of doctors who can solve your blood and heart issues.
To create custom taxonomies programmatically, just continue with the function ak_create_doctor_profiles_cpt(), add the function register_taxonomy() below the register_post_type() function:
register_taxonomy( 'expertise',
array('doctors'),
array(
'labels' => array(
'name' => 'Expertise',
'singular_name' => 'Expertise',
'menu_name' => 'Expertises'
),
'rewrite => array(
'slug' => '', // Add this only if you need a custom slug base
'with_front' => false
)
)
);
}
Again, WordPress Codex provides really helpful info about how to set your own config. They are quite straightforward, but here is one tricky part if you haven’t noticed: the public parameter will affect other parameters like publicly_queryable, show_ui and show_in_nav_menus. So if you would like to change the visibility of the taxonomy, use the combo carefully.
Creating template files for custom post type
Before going deeper, let’s have a look of the anatomy of custom post type pages. In our “doctor” example, it will be like:
- Archive page: can be accessed via http(s)://domainname.com/doctor/
- Single page: for every record that you create with the custom post type, it can be seen via http(s)://domainname.com/doctor/{single-record-slug}/
- Taxonomy page: for every term (e.g cardiologists, dermatologists, dentists, allergists) that is created, the page that collects all records that had the term can be accessed via http(s)://domainname.com/expertise/{term-slug}
Now let’s see how you can create and map the correct template to each of the types mentioned above.
Archive page
To make a custom archive page, create a PHP file and name it archive-doctor.php. WordPress system will automatically detect it and load it when your archive loads.
Single page
Similar to the way to create archive page, just create single-doctor.php and implement your design there.
Taxonomy page
The name for taxonomy page that WordPress can map the template is taxonomy-expertise.php.
How to query the custom post type
WP_Query() and get_posts() both have a parameter that you can filter the post type to return. Here is the examples from both:
For WP_Query():
$args = array(
'post_type' => 'doctor',
'post_status' => 'publish',
'posts_per_page' => 20,
);
$doctor_profiles = new WP_Query($args);
if ( $doctor_profiles->have_posts ) {
while ( $doctor_profiles->have_posts ) {
$doctor_profiles->the_post();
// Do something with the records
}
wp_reset_postdata();
}
For get_posts():
$args = array(
'post_type' => 'doctor',
'post_status' => 'publish',
'numberposts' => 20, // Default of get_posts is 5, so remember to set this value if you want to have more than 5 records returned
);
if ( ! empty($doctor_profiles) ) {
foreach ( $doctor_profiles as $profile )
{
// Do something with the records
}
}
Visually: how it looks like in WordPress admin dashboard
So here’s how you can see the newly created custom post type.
That’s it! Simple as life. Bye and see you in the next article!