Back to Top

Custom Post Types – Explain the Unexplained

Previous Post:

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: register_post_type()1.

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:

  1. <?php register_post_type( $post_type, $args ); ?>
<?php register_post_type( $post_type, $args ); ?>

and while $post_type is rather self-explained, $args still has some of its arguments poorly documented or documented in a confusing way.

arg: publicly_queryable

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 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:

It is therefore recommended that this argument should never be false unless the post type you are registering is not public.

arg: query_var

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).

arg: rewrite

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).

arg: show_in_menu

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.

arg: show_in_nav_menus

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:

Screen Options

Screen Options in Menu Editor

arg: has_archive

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:; 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.

arg: permalink_epmask

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:


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 EP_ALL.

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!


  1. ... _post_type []
  2. ... uery_posts []
  3. []
  4. []
  5. ... en_Options []
Elegant Themes - Designed with Modest Elegance
Print Article Trackback Trackback to this Article   Subscribe to Comments RSS Subscribe to Comments RSS

3 Opinions for Custom Post Types – Explain the Unexplained (1 Trackback)

  1. User's Gravatar
    Chad November 15, 2011 at 12:59 pm – Permalink

    Nice post, you are absolutely right about the documentation being lacking in terms of detail with regard to custom post types. Thanks for taking the time to clarify and elaborate on how to use these arguments, there is not a whole lot out there explaining in depth how to use custom post types or even set them up, and the last thing I would want to do is just install a plugin which probably wouldn’t be as useful or allow for complete control.

    Again, nice post.


  2. User's Gravatar
    Lakha Singh February 13, 2013 at 10:43 pm – Permalink

    Awesome Explanation Man!!
    Keep up this good work :)

  1. Create Fake Pages in WordPress - Better WordPress

    [...] sure you enable appropriate features for your post type, namely publicly_queryable and query_var2, so that our requests are happily accepted by [...]

Speak Up Your Mind!

An asterisk (*) indicates a required field and must be filled.

  • Web page and e-mail addresses turn into links automatically.
  • Wrap codes in: <code lang=""></code> or <pre lang="" extra="">
  • Lines and paragraphs break automatically.

Next Post: