30 June 2010
Create your first WordPress Custom Post Type
Let me get something off my chest. WordPress sometimes, just ever-so occasionally, makes things sound a little harder than they actually are. Custom post types sound quite scary, but really they aren’t. Jane Wells, WordPress UI guru, commented on their name in my last article for Think Vitamin:
“They just got named poorly because they live in the Posts table in the database. Think of them more like custom objects/content types.”
Cool – it’s just custom content. What’s the point of that then? Can’t we just categorise blog posts and order our pages in nice hierarchies? Can’t we use conditionals to spit out different CSS stylesheets? Well yes, we could. But admit it – it’s not fun.
And hands up if you’ve ever tried to explain to a client what a custom field is. Hurts, doesn’t it? So thank goodness for wonderful people like Jane who have given us a solution.
What is it and What it isn’t
Everyone’s talking about them. I recently asked Chris Coyier from CSS-Tricks what excited him about WP3 and he replied custom post types:
“Think of how Tumblr works – how you can publish photos, quotes, links and whatever else. You could create those same types now with WordPress, and build themes to support and have special styles for them. This is fantastic stuff for building custom sites!”
Make sense? Well according to Jane, Chris misinterpreted their goal:
“Custom post types aren’t really meant for that use […] Custom post types are great for things that are more or less catalogued: products (in an e-commerce site), listings for a real estate site, etc. For regular content creation as described [by Chris], you can already do [that] by using custom taxonomies and/or stylesheets to make post templates.”
Now I’m going to go out on a limb here and say that Chris made a interesting suggestion. I say this for two reasons: firstly because I think the great thing about WordPress is we can use it in the way we feel it should be used. There might be a different or better way, but there is no wrong way to do something (unless it doesn’t work!). Secondly I refuse to believe that many designers would read up on something as scarily titled as ‘custom taxonomies‘.
Indeed I expect to see WordPress themes cropping up all over the place that mimic the way Tumblr themes look and work. WooThemes have already released three.
Get your Hands Dirty
Now before we dig in I want to say this – custom post types make things a lot easy for non-technical people to use the WordPress admin to enter content. However the designer/developer still needs to have a reasonable grasp of PHP and needs to be prepared to get their hands dirty (unless they opt for a plugin that does the job for you like http://wordpress.org/extend/plugins/custom-post-template/ or http://wordpress.org/extend/plugins/custom-post-type-ui/)
For our tutorial we’re going to be editing functions.php which is your theme directory. We’re simply adding to this file, so feel free to start at the top or at the bottom – just don’t change any of the code that’s already there. For the more confident of you out there you could adapt this code into a plugin.
With a few edits we are going to create a custom post type for our portfolio, and a template which will use this information. We’ll end up with a new panel in the admin menu which looks like this:
A new overview page called “My Portfolio”:
And a new place to enter our content:
Step 1
Here’s the first bit of code we need to add to functions.php, which I’ll review below.
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 | add_action('init', 'portfolio_register'); function portfolio_register() { $labels = array( 'name' => _x('My Portfolio', 'post type general name'), 'singular_name' => _x('Portfolio Item', 'post type singular name'), 'add_new' => _x('Add New', 'portfolio item'), 'add_new_item' => __('Add New Portfolio Item'), 'edit_item' => __('Edit Portfolio Item'), 'new_item' => __('New Portfolio Item'), 'view_item' => __('View Portfolio Item'), 'search_items' => __('Search Portfolio'), 'not_found' => __('Nothing found'), 'not_found_in_trash' => __('Nothing found in Trash'), 'parent_item_colon' => '' ); $args = array( 'labels' => $labels, 'public' => true, 'publicly_queryable' => true, 'show_ui' => true, 'query_var' => true, 'menu_icon' => get_stylesheet_directory_uri() . '/article16.png', 'rewrite' => true, 'capability_type' => 'post', 'hierarchical' => false, 'menu_position' => null, 'supports' => array('title','editor','thumbnail') ); register_post_type( 'portfolio' , $args ); } |
Anyone who’s worked with WordPress before will recognise the structure here. We’re adding an action when the WP Admin initialises to call the function portfolio_register(). In that function we create two arrays, $labels and $args, and then use register_post_type to pull it all together. In doing so we name the new custom post type ‘portfolio’ and tell it to use the arguments from $args.
The devil is in the detail, so let’s run over some of those arguments. A full list can be found at http://codex.wordpress.org/Function_Reference/register_post_type. First let’s look at $labels:
- name – this is the (probably plural) name for our new post type
- singular_name – how you’d refer to this in the singular (such as ‘Add new ****’)
You can probably work out the rest of $labels for yourself, as they simply refer to different circumstances in which the name of your custom post type would be used.
And now $args:
- public – should they be shown in the admin UI
- show_ui – should we display an admin panel for this custom post type
- menu_icon – a custom icon for the admin panel
- capability_type - WordPress will treat this as a ‘post’ for read, edit, and delete capabilities
- hierarchical – is it hierarchical, like pages
- rewrite – rewrites permalinks using the slug ‘portfolio’
- supports – which items do we want to display on the add/edit post page
That’s the first simple step, and it should be enough to see your new custom post time in the WordPress admin. Save functions.php and take a look!
Step 2
The next thing we need to do is register a taxonomy. Or, in English, create categories for this new content type.
For example, in our portfolio we want to include the names of technologies and software used to create our work. I’m going to call this taxonomy ‘Skills’, and populate it with things like HTML, CSS and jQuery.
It’s just one line of code:
1 | register_taxonomy("Skills", array("portfolio"), array("hierarchical" => true, "label" => "Skills", "singular_label" => "Skill", "rewrite" => true)); |
The first item here is the taxonomy name, ‘Skills’. The second is the name of the object type we’re applying it to, in our case the custom post type ‘portfolio’ (which is an array). Finally our arguments; you can find a full list at http://codex.wordpress.org/Function_Reference/register_taxonomy, and here we’re using just three which have the same meaning as described in Step 1.
Add that line of code in and you should now see:
You can then enter new ‘skills’ just like you’d enter categories for blog posts. It looks like this:
Step 3
The third step is to add custom data fields to the add/edit post page.
For our portfolio we can add things like the year the piece was published and details on who designed, built and produced the site/design.
There’s a bit more code here, but read through it in order and it should make sense:
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 | add_action("admin_init", "admin_init");
function admin_init(){
add_meta_box("year_completed-meta", "Year Completed", "year_completed", "portfolio", "side", "low");
add_meta_box("credits_meta", "Design & Build Credits", "credits_meta", "portfolio", "normal", "low");
}
function year_completed(){
global $post;
$custom = get_post_custom($post->ID);
$year_completed = $custom["year_completed"][0];
?>
<label>Year:</label>
<input name="year_completed" value="<?php echo $year_completed; ?>" />
<?php
}
function credits_meta() {
global $post;
$custom = get_post_custom($post->ID);
$designers = $custom["designers"][0];
$developers = $custom["developers"][0];
$producers = $custom["producers"][0];
?>
<p><label>Designed By:</label><br />
<textarea cols="50" rows="5" name="designers"><?php echo $designers; ?></textarea></p>
<p><label>Built By:</label><br />
<textarea cols="50" rows="5" name="developers"><?php echo $developers; ?></textarea></p>
<p><label>Produced By:</label><br />
<textarea cols="50" rows="5" name="producers"><?php echo $producers; ?></textarea></p>
<?php
} |
First of all we call the add the admin_init function to the queue when the WordPress admin initialises, and within that function we add two meta boxes – places to enter our data. The context for these two statements is
1 | <?php add_meta_box( $id, $title, $callback, $page, $context, $priority ); ?> |
The only difference between the two is where we place them on the screen. The ‘year completed’ is placed in the sidebar using ‘side’ whilst the ‘credits’ are placed in the main flow of the page using ‘normal’.
Within the two functions there is some vanilla WordPress PHP code and HTML to help define our old friend custom fields. Make sure to include
1 | global $post; |
…so that we can then query the current post using
1 | $custom = get_post_custom($post->ID); |
Once the two new meta boxes have been added it looks like this:
The final thing to do in step 3 is to make sure we then save these values with this post. I do this with
1 | add_action('save_post', 'save_details'); |
and
1 2 3 4 5 6 7 8 | function save_details(){ global $post; update_post_meta($post->ID, "year_completed", $_POST["year_completed"]); update_post_meta($post->ID, "designers", $_POST["designers"]); update_post_meta($post->ID, "developers", $_POST["developers"]); update_post_meta($post->ID, "producers", $_POST["producers"]); } |
There’s nothing too tricky here. Again we’re adding an action, this time to the ‘save_post’ event. It fires the function save_details() which uses update_post_meta (http://codex.wordpress.org/Function_Reference/update_post_meta) to save the relevant data.
Step 4
A nice little touch is to rejig the layout of the My Portfolio page to display some of this information. If you’ve followed through the article so far this should all make sense to you:
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 | add_action("manage_posts_custom_column", "portfolio_custom_columns"); add_filter("manage_edit-portfolio_columns", "portfolio_edit_columns"); function portfolio_edit_columns($columns){ $columns = array( "cb" => "<input type=\"checkbox\" />", "title" => "Portfolio Title", "description" => "Description", "year" => "Year Completed", "skills" => "Skills", ); return $columns; } function portfolio_custom_columns($column){ global $post; switch ($column) { case "description": the_excerpt(); break; case "year": $custom = get_post_custom(); echo $custom["year_completed"][0]; break; case "skills": echo get_the_term_list($post->ID, 'Skills', '', ', ',''); break; } } |
Here we’re adding two more functions to the WordPress Admin. The first, portfolio_edit_columns($columns), simply defines the columns. The first two arguments “cb” and “title” are part of the core so don’t play with those too much (you can of course rename “Portfolio Title”). It’s the next three that come from our custom post type, “description”, “year” and “skills”.
We have one more function to tell WordPress where to get this data from – portfolio_custom_columns($column). Using a simple switch/case we can define what data to actually show in the column layout. For the “description” we use the_excerpt(), for “year” we get the custom field data using get_post_custom(), and for “skills” we get a comma separated list of the terms/taxonomies/categories using get_the_term_list().
With that we have our customised columns:
One final touch
Be default custom post types will display using single.php, or index.php as a fallback. The great thing is we can create our own custom template using the filename single-xxxxxx.php. In our case this is single-portfolio.php. Just create your template file in your theme directory and the custom post type will use it. How you display the data is totally up to you.
Hey, did you also notice the ‘Featured Image’ option on the add/edit page. That works out-of-the-box thanks to the ‘thumbnail’ part of:
1 | 'supports' => array('title', 'editor', 'thumbnail') |
You just need to make sure to include the following line of code in functions.php:
1 | add_theme_support('post-thumbnails'); |
For more details check out this excellent post by Mark Jaquith.
Rewrite Problems?
There are a few reported problems out there about the rewriting of custom URLs; in short, they sometimes don’t work. However, if you’re experiencing this problem there are a couple of easy fixes.
First, simply go to the Settings > Permalinks page, which will flush the permalinks (assuming that your WordPress install can write to the .htaccess file). This should clear up most problems related to permalinks, custom post type related or not.
If that doesn’t work you can add a line of code after you register the post type:
1 2 | register_post_type( 'portfolio' , $args ); flush_rewrite_rules(); |
This worked for me on a particularly problematic install.
Conclusion
And there we have it! That is a whistle-stop tour of custom post types which I hope gives you the appetite to explore further.
The best thing is to experiment with the code, read through the documentation in the WordPress Codex, and share your ideas with others. Like any new feature I’m sure it will evolve as users create new and exciting ways to use it, and we’d love to hear about how you’re using custom post types here at Think Vitamin.





We're big fans of 
Matt Hill
# June 30, 2010 - 12:14 pm
I’ve been doing some work with Custom Post Types and while I can see that they are useful for some things, I do feel that they are rather crippled from the start.
Why? Simple, many (if not most) of the existing WP post related functions have not yet been extended to work with custom post types. So for example, there’s no ‘out of the box’ methods for handling custom posts the way you would handle standard blog posts. See here for an example: http://wordpress.org/support/topic/398135
While I appreciate that it’s a big job to make all the existing functions work with custom post types, I do think it’s very disappointing, and a bit misleading, for a new version of WP to be released without this support.
steve
# July 1, 2010 - 4:13 am
Spot on Matt, it seems to be a non native feature due to the hoops you need to jump through just to get something substantial.
Ian
# July 1, 2010 - 5:12 am
Yeah, I’m having a lot of similar problems at my site. Just hard to get everything working with it. Weird things, like the title not taking into account the custom ost types when figuring out how many “posts” are in a category, and so on.
JohnONolan
# July 13, 2010 - 3:31 am
I agree with you on that specific issue (archive templates) Matt, and it was actually me who submitted the official ticket for that to be included in 3.1 – see http://core.trac.wordpress.org/ticket/12974
I don’t think it’s at all misleading for any opensource (read: free) software to do (or not do) anything at all to be honest. Custom taxonomies have been in WordPress since version 2.8 and are only just now getting a front end to make them useful in 3.0. Is that misleading too? Nope, it’s just evolved over time, as everything with WordPress does.
Matt Hill
# August 6, 2010 - 3:06 pm
I should clarify up what I mean by “misleading”.
Custom Post Types have a poor name. They should have been called “Custom Content Types”. CPT act more like WP Pages, than Posts. All the advance advertising of CPT that’s happened in the last 6 months never really made it clear that CPT are not in fact Posts, they don’t behave like them, and they don’t work with most of WPs current post related functions.
It’s reasonable for someone to read the phrase “Custom Post Types” and think “Great! All the power of normal Posts, but I can customise them too!”. But of course, this is far from the truth.
The fact that CPT don’t work with most of the Post functions in WordPress won’t be apparent to most users until they actually start to use them. That’s what’s misleading.
Justin Tadlock
# August 18, 2010 - 7:42 am
*Some* post-related functions might not work with custom post types, but that’s a long way from “most.” In fact, nearly all post-related functions work with custom post types. But, some things are meant to be, well, “custom.”
Jamie Brightmore
# June 30, 2010 - 12:21 pm
Fantastic walk-through. I need to start playing with this feature soon for a personal project, this will come in very handy! Cheers :)
SVIT AVTO
# June 30, 2010 - 1:04 pm
Wow, and in fact set out really thoughtful …
Bookmark, think later finish reading
Steven Grant
# June 30, 2010 - 1:11 pm
I have to say when I heard about custom post types I was super excited. I love ExpressionEngine and custom fields are the huge selling point for me. However, not all projects have budget for EE and so WP3.0 looked to fit the need.
I’ve been left really underwhelmed. Not being able to define CPTs from the control panel just seems wrong and almost ‘hacky’.
I’d love to see 3.1 bring that power into the control panel.
Piet
# June 30, 2010 - 1:36 pm
For the life of it, I cannot get the manage_posts_custom_column to work. By now I have tried at least 10 different possibilities including yours, but all fail to show any results.
On my single post template get_the_term_list works as it should, but in the admin panel they just do not show.
Any insights in that?
Thanks!
Eric
# June 30, 2010 - 2:29 pm
There is a that plugin makes it a bit easier to create custom post types. It’s called “Easy Post Types” and you can get it at http://www.wpeasyposttypes.com. I highly recommend.
Richard Shepherd
# July 1, 2010 - 8:49 am
Thanks for the link, Eric.
It seems like a lot of people are finding CPT a bit hacky, and I agree. I think it’s a step in the right direction, and it promises to be a powerful feature going forward.
However, for the time being (like many things in WordPress) you have to roll up your sleeves and get stuck in with functions.php.
Aaron Davidson
# July 8, 2010 - 11:58 pm
Solid tutorial, but after seeing how much work would be involved, looked hard at alternatives.
Tried all the custom post type plugins (at this point in time) – some have definite potential.
But decided that although far from ideal, Magic Fields http://magicfields.org/ along with Custom Post Template http://wordpress.org/extend/plugins/custom-post-template/ will probably get you closer, quicker. to what you thought Custom Post Types would deliver than what it currently delivers.
Faye
# June 30, 2010 - 2:49 pm
Have been following your tutorial here to get my head round custom post types and it’s excellent – the only problem I seem to have is that the custom meta data won’t save, at least not other than the first declared type (in this case year_completed which saves no problem). Any ideas? Thanks!
Richard Shepherd
# July 1, 2010 - 8:49 am
See below!
wayne
# June 30, 2010 - 2:59 pm
thanks for the run through, i’ve found the other tutorials very specific so this will be very helpful!
i agree that wp3 only add the fundamental support of custom post types, it needs to be supported throughout wordpress.
for example, the wp_dropdown_pages() function cannot access different post types, only wp_list_children can… so you’re stuck with using custom taxonomies for now
Vas
# June 30, 2010 - 3:23 pm
Very nice post/tutorial here, thanks a lot! But if i’m a newbie i can’t really understand what i have to do after a have created a new single.php. How do i show the content from my new custom post on the site page? Thanks again.
Richard Shepherd
# July 1, 2010 - 8:52 am
Hey Vas,
Let’s say your custom post type is called ‘portfolio’, as it is here in the tutorial.
1. Copy the single.php file in your theme directory.
2. Rename it single-portfolio.php.
3. Et voila! In this new file you can call on the custom meta data with something like this:
echo get_post_meta($post->ID, ‘designers’, true);
Hope that helps!
Jason Carlin
# August 3, 2010 - 3:12 am
I’m not sure, but I think you might need to use get_the_ID() instead of $post->ID when you’re working inside the single-portfolio.php file.
Amazing tutorial, btw. This got me further faster than anything else I was able to find online!
Gabe Rosser
# August 19, 2010 - 5:35 pm
Having a little trouble with this. Using ID, ‘featured_vid’, true); ?> to get ‘featured_vid’ to display & it’s not working. I’ve followed the instructions & have everything on the backend, just need to figure how to display. I am a little new to this also :) Any help would be appreciated. Great post!!!
Jordan Koschei
# June 30, 2010 - 3:56 pm
I’ve already been using custom post types, but not to their full usefulness — thanks to this article, I’m able to see the full extent of their adaptability. Thank you!
Jeff Bridgforth
# June 30, 2010 - 7:03 pm
Thanks for the article. I like how you walked through the project and explained what you were doing and how certain code worked. I wish you had done more on the template section so I could have learned how to display all the information from the custom post type you created. That would have been helpful for me to see so that I understood the whole scope of the project you were doing.
Richard Shepherd
# July 1, 2010 - 8:56 am
Hi Jeff. Have a quick look at my comment above in reply to Vas. Hopefully that’ll point you in the right direction.
Jeff Bridgforth
# July 1, 2010 - 5:34 pm
Thanks Richard for pointing that out. It is very helpful. Thanks again for writing the article. I think I am going to use it as the basis for my portfolio section my site.
Jeffrey Fisher
# July 2, 2010 - 3:46 am
Hi Richard,
Your tutorial is great! Thanks so much. However, I’ve created single-portfolio.php and really have no idea where to go from here. How do I access this new page. My home page posts defaults to index.php, but how do I go about setting up this new Portfolio page on which I will add these new custom posts? I read all your other replies, but I must be missing something. I am quite new at the WordPress game. Can you help or could you recommend a page in the codex? I’m not sure what terms I would search.
Jeff
Shaun Bent
# June 30, 2010 - 7:30 pm
This is a great article. It reads really well and is very clear to understand.
As with many of the others who have commented I have being using Custom Post Types, but I have found it a very difficult processes to get my head around do the lack of documentation on them. This article really beings all that information together in one place, and has shown me a few places I could do things better!
Thanks You!
Cedric Neveu
# June 30, 2010 - 8:05 pm
Great article! It will be very useful for my future projects with WP 3.0.
David Calhoun
# July 1, 2010 - 3:36 am
Great post! Thanks for the detailed walk through. I am having one issue though. For some reason my metas are not saving. The “year completed” will save correctly, but the other will not. Any ideas?
Faye
# July 1, 2010 - 8:36 am
Exactly the same issue I’m having. Would love a fix!
Richard Shepherd
# July 1, 2010 - 8:45 am
Hi David & Faye!
I’ve checked this today and can’t replicate you’re problem. I’m using a fresh install of WordPress 3 with the TwentyTen theme.
I’ve uploaded a copy of functions.php to http://www.richardshepherd.com/php/functions.zip for you both, and this file is working fine for me. Please let me know how you go with it :)
Rich
Faye
# July 1, 2010 - 9:06 am
Thanks Richard – have just replaced my functions.php in Twenty Ten with yours, but still having the same issue with the meta not saving. My install is an upgrade from 2.9.2 rather than a fresh install of 3.0, but that’s the only difference…
Richard Shepherd
# July 1, 2010 - 9:40 am
Okay guys, I think you just need to update the textarea code so that they have a name. For example, name=”designers” for the designers textarea etc. That should do it :)
Faye
# July 1, 2010 - 9:57 am
That’s cracked it! Thanks Richard, that’s brilliant!
David Calhoun
# July 1, 2010 - 11:59 am
That worked for me as well. Thanks a lot, Richard!
Justin
# July 8, 2010 - 9:54 am
I was having the same problem as others described above with some meta-data not saving (a few minutes after I would save a custom post type along with meta data, the meta data would disappear from the WP-admin screen…), and I solved it by checking whether or not WordPress is autosaving. If anyone has the same problem, try changing the save_details() function to:
function save_details(){
global $post;
$post_id = $post->ID;
// to prevent metadata or custom fields from disappearing…
if ( defined(‘DOING_AUTOSAVE’) && DOING_AUTOSAVE )
return $post_id;
update_post_meta($post_id, “year_completed”, $_POST["year_completed"]);
update_post_meta($post_id, “designers”, $_POST["designers"]);
update_post_meta($post_id, “developers”, $_POST["developers"]);
update_post_meta($post_id, “producers”, $_POST["producers"]);
}
More info here:
http://stackoverflow.com/questions/2539951/wordpress-add-meta-box-weirdness
Richard Shepherd
# July 29, 2010 - 12:21 pm
Thanks Justin – well spotted!
Yep, it’s a ‘feature’/'bug’ that you can read more about at http://core.trac.wordpress.org/ticket/10744 and http://codex.wordpress.org/Function_Reference/add_meta_box#Example
I recommend your solution – checking to see if it’s an autosave or not.
sandrups
# July 1, 2010 - 3:50 am
ok, tomorrow I experience
Jonathan
# July 1, 2010 - 5:16 am
One of, if not, THE, best WP3CP tutorials out there. Thank you for putting this together so clearly.
Jonathan
Rembrand
# July 1, 2010 - 7:45 am
That’s a very helpful walk-through. I’m currently exploring some options for my portfolio. I don’t know if this has been brought up anywhere else, but is it possible to group custom post types together like you would categories and subcategories (extended into pages and subpages)?
E.g I have a main category Portfolio with subcategories Web, Graphic and Illustration. This gives me a full archive of everything as well as 3 more detailed archives.
Don’t know if I can replicate that hierarchy with custom post types though.
Any thoughts or suggestions I’d greatly appreciate!
Richard Shepherd
# July 1, 2010 - 9:00 am
Hi Rembrand. Sounds to me like you might need to look at custom taxonomies (basically custom categories you can create and manage) as you can arrange these in a hierarchy. You can then create pretty URLs like /portfolio/web/ and /portfolio/graphic-design/.
Justin Tadlock has written about this in some detail, and it’s a great article. Check out http://justintadlock.com/archives/2009/05/06/custom-taxonomies-in-wordpress-28 for more details.
Hope that helps!
Rembrand
# July 1, 2010 - 9:37 pm
Great! I read bits and pieces about taxonomy earlier but that possibility didn’t seem to register with me for some reason :P
I’ll check that out, thanks!
Chris
# July 22, 2010 - 7:30 pm
Correct me if I am wrong… but are you saying that you cannot use hierarchical for the Skills?
Meaning you cannot use custom post types that make the url /portfolio/css/ ?
Mike
# July 1, 2010 - 8:29 am
This is a long tutorial. Although I haven’t gone through the whole thing yet but thanks! A new article for beginners like us to learn about WordPress 3.0 :)
David Calhoun
# July 1, 2010 - 12:32 pm
Richard, is there a way to add a drop down menu to the view of the Portfolio posts so that I can filter the posts by these custom taxonomies? Similar to how normal posts can be filtered by category.
Johannes
# July 1, 2010 - 12:58 pm
Thanks so much for this tutorial! I’ve gone through several custom post type tutorials but haven’t really gotten any of them working or haven’t understood them but this one is super easy to follow and does actually work perfectly.
Exactly what I needed for a new client project I’m just starting that will be built in WP 3.0.
Jeff Bridgforth
# July 1, 2010 - 5:37 pm
I agree with Johannes. This is one of the clearest tutorials I have seen on implementing Custom Post Types.
Jason Gross
# July 1, 2010 - 3:57 pm
Fantastic post Richard! The timing couldn’t be any better as I have been working with custom post types to build my new portfolio for the last few days. The tip about the single.php page is just what I was looking for too!
I have noticed over the last few days that the featured image is a little frustrating to get working right as a thumbnail. In my case I want my thumbnail to be 240×110 but WordPress would much rather it be 150×110 regardless of whether I have the thumbnail size or original size option selected.
The only way I have found to get it to work is to edit the image in WP and force the ratio to 24:11 and then force WP to let me save those image changes on the thumbnail by rotating the image once and then back, pretty weird stuff.
Erik Teichmann
# July 7, 2010 - 1:06 pm
Jason–
To use image sizes other than the built-ins, you need to first define them in your functions.php
Use code like this:
‘home-post-thumbnail’ is a nickname for the size of the image. It can be anything you want.
420 is the width, 280 is the height. The last boolean value lets WordPress know if you’d like to “hard-crop” the image. If it is set to true, the image will be cropped to exactly the size you’ve set, similar to how WP’s built in 150×150 thumbnails work.
To use the image in your theme, use something like this:
Hope this helps!
Erik Teichmann
# July 7, 2010 - 1:08 pm
Sorry, code got stripped.
Define image size:
add_image_size( 'home-post-thumbnail', 420, 280, true ); // Homepage featured article thumbnail sizeDisplay image:
the_post_thumbnail('home-post-thumbnail');Jeff Bridgforth
# July 1, 2010 - 5:42 pm
Does anyone know if you can do other custom meta field types besides single line or text area boxes? Can you do drop-downs, checkboxes, or even WSIWYG boxes like the main content editor? I have seen it done in a plugin but that plugin has not been updated in WP 3.0 and no longer works.
Thanks.
Jacob
# July 1, 2010 - 7:59 pm
It seems that in “Step 3″ the text boxes are just HTML form fields. You should be able to use HTML (and javascript if needed) to create any sort of input widget you need.
I could be wrong though.
Trey Brister
# July 1, 2010 - 6:13 pm
I tried to make your tutorial into a plugin.
I get no taxonomies in the sidebar and an error in place of the two meta boxes
Warning: call_user_func() [function.call-user-func]: First argument is expected to be a valid callback in /home3/conoverl/public_html/johnsoncountybar/wp-admin/includes/template.php on line 2868
Warning: call_user_func() [function.call-user-func]: First argument is expected to be a valid callback in /home3/conoverl/public_html/johnsoncountybar/wp-admin/includes/template.php on line 2868
Here is the pastebin of the two files the main plugin file only includes the class and nothing more.
http://pastebin.com/CniHcGYz – Class File with your code
http://pastebin.com/VNYwKfx3 – Plugin wrapper
2imagine
# July 1, 2010 - 7:51 pm
I have gone through numerous (no, a massive lot) of articles about Custom Post Types and Custom Taxonomies in WordPress 3.0 and this one is by far the best, most applicable, most correct application of said objects, most understandable, most enjoyable, most logical of all of them!
Thank you very much Richard!
However, it still saddens me to see that SO many people still do not see Custom Post Types for what they really are. Trapped in the mindset of a blogging environment driven by plugins and “premier” themes.
The work of people like Richard will ease that pain.
Jacob
# July 1, 2010 - 8:10 pm
It seems that one of the major problems WordPress has with custom post types is that the custom content is too closely coupled to the display of it in the theme. You create a custom type like product (in an e-commerce site) and in order to display the price, you have to modify your theme. That makes it hard to switch themes, or to package up your e-commerce content types as a plugin to share with other people.
Dallas Moore
# July 1, 2010 - 8:48 pm
Richard!
First of all, thanks so much for the amazing tutorial! I now consider myself a regular follower of this blog!
As for it working, I’m doing great until I get to Step #4! For the second line what should I replace ‘manage_edit-portfolio_columns’ with? I’ve tried several things, and my new columns aren’t showing up. Help, Please!
Dallas
Delwin Holeman
# August 24, 2010 - 5:15 am
This has me stumped as well. Did you ever have any luck figuring this out? I’ve tried all sorts of things and nothing seems to work.
Markus
# July 1, 2010 - 9:14 pm
great tutorial :)
@Jeff Bridgforth http://www.deluxeblogtips.com/2010/04/how-to-create-meta-box-wordpress-post.html
paul
# July 2, 2010 - 1:25 am
I’d recommend reading this article before deciding to use custom post types in your next project:
http://ottopress.com/2010/wordpress-3-0-and-custom-post-types/
There’s a better solution if you just need extra fields, you can create custom meta boxes which will be less “scary” to the client rather than creating a custom post type.
Aaron Davidson
# July 9, 2010 - 12:07 am
Touche!
And keep posts as what WordPress does best.
Jason Gross
# July 2, 2010 - 6:58 pm
I can not for the life of me get my permalinks to work for my custom posts :( The only way to get everything working is to use the default permalink format, otherwise my custom post types display a 404 page.
I have tried reloading my permalinks a bunch and the flush_rewrite_rules(); line doesn’t appear to have made any difference.
Anyone having similar problems or have I done something wrong somewhere along the line here?
Jasper
# August 23, 2010 - 11:25 am
I have the same 404 issues. And I tried the tip mentioned here on the issue. I am wiring about it here. My .htaccess seems ok and I can create custom post types and taxonomies, but when I click view portfolio item I get this dreadful 404..
Jason
# July 3, 2010 - 7:48 am
Awesome!
One problem though, my “.html” permalink setting doesn’t apply to custom-post-type posts. (But does to regular posts.)
Would you know if there is a way to fix this (add .html) via functons.php?
Scott Elkin
# July 4, 2010 - 9:50 pm
How do you view all posts by the custom post type you define?
If my slug is ‘portfolio’, this will work:
/portfolio/my-first-post/
But this will not show all my portfolio posts and just 404′s:
/portfolio/
What do I need to do to make this work?
My permalink settings are just to /%postname%/
Erik Teichmann
# July 7, 2010 - 1:13 pm
+1
I’ve been trying to figure out the same thing. The workaround I’ve come up with so far is to use a page with an identical slug, then build a page template on that page that displays the custom content. Use code like this on that template:
$loop = new WP_Query( array( 'post_type' => 'staff_directory' ) );while ( $loop->have_posts() ) : $loop->the_post();
This isn’t pretty, but it works. The problem is, it could easily be borked by a client who wants to edit that content.
Jason
# July 15, 2010 - 8:06 pm
I just use the CMS Press plugin. It automatically sets up templating for this. Just create index-portfolio.php, single-portfolio.php, etc. The plugin even lets you set up pretty permalinks ending in .html, if you use this like I do. And this I haven’t found in any other post type plugins.
The one and only major thing CMS Press is missing right now, IMO, is tag and category support. Although he does have taxonomy support. Tags & categories are on his to-do list he says. I hope it comes out SOON!
Simon
# August 1, 2010 - 12:18 am
I’m trying to figure out the same thing. I’ve got all the the custom post type functionality working except for this. i figured using something like category-postype.php would work, but it doesn’t.
I can see that Erik’s solution will work, but unfortunately not if you are planning to release a theme. I can’t seem to find the solution to this anywhere, so I’m starting to wonder if it’s possible without a hack.
Joris
# July 5, 2010 - 10:51 am
Thanks for the clear tutorial. Just like some people already pointed out in the comments, I as well think this is an overly complicated and unattractive way to build custom post types. I’ve been using Expression Engine for a couple of years and they really make it dead-easy to create any type of content for me or my clients. Until WordPress has an easy and built-in way to create custom content types, I’m sticking to EE for anything that’s not a blog.
Cippo
# July 7, 2010 - 1:18 pm
Hi Richard, thank you for your tutorial :)
I have one question. What if I want to display the portfolio loop in a page?
How can I do that?
Cippo
# July 7, 2010 - 3:21 pm
I managed to solve it in a way. I’m still working on it but here’s what I did: I renamed a page to page-portfolio.php
and inside it, I placed the following code:
Cippo
# July 7, 2010 - 3:22 pm
query_posts(‘post_type=portfolio’);
//The Loop
if ( have_posts() ) : while ( have_posts() ) : the_post();
the_content();
endwhile;
endif;
//Reset Query
wp_reset_query();
Scott Elkin
# July 7, 2010 - 6:02 pm
Correct, that is exactly what I did – it just felt like a hack.
Jaap
# July 8, 2010 - 1:27 am
Hi,
This works very well. When I try to create another custom post types with new custom fields my page turns blank. Could you please show how to put 2 custom post types into the functions.php file?
Kind regards,
J.
Cippo
# July 8, 2010 - 10:20 am
One more thing.
If I use this:
register_taxonomy(“skills”, array(“post”), array(“hierarchical” => true, “label” => “Skills”, “singular_label” => “Skill”, “rewrite” => true, “query_var”=>true, “rewrite”=>true));
It shows me the skills in page using the echo get_the_term_list($post->ID, ‘skills’, ‘Skills: ‘, ‘, ‘, ”)
but if I use register_taxonomy(“skills”, array(“portfolio”), array(“hierarchical” => true, “label” => “Skills”, “singular_label” => “Skill”, “rewrite” => true, “query_var”=>true, “rewrite”=>true));
using the same get_the_term_list doesn’t show anything while the get_tag_cloud works.
Also, your suggestion echo get_post_meta(the_ID, ‘designers’, true); doesn’t work.
Any suggestions, please?
Cippo
# July 8, 2010 - 1:42 pm
Ok, managed to make it work.
use this:
echo get_the_term_list($post->ID, ‘Skills’, ”, ‘, ‘,”);
Rich Senior
# July 20, 2010 - 11:44 am
Regarding: “Also, your suggestion echo get_post_meta(the_ID, ‘designers’, true); doesn’t work.”
I found that too. I copied and pasted it from Richard’s comment using my text editor (Coda). However, when I looked at the single.php from within the WordPress appearance editor the single quotes around designers were showing as errors/question marks. Deleted the single quotes and replaced them and all is now hunky dory.
Cippo
# July 8, 2010 - 8:11 pm
Thank you very much for your article :)
Here’s what I did with your help: http://cippodesign.com/cippo-design-portfolio
Cheers
Christoph Mandl
# July 9, 2010 - 1:22 pm
Thanks for the tutorial! The custom data fields i added are created in the database for every page that is saved, even if it’s not the custom post type. Is that normal behavier?
Kim
# July 9, 2010 - 1:24 pm
Nice tutorial.
I’m currently working on a project and I might try getting it done with custom posts, but I’m not sure that’s the wright way to go. So I was wondering if anyone could give me a tip.
The project is a survey with lost of different types of questions (open answers, multiple choices,…) and each question belongs to a category. On the frontside, the users must fill in the questions and get a indication afterwords. So the answers needs to be saved also, to be visualized in a chart.
Building a custom type called ‘questions’ with hierarchy for the categories isn’t the problemen. I want to add a metabox with the ability to grow dynamically (for the answers), something like the custom fields-metabox where you can add multiple custom fields without reloading the page.
Can someone point me to a tutorial to build a ‘custom fields’-like metabox?
Or should I build a plugin for the whole survey app, knowing that the score also needs to be saved?
Thanks in advance for your input.
And thanks for the great tutorials.
iamronen
# July 10, 2010 - 5:04 pm
Hello Richard,
Thank you for this great guide.
I created a full and working custom post-type application – and in doing so I encountered a problem with the save_details() function (unless I missed something). I think that the function needs to be qualified for the custom post type – so that empty fields are not creating for other post-types (this action is not post-type specific). I added an if statement and that solved the problem:
if ( get_post_type( $post ) == ‘portfolio’ ) {
// update meta data
}
My application required automated title generation – and that messed up other posts – which is what led me to this solution.
More on my application and tips:
http://www.odharma.com/2010/07/creating-a-teachers-directory-with-wordpress-3-0/
Again – thank you for the wonderful guidance.
All Things Good
Ronen
Christoph Mandl
# July 14, 2010 - 3:15 pm
Thank you, that solved my issue posted above….
Chad
# July 12, 2010 - 3:22 pm
Hi,
First of all, great article, very detailed indeed!
However, not sure if this is a bug or an error on my part?
Theres a few “headers already sent” errors that appear due to the html being written out within the functions.php file?
For example, when uploading an image!
Any help would be appreciated :)
Kind regards,
Chad
Chad
# July 13, 2010 - 2:15 pm
Nevermind,
Had some white space after the closing php tag ;)
Kind regards,
Chad
Richard Frost
# July 13, 2010 - 10:18 am
Really great tutorial, thanks for putting it together.
I’m struggling on the last bit, which pulls together the custom post information into columns. On loading the custom section in the admin screen the columns display, but only show empty spaces. If I then, go into quick edit mode for a post, and save, the information will then show in the columns for that post alone.
Any ideas why it might do that?
Richard Frost
# July 13, 2010 - 10:23 am
Small update. I turned hierarchy off in the options for the custom post type and the information displays in the columns. Is there some way to enable the hierarchy mode and allow the information to be displayed in columns?
Lincoln
# September 2, 2010 - 8:04 pm
You saved my life ->> This is key.
Richard Frost
# July 13, 2010 - 10:41 am
Fixed!
For hierarchy to work, it seems ‘manage_pages_custom_column’ is needed instead of ‘manage_posts_custom_column’. http://core.trac.wordpress.org/ticket/14004#comment:3
Chris
# July 22, 2010 - 7:22 pm
Perfect! Exactly what I was looking for… thanks for this!
David
# July 27, 2010 - 6:09 am
OMG a simple change:
‘manage_pages_custom_column’ is needed instead of ‘manage_posts_custom_column’.
I was trying to work this out for days!
Thank you
Thank you
James Tryon
# July 29, 2010 - 5:26 pm
Yep that fixed it for me too.
Great Review.
Jenny
# July 31, 2010 - 1:00 pm
I was about to ask the same question – thanks for posting the fix :)
Sean
# July 13, 2010 - 6:48 pm
in your step 4, is it possible to order the list by ‘year completed’ ?
Dallas Moore
# July 13, 2010 - 8:30 pm
How would I do things I would normally do with categories? Is there a tag similar to wp_list_categories, or the_category that I could use. Especially the last, so that I can include the category as part of the meta information at the bottom of the post.
Bexxie
# July 14, 2010 - 5:56 pm
Thanks Richard for the fantastic tutorial! I’ve read quite of a few on custom post types and this one has definitely been the most helpful. Also, thanks for posting a link to the full functions.php file. I was having a few issues but after looking at that I now have a fully functioning music discography with label, artists, catalogue number and release date. I just have to add images now.
Thanks again!
Charlotte Coleman
# July 15, 2010 - 2:30 pm
Thanks for a really insightful post. I’ve been wondering how to alter the layout of the custom post type admin pages and the list of post types and there don’t seem to be many tutorials out there. It’s much better to write the code in the functions file than rely on someone else’s plugin too. Great advice – thanks again!
Kyle
# July 15, 2010 - 8:45 pm
Beautiful!
I’ve read a slew of posts and scoured the codex for information on custom post types as I need to write about them in an upcoming publication. This has been the /best/ resource as of yet!
I need clarification on one thing – an item I can’t find an answer for anywhere. In this what does the “[0]” do?
$year_completed = $custom["year_completed"][0];
James Tryon
# July 29, 2010 - 5:21 pm
From what I understand the [0] stand for the first instance of that element. If you had 2 and you wanted to target the 2nd one you would use [1]. The counter starts at “0″.
-James Tryon
todd valentine
# July 16, 2010 - 11:53 pm
Does anyone know why the meta box values I’ve created for my custom post types are showing up as custom field values in my ‘edit page’ admin area. They aren’t there when I add the page, but after I have published the page, they show up when I go to edit the page. I substituted the $page variable in the add_meta_box function with my custom post type, so not sure why their showing up in my pages? Has anyone else experienced this? I think it could be confusing for clients.
Jenny
# July 31, 2010 - 1:07 pm
I have the exact same problem, and so far no fix for it. Deleting them won’t help, after saving they’re back. I agree, it’s very confusing for clients.
ram
# July 18, 2010 - 3:54 am
Thanks for the great tutorial.
I would like to create a portfolio in which I need child pages like “webdesign”, “logo design” and “SEO” etc. How can we achieve this target? can we do it with custom post type or taxnomies? any body can point me to tutorial?
Kevin Cannon
# July 19, 2010 - 8:54 pm
I have the same problem as Jaap, the page turns blank as soon as I put your code it the admin presents a completely blank page.
I’ve reinstalled WordPress from scratch and can’t find the problem. I’ve tried different code for custom post types as well as editing functions.php in different editors. I’m running wordpress on my local machine under a MAMP setup.
Have you any ideas what it might be?
Thanks.
Jenny
# July 20, 2010 - 10:02 pm
After reading a dozen or so tutorials on how to create custom post types I FINALLY got it and it’s working – amazing stuff!
Thanks a lot!!!
Kevin Cannon
# July 24, 2010 - 5:49 pm
Solved my problem. I was editing the main wordpress functions.php rather than the one for the current theme.
Alice
# July 28, 2010 - 2:51 am
I’m having the autosave issues. I tried the code provided by Justin above, but no luck. The autosave doesn’t save my custom fields…
Richard Shepherd
# July 29, 2010 - 12:24 pm
Hey Alice – you might find your solution at http://codex.wordpress.org/Function_Reference/add_meta_box#Example
Hope that helps!
Alice
# August 3, 2010 - 12:26 am
Thanks, Richard.
I tried it, but encountered other issues. I’m not familiar with the whole nonce thing. I posted my code and issues here: http://wordpress.org/support/topic/problems-with-autosave-and-custom-fields?replies=2
Louisa
# July 29, 2010 - 3:37 am
Hello!!!
Brilliant tutorial! I finally have a grasp on the whole custom post idea! Thank you!!!
Just one question…
How do I add multiple post types, say for example a design and a photograhy post type rather than just a portfolio one?
Thanks for any suggestion!
Louisa
Richard Shepherd
# July 29, 2010 - 12:26 pm
Hi Louisa,
Just rinse and repeat! You’ll need two register_post_type() ‘s, each with a different name and relevant arguments.
Another solution would be to create a couple of new taxonomies/categories, so within ‘portfolio’ you have ‘design’ and ‘photography’ – each of which can have child categories.
Louisa
# July 30, 2010 - 4:02 am
Thanks so much, Richard!
Works brilliantly!! But I’m going to have to ask how I can now add new “add_meta_box” to add different categories to the ‘design’ area ! Sorry to have to ask! Trying to also get a grasp on php too at the moment but everything I tried just ended up in a blank page! Sigh!
Sorry to have had to ask another question especially when your tutorial is so clear and easy to follow!!
Louisa
# July 30, 2010 - 7:15 am
Ignore my last question! I worked it out!!!
M
# July 31, 2010 - 4:06 pm
Great starting point to get into custom post types.
However, there are some potential issues that could be avoided easily, to do with naming conventions for functions, variables and also for the post types and taxonomy terms. Looks like most of them are mentioned in the comments in some way or form, but I thought I’d summarise it somewhat, having just gone through the whole thing for a site I’m building:
As a general rule, you should give your post type a name that is unique and also different to the labels you’re going to use on the site, like ‘mysite_portfolio’, in order to keep the code tidy and to avoid a bunch of issues. You can still have nice permalinks by replacing ‘mysite_portfolio’ in the rewrite option.
Similarly, taxonomies should get their own name. Something like:
register_taxonomy(“mysite_portf_skills”, array(“mysite_portfolio”), “label” => “Skills” (etc…)
I was being stupid when I first played around with this: I chose “Type” for one of my custom taxonomies, which was already used by the system (or by some plugin). Big mistake, better to avoid this from the start by giving it a unique name.
This also helps with finding out where you have to repeat a chosen name in the code, eg when it comes to tying a taxonomy or a meta box to a specific post type.
add_action(“admin_init”, “admin_init”);
Not such a great idea, either. The last bit can get its own name (with the same name repeated for the function that follows).
Otherwise people might get into trouble when they try to include several post types.
A different but related (permalink) issue is the following:
Suppose you want to display 50 portfolio items on your site under the name ‘Portfolio’ (naturally), with 10 items on 5 pages. Naming the WordPress page ‘Portfolio’ and the post type ‘portfolio’ is likely to get the pagination messed up.
Choose something different for the post type (or the post type rewrite slug) and the page on which you’re calling the list of items.
I’m no expert (please treat my points as hints or suggestions, nothing more), in fact I needed a tutorial like this to even get me started on custom post types – so full credits to Richard. I just wanted to share what I had found and how I solved it.
Cor van Noorloos
# August 3, 2010 - 9:08 pm
Hi Richard,
Thank you very much for this article.
As a new guy on custom post types I wondered why _x is placed in front of ‘name’ => _x(‘My Portfolio’… instead of __?
Devin
# August 4, 2010 - 2:27 pm
Nice walk through Richard!
I built a portfolio theme that is very similar (minus the metaboxes) and wanted to share a real life example of the code: http://wptheming.com/2010/07/portfolio-theme/
3 Roads Media
# August 10, 2010 - 9:19 pm
Great article Richard. There are a lot of tutorials on how to use custom post types, but I’ve found yours to be the most intuitive and complete. Thank you!
3 Roads Media
# August 11, 2010 - 8:37 pm
After following this tutorial, I couldn’t get a couple of things to work. The permalinks will not work with the register_post_type() and arrays outlined in a function; I simply removed this and permalinks worked fine.
Also, your save function didn’t work for me. I found another tutorial that does work.
Chad Kaufman
# August 19, 2010 - 3:58 pm
I am having problem with ‘hierarchical’ posts (note: NOT hierarchical taxonomy).
Everything is running fine, but when I make ‘hierarchical’ => true my admin screen columns disappear. The data remains saved, but they disappear from display. When I make ‘hierarchical’ => false again, they come back.
Any ideas?
Shane
# August 27, 2010 - 2:38 pm
Excellent tutorial for the most part!
But I find it to be incomplete in the sense of displaying the custom post types on the front end. Other than the lack of explanation there, it is a great tutorial.
Doug C.
# August 28, 2010 - 10:28 pm
Nice in-depth tutorial, but I’m no coder so it was mostly Greek to me. I need to create a way for my client to list items on one page, so someone suggested I make a template page and then make custom post types and custom fields. None of which I know how to do.
If it’s confusing for me then I know it won’t help my client. I might try that Easy Post Types plugin. It looks more usable than all the others. But again, the end result must produce something that my client can easily use.
TradiArt
# September 4, 2010 - 5:33 pm
Hello!
This is a very useful tutorial. Thanks for sharing.
Just in case it is possible… In my website I have a lot of custom post types, and I would like to filter them, in admin area, by custom taxonomy.
Will be nice to show a dropdown of the custom taxonomies assigned to portfolio projects and when selecting one option in dropdown, only see the portfolio projects assigned to that custom taxonomy.
I have searched to find a solution with no success… any idea if this can be done?
Thank you!!! :-)