Creating a Custom Post Type
WordPress has been around for several years, been used by millions of people, and installed on millions of websites. It’s pretty good at being everything to everyone out of the box. But sometimes you have to take a few extra steps to make it work for you. Custom Post Types are a good example of this.
WordPress comes packaged with the ability to create pages and posts. Sometimes that’s just not enough. Usually you can find a plugin that will add the functionality to add different kinds of content:
- WooCommerce
- Easy Testimonials
- WP Job Manager
All of these plugins create new post types and ways of displaying those post types. But they also come with a lot of overhead that maybe you don’t need. Maybe you just want to add products for affiliate purposes: a description, image, and external URL for your affiliate link. Do you really need to install a monster plugin like WooCommerce to handle something that simple? Definitely not.
What if the custom post type you want to create isn’t created by a plugin? Maybe you have a science fiction website and you want to create an online documentation of alien species. Try to find that plugin in the WordPress directory.
The point is, there are times you might want to create a custom post type yourself vs relying on a plugin. If that’s you, I have great news. IT’S REALLY EASY!! Especially since I am providing all of the code and commented it for you to understand what’s happening!
For this tutorial, I’m going to create a new post type Recipes with recipe categories called Types and with the ability to add tags. I’m going to put all of the code inside a plugin. Why? It just makes life easier. If you can create a website with WordPress, you can create a custom post type plugin for that website. If you really don’t want to deal with a plugin, you can copy everything from the code below into your functions.php file minus lines 2-10 and lines 125-139. On a side note, that should tell you how easy creating a WordPress plugin really is.
I am also making this plugin available for FREE on my Divi Plugins site. Two versions are available: the Divi version adds the Divi Page Builder to your CPT and the other is the standard version and will work on any WordPress theme.
If you want to create the plugin yourself, here’s the full code and then I’ll give you a few tips:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
<?php /** * Plugin Name: Custom Post Type Plugin * Plugin URI: http://www.diviplugins.com/plugins/custom-post-types * Description: Creates new custom post type RECIPES and recipe taxonomy TYPES and TAGS. * Version: 1.0 * Author: Brad Crawford * Author URI: http://www.diviplugins.com **/ // Create a new category called 'Type' for our recipes. if( ! function_exists('dp_define_recipe_type_taxonomy')) : function dp_define_recipe_type_taxonomy() { $labels = array( // these labels change the text in the WordPress dashboard to match your taxonomy name 'name' => 'Types', 'singular_name' => 'Type', 'search_items' => 'Search Types', 'all_items' => 'All Types', 'parent_item' => 'Parent Type:', 'edit_item' => 'Edit Type:', 'update_item' => 'Update Type', 'add_new_item' => 'Add New Type', 'new_item_name' => 'New Type Name', 'menu_name' => 'Types', 'view_item' => 'View Types' ); $args = array( 'labels' => $labels, //reference to the labels array above 'hierarchical' => true, // whether a new instance of this taxonomy can have a parent 'query_var' => true // whether you can use query variables in the URL to access the new post types ); // Tell WordPress about our new taxonomy and assign it to a post type register_taxonomy( 'type', 'recipes', $args ); } endif; // Call our new taxonomy function add_action('init', 'dp_define_recipe_type_taxonomy'); // Add tags to our recipes if( ! function_exists('dp_define_recipe_tag_taxonomy')) : function dp_define_recipe_tag_taxonomy() { $labels = array( // these labels change the text in the WordPress dashboard to match your taxonomy name 'name' => 'Tags', 'singular_name' => 'Tag', 'search_items' => 'Search Tags', 'popular_items' => ( 'Popular Tags' ), 'parent_item' => null, 'parent_item_colon' => null, 'all_items' => 'All Tags', 'edit_item' => 'Edit Tag:', 'update_item' => 'Update Tag', 'add_new_item' => 'Add New Tag', 'new_item_name' => 'New Tag Name', 'menu_name' => 'Tags', 'view_item' => 'View Tags' ); $args = array( 'labels' => $labels, //reference to the labels array above 'hierarchical' => false, // whether a new instance of this taxonomy can have a parent 'query_var' => true // whether you can use query variables in the URL to access the new post types ); // Tell WordPress about our new taxonomy and assign it to a post type register_taxonomy( 'tag', 'recipes', $args ); } endif; // Call our new taxonomy function add_action('init', 'dp_define_recipe_tag_taxonomy'); // Create our new post type if( ! function_exists('dp_register_recipes')) : function dp_register_recipes() { $labels = array( // these labels change the text in the WordPress dashboard and other places to match your custom post type name 'name' => 'Recipes', 'singular_name' => 'Recipe', 'add_new' => 'Add New Recipe', 'add_new_item' => 'Add New Recipe', 'edit_item' => 'Edit Recipe', 'new item' => 'New Recipe', 'all_items' => 'All Recipes', 'view_item' => 'View Recipe', 'search_items' => 'Search Recipes', 'not_found' => 'No recipes found', 'not_found_in_trash' => 'No recipes found in Trash', 'menu_name' => 'Recipes' ); $args = array( 'labels' => $labels, // reference to the labels array above 'public' => true, // whether the post type is available in the admin dashboard or front-end of site 'taxonomies' => array( 'Type', 'Tag'), // currently set to the Type taxonomy we created in the function above. You could leave blank for none or 'rewrite' => array( 'slug' => 'recipe'), // base URL to use for your post type 'hierarchical'=> false, // whether a new instance of this post type can have a parent. 'page-attributes' must be added to the supports array below for this to work. 'has_archive' => true, // enables archive page for post type. Copy page template from theme and rename archive-recipes.php 'supports' => array( // this array defines what meta boxes appear when adding/editing the post type 'title', 'editor', 'thumbnail', 'custom-fields', 'comments', 'excerpt', 'revisions' ), 'menu_icon' => 'dashicons-edit', // sets the icon to display in the menu 'menu_position' => 5, // position in the menu; the higher the number, the lower the position ); // Tell WordPress about our new post type register_post_type( 'recipes', $args ); } endif; // Call our new posty type function add_action( 'init', 'dp_register_recipes' ); // This is required for pretty links to custom post types to work function dp_recipe_cpt_install() { dp_define_recipe_type_taxonomy(); dp_define_recipe_tag_taxonomy(); dp_register_recipes(); flush_rewrite_rules(); } // When the plugin is deactivated/activated, run the pretty link function above register_deactivation_hook( __FILE__, 'flush_rewrite_rules' ); register_activation_hook( __FILE__, 'dp_recipe_cpt_install' ); |
Update: Elegant Themes shared a bit of handy code that will allow you to use the Divi Page Builder (Divi theme or plugin required) when creating any CPT. Below is the code you would add to the file above to allow the use of the page builder on our recipes. Again, this only applies if you are using the Divi theme or plugin.
1 2 3 4 5 6 7 |
// Add the Divi Page Builder to the new post type function my_et_builder_post_types( $post_types ) { $post_types[] = 'recipes'; return $post_types; } add_filter( 'et_builder_post_types', 'my_et_builder_post_types' ); |
Replace ‘recipes’ in the code above with your custom post type. You can also enable the page builder on multiple post types within the same function like this:
1 2 3 4 5 6 7 8 |
// Add the Divi Page Builder to the new post type function my_et_builder_post_types( $post_types ) { $post_types[] = 'recipes'; $post_types[] = 'YOUR-POST-TYPE'; return $post_types; } add_filter( 'et_builder_post_types', 'my_et_builder_post_types' ); |
By default, the layout created from the page builder in your new CPT will be displayed in a template with a sidebar. And the content will not take up the entire width of the container. To fix this, copy the single-project.php template from the Divi folder into your child theme folder. Then rename it single-YOUR-POST-TYPE.php. This will not only fix the content not stretching all the way but will also remove the sidebar and give you a fullwidth page to work with.
Now back to explaining the plugin:
Before you get too overwhelmed with the code above, you can easily make this code work for your custom post type by simply replacing the word “recipe” and “recipes” with any other word and voila!! You have a [insert your word] custom post type. It really is that easy. Same thing with the Type categories. Replace “type” and “types” with your word (solar system/solar systems, planet/planets, galaxy/galaxies).
You can see in the code there are four functions (feel free to rename this however you like). The first three register the tags, categories, and post type respectively. The last function calls all three functions followed by a flush rewrite. This is the same as going to your permalinks and clicking on the save button. If you didn’t do this, the pretty URLs for your new post types wouldn’t work right until you manually updated your permalinks.
If you decide you don’t want to use categories or tags, you can delete those functions (the first two) and also delete them from the last function just before the flush rewrite.
Now we need to display our new custom post types. If you’re using Divi, you can display them with Porfolio Posts Pro. With this plugin, you can display any custom post type in a grid, carousel or fullwidth view. If you don’t have Divi or the plugin, you’ll have to rely on your theme’s template files to display your new posts.
By default, your theme will display your new custom post types using your archive.php and single.php files. If you want to modify these templates just for the new CPTs, you’ll need to create a template for them. Copy the archive.php file to your child theme folder. Rename it archive-[enter your post type].php. In the case of the example, it’s recipes. So we’ll rename the template archive-recipes.php.
The same applies to individual posts. We’ll copy the single-project.php file from our parent theme and paste it into our child theme folder. Then we’ll rename it single-recipes.php.
That’s it. You’ve now created a new custom post type. You can create new post types within the same plugin by copying the first three functions, changing the names, and then adding them to the dp_recipe_cpt_install function. Good luck!
6 Comments
Hi! Perhaps I haven’t entirely understood your explanation, but I’m currently trying to introduce a custom post type, so that I can on a separate page list articles underneath. Since the page is also built with the divi builder, I need the builder to give me the option to select my customs post type (let’s called it recipes like you did), otherwise I have no way of displaying the entirety of my recipes on the overarching page with the builder. I copied all of the code and changed the corresponding parts in the code to my personal custom post, however it’s still not giving me an option to display the new type. What could I do to change that? Thanks!
March 10, 2017
Agreed Anna, this is the only reason we still use Visual Composer.
April 28, 2017
How would you integrate schema.org for the recipes, Lawrence?
I feel like this would be the missing piece of the puzzle 😀
July 9, 2017
Hi
When I copied your code into fuctions php I got a Parse error message (unexpected ” on line 84) I read through and I couldn’t find the error… has anyone else had this?
November 8, 2017
Now that CPT support is built-in to Divi, most of this just works. However, I find my CPT’s don’t have the “Title” setting in the “Divi Page Settings”. So I can’t hide the Title, Meta, and Featured image and design the whole CPT in Visual Builder. Any tips for how to accomplish that?
November 30, 2018
I have the same issue as Tevya and can’t find an answer. Thanks!
July 31, 2019