How to Create WordPress Custom Post Types
WordPress’s core functionality is built around Posts. At their most basic, posts are different articles displayed in a reverse chronological order on your website typically under the title of “Blog”. But WordPress allows an extension of the posts functionality by creating “Custom Post Types”.

Creating a Create Post Type also creates a new link in the Admin Menu for that post type. For example, in the image on the right, “Posts” is the default post. Below that we have media, pages, and comments – all of which are default WordPress links. At the bottom, both Projects and Ninja Forms are “Custom Post Types”. They were created using the PHP below and WordPress added a link to them in the sidebar.
Custom Post Types are extremely versatile, so a huge variety of plugins and themes utilize them to create all kinds of functionality within WordPress. While you can create them using a plugin, a basic understanding of PHP can allow you to easily create Custom Post Types inside of a functions.php file in the theme or (more correctly) inside of a plugin.

Adding the Custom Post Types Manually Using PHP
Creating a Custom Post Type directly using PHP is shockingly easy. It requires only a couple of lines of code.
Where to Add the Code
You can add the code below inside of the active theme’s functions.php file (wp-content/themes/theme-name). This is the easiest and quickest way of adding post types. However, it’s also not best practice.
The Custom Post Types you’ll be creating should be evergreen – as in, you keep them regardless of the WordPress them you use. If you add this coding to a theme’s functions.php file, when you deactivate that theme, you won’t be able to use your Custom Post Types anymore. You could transfer the coding from one theme to another simply by copying and pasting, but this isn’t ideal.
Instead, the coding below should be added to a separate plugin you create for this purpose. I recommending creating a custom plugin to which you add in all your custom coding that isn’t related to the WordPress theme. This is actually just as easily said as done. The steps below will use this method because it is best practice.
Step 1 – Create a Plugin
Blank plugins are easy to create in WordPress. Using a blank PHP file, add the following code to the top (including the comments section!)
1 2 3 4 5 6 7 8 9 10 11 12 | /* Plugin Name: Fox Custom Post Types //rename if you'd like Plugin URI: https://whitefoxcreative.com //add your own website here. Description: This plugin is for additional programming that will need to be in the site regardless of the theme. // change for your description Version: 1.0 Author: https://whitefoxcreative.com //add your own website here Author URI: https://whitefoxcreative.com/kimjoyfox //and once more, change this License: GPL2 License URI: https://www.gnu.org/licenses/gpl-2.0.html Text Domain: foxcpt //you can use your own text */ defined( 'ABSPATH' ) or die( 'No script kiddies please!' ); |
You’ll want to take the page you just created and name it anything you like (ie. fox_custom_plugin.php).
Next, create a folder with the same name (fox_custom_plugin) and add this file into the folder. You now have a folder “fox_custom_plugin” with one file in it called “fox_custom_plugin.php”.
You can either zip the folder and upload it to the plugins using WordPress’s Admin or you can just FTP the folder and file into the plugins folder on your WordPress install. Don’t forget to activate the plugin!
Step 2: Creating the Custom Post Type
Your plugin should now be active within your WordPress installation, but it obviously isn’t doing anything yet.
The following coding will allowing you to add a custom post type with a basic setup (see below the code for an explanation):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 add_action( 'init', 'create_posttype_wfc' );
function create_posttype_wfc() {
register_post_type( 'portfolio',
array(
'labels' => array(
'name' =>; __( 'Projects' ),
'singular_name' => __( 'Project' )
),
'hierarchical' => 0,
'supports' => array('title', 'editor', 'thumbnail', 'excerpt'),
'public' => true,
'has_archive' => true,
'taxonomies' => array( 'portfolio_category' ),
'rewrite' => array('slug'=> 'projects'),
)
);
}
Line 1: We’re adding an action here (a build-in WordPress function) to call a PHP function
Line 2 – 17: the function
Line 3: Register the post type (WordPress function) with the following information. The post type’s unique name in this example is “portfolio”
Line 4 – 8: Some basic options about labels. Here, I’m only setting the plural name and the singular name. The plural name will be shown in the sidebar.
Line 9 – 14: These are the most common basic options for post types.
- Hierarchal means the post will act like a page. Pages can be nested under each other, while posts cannot.
- Supports is everything you want that post to be able to have. If you choose not to include, for example, thumbnail, then you won’t be able to set a thumbnail on these custom post types.
- Public means it’s intended to be used on the front-facing portion of your website (as opposed to within the user admin interface only)
- Has Archive will create an archive page (like the posts on the blog) on the front end of the site
- Taxonomies we’ll be working through next.
- Rewrite provides a way to adjust the “slug” or portion of the URL dealing with this Custom Post Type. I named the post type “portfolio”, but the slug is “project”, so the pages on the site will have the following URL: /project/name-of-post
To see all the options available, you can check out WordPress’s developers’ reference website.
If you save your page and visit the Admin page of your WordPress installation, you should now see your custom post type showing up in the sidebar.
Is your custom post type not showing up?
If you’ve added the coding and it’s not showing up, here are a few things to look at.
- Check if you’ve added the coding to the active theme
- Reset the permalinks by going to Settings -> Permalinks and simply clicking the SAVE button
Step 3: Creating and Connecting Taxonomies
In the process of creating a custom post type, you might also decide you want categories or tags specific to that custom post type. These are called taxonomies and can be created like such:
1
2
3
4
5
6
7
8
9
10
11
12
13
14 add_action( 'init', 'customTax' );
function customTax() {
register_taxonomy( 'portfolio_category', array('portfolio'),
array(
'label'=> 'Project Categories',
'public'=> true,
'show_ui'=> true,
'show_admin_column'=> true,
'query_var'=> true,
'hierarchical'=> true,
'rewrite'=> array('with_front'=> true,'hierarchical'=> true,'slug' => 'project_category'),
)
);
}
We’ll start with the same init action as before, and add a custom function name.
Line 2 – 15: Our custom function for taxonomies. You can register more than one taxonomy per function, just repeat lines 3 – 13.
Line 3: The first step is registering the taxonomy. We start with a unique taxonomy name (“portfolio_category”) and then declare which post types we’re associating this taxonomy with. In this example, we’re only adding this taxonomy to the “portfolio” Custom Post Type.
Lines 4- 12: These are some basic options for this taxonomy. At the bottom, you’ll notice the rewrite rule which is similar to the rewrite options in the post type registering function above.
To see all the options available, you can check out WordPress’s developers’ reference website.
Don’t Use a Plugin: Why You Should Create Custom Post Types Without a Plugin
Using PHP to create a Custom Post Type instead of using a plugin can provide some major upsides.
First, it’s easy. I would even say it’s easier than using a plugin in many situations. You’re not trying to learn a UI when all you’ll need is roughly 14 lines of code.
Second, using a plugin to create the code means that you’ll be loading more code than necessary. The Custom Post Type code will be the same, but you now have an entirely separate plugin full of coding that isn’t required.
Third, moving this from the database (plugin) to the files will allow you to easily control this setup if you use Git for version control.
Creating Custom Post Types can provide you with extended functionality to allow you to do almost anything with WordPress. Are you doing something unique with Custom Post Types? Tell us about it below!