Custom Post Types – Explain the Unexplained
Custom Post Types has been one of the most discussed topics when people talk about WordPress since version 3.0. Whether you are developing a website using WordPress as a CMS or you just have different content types rather than posts, pages or attachments, custom post types is the most complete way to go.
In order to add custom post types to your website or blog you can either use some plugins that have nice User Interfaces or you can just use the magic function behind those plugins:
While you can use both approaches without any problem, do you actually understand what all those inputs (in case you use plugins) and those parameters and arguments (in case you use the magic function) are all about? Let’s together dig deeper into the world of
register_post_type() and see if we can find anything interesting, shall we?
Our magic function currently needs two parameters:
<?php register_post_type( $post_type, $args ); ?>
$post_type is rather self-explained,
$args still has some of its arguments poorly documented or documented in a confusing way.
From Codex: “Whether post_type queries can be performed from the front end.”
What exactly does this description mean then?
A front-end action regarding the use of post_type can be understood as using such query var either in a requesting URL (for example
http://example.com/?post_type=movie) or in the
query_posts()2 function. It is unclear whether we can control just one action or both.
A quick test reveals that
query_posts() will not be affected at all and setting ‘publicly_queryable’ to false will only tell WordPress to ignore the post_type query var in WordPress’s internal query parsing. For example if ‘publicly_queryable’ is false, such requests like below are all greeted with a 404 error page:
example.com/?post_type=movie example.com/?movie=let-me-in example.com/movie/let-me-in/
It is therefore recommended that this argument should never be false unless the post type you are registering is not public.
From Codex: “False to prevent queries, or string value of the query var to use for this post type.”
In my opinion, this is the most confusingly and poorly documented argument. To make use of this you must also enable ‘publicly_queryable’. What this argument does is allow you to request your custom posts using this:
and if it is set to a string rather than true (for example ‘video-clips’), you can then do this:
Technically speaking, ‘query_var’ appends the built-in query_vars array with our custom post type’s query var so that WordPress recognizes it (WordPress will remove any query var not included in that array.)
Please also note that WordPress will not automatically redirect request using such query var to a nice permalink for you (it only adds a canonical link rel in your document’s header).
From Codex: “Rewrite permalinks with this format. False to prevent rewrite.”
This argument is rather easy to understand but please note that you can not use link tag e.g. %post_id% to construct the permalink structure. You can only specify a string that appears before your post name (default to the name of your post type) and nothing more.
You can have deeper permalink structure, for example ‘movie/blu-ray’ instead of ‘movie’, if you wish. As far as I know there’s no working plugin that lets you modify the entire permalink for custom post types, i.e. lets you specify an actual permalink structure (please correct me if I am wrong).
From Codex: “Whether to show the post type in the admin menu and where to show that menu. Note that show_ui must be true.”
What this argument allows you to do is not that clear at first glance. Is admin menu referring to the whole menu that contains Posts, Media, Links, Pages, etc. or just a particular menu?
When you set ‘show_ui’ to true and leave ‘show_in_menu’ with its default value (which is null) you will still see a nice top-level admin menu for your custom post type under Comments, and if you want to change such default position you can use ‘menu_position’. So, what do we need this argument for anyway?
If you pay attention to the word in in ‘show_in_menu’, you will realize that this argument lets you show the custom post type menu in another admin menu, in other words, it lets you make the custom post type menu become a sub-menu rather than a top-level one like above. For example if you set ‘show_in_menu’ to ‘users.php’, the custom post type menu will appear as Users’s sub-menu, similar to ‘Add New’ and ‘Your Profile’.
Please note that this argument is only available since WordPress 3.13 and you might find more information about it here: Better admin menu handling for post types in WordPress 3.1 if you are interested.
From Codex: “Whether post_type is available for selection in navigation menus.”
This explanation is clear and easy to understand: by setting this to true you will be able to add posts that have such post_type in the Navigation Menu (available since WordPress 3.0.04).
The problem is after setting ‘show_in_nav_menus’ to true you will not see your custom post types anywhere in the Menu Editor. The reason is custom post types (along with some other things) are actually hidden by default, and to make them show up you will have to access Screen Option5 and then choose to show your custom posts:
From Codex: “Enables post type archives. Will use string as archive slug. Will generate the proper rewrite rules if rewrite is enabled.”
Basically this argument allows you to set up archive pages for your custom post types (just like ‘category/a-category’). ‘has_archive’ can be either true or false and it also accepts a string as its value. If ‘has_archive’ is a string, for example ‘movie’, your custom post type’s archive page will have a permalink structure like this:
http://example.com/movie/; be careful not to have a normal page with the same slug, though.
Please keep in mind that ‘has_archive’ is only available since WordPress 3.1.
From Codex: “The default rewrite endpoint bitmasks.”
To tell the truth you might not need to change this argument at all so I only include it for completeness (the documentation is indeed confusing, even to developers).
‘epmask’ actually stands for endpoint mask. An endpoint is something that is added to the end of a permalink. For example, /feed/ or /trackback/ is an endpoint. The mask we are talking about will decide whether an endpoint should be added to the end of a particular type of permalink or not. If you take a look at
wp-includes/rewrite.php you can see a list of default epmasks just like below:
EP_NONE EP_PERMALINK EP_ATTACHMENT EP_DATE EP_YEAR EP_MONTH EP_DAY EP_ROOT EP_COMMENTS EP_SEARCH EP_CATEGORIES EP_TAGS EP_AUTHORS EP_PAGES EP_ALL
As you might have guessed, the ‘permalink_epmask’ argument allows us to specify which endpoints we want to add to our custom post type’s permalink. For example, if you set its value to
EP_PAGES & EP_CATEGORIES, all endpoints that can be added to pages and categories’ permalinks can now be added to your custom post type’s permalink.
The ‘permalink_epmask’ argument defaults to
EP_PERMALINK, i.e. the mask used for regular posts. This means the same endpoints added to posts will also get added to your new custom post type. If you do not want to add any endpoint at all, set this argument to
EP_NONE. If you want to add all endpoints instead, set it to
The Bottom Line
The custom post types feature has been around for some time, but its documentation really needs more attention, not from the core editors, but actually from everyone. Anyway, that’s all I have to say and I do believe that you now have better understanding of some arguments used in
register_post_type() – the magic function. As always, feedbacks, suggestions and questions are welcomed!
- http://codex.wordpress.org/index.php?title=Function_Ref ... _post_type [↩]
- http://codex.wordpress.org/Function_Reference/query_pos ... uery_posts [↩]
- http://codex.wordpress.org/Version_3.1 [↩]
- http://codex.wordpress.org/Version_3.0 [↩]
- http://codex.wordpress.org/Administration_Panels#Screen ... en_Options [↩]