Justin Tadlock

register_post_type() cheat sheet

Whenever I create new post types, I always use my own little cheat sheet to get started just to make sure I cover all the arguments (there’s tons of them!). I thought I’d share this with you. It’s commented like crazy so you can understand all the arguments.

I’ve also made this file available as a gist on GitHub.

Here’s the code:

<?php

/* Register custom post types on the 'init' hook. */
add_action( 'init', 'my_register_post_types' );

/**
 * Registers post types needed by the plugin.
 *
 * @since  0.1.0
 * @access public
 * @return void
 */
function my_register_post_types() {

	/* Set up the arguments for the post type. */
	$args = array(

		/**
		 * A short description of what your post type is. As far as I know, this isn't used anywhere
		 * in core WordPress.  However, themes may choose to display this on post type archives.
		 */
		'description'         => __( 'This is a description for my post type.', 'example-textdomain' ), // string

		/**
		 * Whether the post type should be used publicly via the admin or by front-end users.  This
		 * argument is sort of a catchall for many of the following arguments.  I would focus more
		 * on adjusting them to your liking than this argument.
		 */
		'public'              => true, // bool (default is FALSE)

		/**
		 * Whether queries can be performed on the front end as part of parse_request().
		 */
		'publicly_queryable'  => true, // bool (defaults to 'public').

		/**
		 * Whether to exclude posts with this post type from front end search results.
		 */
		'exclude_from_search' => false, // bool (defaults to 'public')

		/**
		 * Whether individual post type items are available for selection in navigation menus.
		 */
		'show_in_nav_menus'   => false, // bool (defaults to 'public')

		/**
		 * Whether to generate a default UI for managing this post type in the admin. You'll have
		 * more control over what's shown in the admin with the other arguments.  To build your
		 * own UI, set this to FALSE.
		 */
		'show_ui'             => true, // bool (defaults to 'public')

		/**
		 * Whether to show post type in the admin menu. 'show_ui' must be true for this to work.
		 */
		'show_in_menu'        => true, // bool (defaults to 'show_ui')

		/**
		 * Whether to make this post type available in the WordPress admin bar. The admin bar adds
		 * a link to add a new post type item.
		 */
		'show_in_admin_bar'   => true, // bool (defaults to 'show_in_menu')

		/**
		 * The position in the menu order the post type should appear. 'show_in_menu' must be true
		 * for this to work.
		 */
		'menu_position'       => null, // int (defaults to 25 - below comments)

		/**
		 * The URI to the icon to use for the admin menu item. There is no header icon argument, so
		 * you'll need to use CSS to add one.
		 */
		'menu_icon'           => null, // string (defaults to use the post icon)

		/**
		 * Whether the posts of this post type can be exported via the WordPress import/export plugin
		 * or a similar plugin.
		 */
		'can_export'          => true, // bool (defaults to TRUE)

		/**
		 * Whether to delete posts of this type when deleting a user who has written posts.
		 */
		'delete_with_user'    => false, // bool (defaults to TRUE if the post type supports 'author')

		/**
		 * Whether this post type should allow hierarchical (parent/child/grandchild/etc.) posts.
		 */
		'hierarchical'        => false, // bool (defaults to FALSE)

		/**
		 * Whether the post type has an index/archive/root page like the "page for posts" for regular
		 * posts. If set to TRUE, the post type name will be used for the archive slug.  You can also
		 * set this to a string to control the exact name of the archive slug.
		 */
		'has_archive'         => 'example', // bool|string (defaults to FALSE)

		/**
		 * Sets the query_var key for this post type. If set to TRUE, the post type name will be used.
		 * You can also set this to a custom string to control the exact key.
		 */
		'query_var'           => 'example', // bool|string (defaults to TRUE - post type name)

		/**
		 * A string used to build the edit, delete, and read capabilities for posts of this type. You
		 * can use a string or an array (for singular and plural forms).  The array is useful if the
		 * plural form can't be made by simply adding an 's' to the end of the word.  For example,
		 * array( 'box', 'boxes' ).
		 */
		'capability_type'     => 'example', // string|array (defaults to 'post')

		/**
		 * Whether WordPress should map the meta capabilities (edit_post, read_post, delete_post) for
		 * you.  If set to FALSE, you'll need to roll your own handling of this by filtering the
		 * 'map_meta_cap' hook.
		 */
		'map_meta_cap'        => true, // bool (defaults to FALSE)

		/**
		 * Provides more precise control over the capabilities than the defaults.  By default, WordPress
		 * will use the 'capability_type' argument to build these capabilities.  More often than not,
		 * this results in many extra capabilities that you probably don't need.  The following is how
		 * I set up capabilities for many post types, which only uses three basic capabilities you need
		 * to assign to roles: 'manage_examples', 'edit_examples', 'create_examples'.  Each post type
		 * is unique though, so you'll want to adjust it to fit your needs.
		 */
		'capabilities' => array(

			// meta caps (don't assign these to roles)
			'edit_post'              => 'edit_example',
			'read_post'              => 'read_example',
			'delete_post'            => 'delete_example',

			// primitive/meta caps
			'create_posts'           => 'create_examples',

			// primitive caps used outside of map_meta_cap()
			'edit_posts'             => 'edit_examples',
			'edit_others_posts'      => 'manage_examples',
			'publish_posts'          => 'manage_examples',
			'read_private_posts'     => 'read',

			// primitive caps used inside of map_meta_cap()
			'read'                   => 'read',
			'delete_posts'           => 'manage_examples',
			'delete_private_posts'   => 'manage_examples',
			'delete_published_posts' => 'manage_examples',
			'delete_others_posts'    => 'manage_examples',
			'edit_private_posts'     => 'edit_examples',
			'edit_published_posts'   => 'edit_examples'
		),

		/**
		 * How the URL structure should be handled with this post type.  You can set this to an
		 * array of specific arguments or true|false.  If set to FALSE, it will prevent rewrite
		 * rules from being created.
		 */
		'rewrite' => array(

			/* The slug to use for individual posts of this type. */
			'slug'       => 'example', // string (defaults to the post type name)

			/* Whether to show the $wp_rewrite->front slug in the permalink. */
			'with_front' => false, // bool (defaults to TRUE)

			/* Whether to allow single post pagination via the <!--nextpage--> quicktag. */
			'pages'      => true, // bool (defaults to TRUE)

			/* Whether to create feeds for this post type. */
			'feeds'      => true, // bool (defaults to the 'has_archive' argument)

			/* Assign an endpoint mask to this permalink. */
			'ep_mask'    => EP_PERMALINK, // const (defaults to EP_PERMALINK)
		),

		/**
		 * What WordPress features the post type supports.  Many arguments are strictly useful on
		 * the edit post screen in the admin.  However, this will help other themes and plugins
		 * decide what to do in certain situations.  You can pass an array of specific features or
		 * set it to FALSE to prevent any features from being added.  You can use
		 * add_post_type_support() to add features or remove_post_type_support() to remove features
		 * later.  The default features are 'title' and 'editor'.
		 */
		'supports' => array(

			/* Post titles ($post->post_title). */
			'title',

			/* Post content ($post->post_content). */
			'editor',

			/* Post excerpt ($post->post_excerpt). */
			'excerpt',

			/* Post author ($post->post_author). */
			'author',

			/* Featured images (the user's theme must support 'post-thumbnails'). */
			'thumbnail',

			/* Displays comments meta box.  If set, comments (any type) are allowed for the post. */
			'comments',

			/* Displays meta box to send trackbacks from the edit post screen. */
			'trackbacks',

			/* Displays the Custom Fields meta box. Post meta is supported regardless. */
			'custom-fields',

			/* Displays the Revisions meta box. If set, stores post revisions in the database. */
			'revisions',

			/* Displays the Attributes meta box with a parent selector and menu_order input box. */
			'page-attributes',

			/* Displays the Format meta box and allows post formats to be used with the posts. */
			'post-formats',
		),

		/**
		 * Labels used when displaying the posts in the admin and sometimes on the front end.  These
		 * labels do not cover post updated, error, and related messages.  You'll need to filter the
		 * 'post_updated_messages' hook to customize those.
		 */
		'labels' => array(
			'name'               => __( 'Examples',                   'example-textdomain' ),
			'singular_name'      => __( 'Example',                    'example-textdomain' ),
			'menu_name'          => __( 'Examples',                   'example-textdomain' ),
			'name_admin_bar'     => __( 'Examples',                   'example-textdomain' ),
			'add_new'            => __( 'Add New',                    'example-textdomain' ),
			'add_new_item'       => __( 'Add New Example',            'example-textdomain' ),
			'edit_item'          => __( 'Edit Example',               'example-textdomain' ),
			'new_item'           => __( 'New Example',                'example-textdomain' ),
			'view_item'          => __( 'View Example',               'example-textdomain' ),
			'search_items'       => __( 'Search Examples',            'example-textdomain' ),
			'not_found'          => __( 'No examples found',          'example-textdomain' ),
			'not_found_in_trash' => __( 'No examples found in trash', 'example-textdomain' ),
			'all_items'          => __( 'All Examples',               'example-textdomain' ),

			/* Labels for hierarchical post types only. */
			'parent_item'        => __( 'Parent Example',             'example-textdomain' ),
			'parent_item_colon'  => __( 'Parent Example:',            'example-textdomain' ),

			/* Custom archive label.  Must filter 'post_type_archive_title' to use. */
			'archive_title'      => __( 'Examples',                   'example-textdomain' ),
		)
	);

	/* Register the post type. */
	register_post_type(
		'example', // Post type name. Max of 20 characters. Uppercase and spaces not allowed.
		$args      // Arguments for post type.
	);
}

?>