Site icon WP Smith

Registering Custom Post Types

Understanding WordPress Custom Post Types

Custom Post Types Location

First, where does this code reside? As with almost any addition, it will reside in your functions.php file or in an external php that functions.php calls through a require_once (e.g., require_once( TEMPLATE.'/lib/custom_post_type.php' );). Second, registering the custom post type needs to happen in the init hook.

Custom Post Types Namespaces

Naming of the custom post type is critical. Be sure to use a short namespace, which identifies the plugin, theme, or website (in this case, website) that implements the custom post type. Namespaces is the prefix that appears before the custom post type code name. For example, I may have a custom post type of CARS, but my custom post type code name is wps_cars. The "wps_" is a namespace. My recommendation is to create a namespace that identifies you and your brand, e.g., for me wps_, for a company called Bob Barker Media, they may want bbm_ or bbmed_. Then consistently use this prefix in front of all your functions, names, etc. to prevent conflicts.

This is important because without this namespace, it is extremely possible and even likely to conflict with a custom post type in your theme or a plugin that you use. While this namespacing won't guarantee a lack of conflict, it dramatically reduces the chances. However, be sure that your namespace does not exceed 20 characters as the post_type column is a varchar of the latter length. Also be sure to avoid the namespace "wp_" as WordPress may use that moving forward. And finally, never use capital letters.

Summary:

Registering the custom post type can take 25 arguments with more sub-arguments. They are:

label (string, default: $post_type):a plural descriptive name labels (array, default: name is set to label value, and singular_name is set to name value; more below) description (string, default: blank): A short descriptive summary of what the post type is
public (boolean, default: false): Meta argument used to define default values for publicly_queriable, show_ui, show_in_nav_menus and exclude_from_search publicly_queryable (boolean, default: value of public): Whether post_type queries can be performed from the front end exclude_from_search (boolean, default: opposite value of public): Whether to exclude posts with this post type from search results
show_ui (boolean, value of public): Whether to generate a default UI for managing this post type show_in_menu (boolean/string, default: null; false-no menu item, true-top level admin menu item, some string-top level page like 'tools.php'): Whether to show the post type in the admin menu and where to show that menu menu_position (integer, default: null): The position in the menu order the post type should appear
menu_icon (string, default: null): The url to the icon to be used for this menu capability_type (string/array, default: "post"): The string to use to build the read, edit, and delete capabilities capabilities (array, default: capability_type: post): An array of the capabilities for this post type
map_meta_cap (boolean, default: false): Whether to use the internal default meta capability handling hierarchical (boolean, default: false): Whether the post type is hierarchical. Allows Parent to be specified supports (array, default: title and editor, but can support the following: title, editor, author, thumbnail [featured image, theme must support post-thumbnails], excerpt, trackbacks, custom-fields, comments, revisions, page attributes, post-formats [see Post Formats] ): An alias for calling add_post_type_support() directly
register_meta_box_cb (string, default: none): Provide a callback function that will be called when setting up the meta boxes for the edit form. Do remove_meta_box() and add_meta_box() calls in the callback taxonomies (array, default: none): An array of registered taxonomies like category or post_tag that will be used with this post type. This can be use in lieu of calling register_taxonomy_for_object_type() directly. Custom taxonomies still need to be registered with register_taxonomy() permalink_epmask (string, default: EP_PERMALINK): The default rewrite endpoint bitmasks
has_archive (boolean, default: false): Enables post type archives. Will use string as archive slug. Will generate the proper rewrite rules if rewrite is enabled. rewrite (boolean/array, default: true/slug): Rewrite permalinks with this format. False to prevent rewrite query_var (boolean/string, default: true, set to $post_type): Whether post_type is available for selection in navigation menus
can_export (boolean, default: true): Can this post_type be exported show_in_nav_menus (boolean, default: value of public): Whether post_type is available for selection in navigation menus

*Two other arguments include _builtin and _edit_link; however, WordPress core developers recommend you don't use these when registering your custom post type.

To me, the most important arguments to set are label, labels, public (which sets publicly_queryable, exclude_from_search, show_ui, and show_in_nav_menus), description, supports, register_meta_box_cb, taxonomies, has_archive, rewrite, and capabilities.

Label

Label (a plural descriptive name for the post type marked for translation) and labels (an array of labels for this post type) are what appears on the UI (use
r interface) on the backend.

Labels

from the Codex:

Default: if empty, name is set to label value, and singular_name is set to name value

  • 'name' - general name for the post type, usually plural. The same as, and overridden by $post_type_object->label
  • 'singular_name' - name for one object of this post type. Defaults to value of name
  • 'add_new' - the add new text. The default is Add New for both hierarchical and non-hierarchical types. When internationalizing this string, please use a gettext context matching your post type. Example: _x('Add New', 'product');
  • 'add_new_item' - the add new item text. Default is Add New Post/Add New Page
  • 'edit_item' - the edit item text. Default is Edit Post/Edit Page
  • 'new_item' - the new item text. Default is New Post/New Page
  • 'view_item' - the view item text. Default is View Post/View Page
  • 'search_items' - the search items text. Default is Search Posts/Search Pages
  • 'not_found' - the not found text. Default is No posts found/No pages found
  • 'not_found_in_trash' - the not found in trash text. Default is No posts found in Trash/No pages found in Trash
  • 'parent_item_colon' - the parent text. This string isn't used on non-hierarchical types. In hierarchical ones the default is Parent Page
  • 'menu_name' - the menu name text. This string is the name to give menu items. Defaults to value of name

Public

public sets a few other parameters, which don't need to be set unless you want something different (e.g., I want a public post_type but want it unsearchable/unqueryable publicly, then public => true and publicly_queryable => false or exclude_from_search => true).

From the codex:

  • 'false' - do not display a user-interface for this post type (show_ui=false), post_type queries can not be performed from the front end (publicly_queryable=false), exclude posts with this post type from search results (exclude_from_search=true), hide post_type for selection in navigation menus (show_in_nav_menus=false)
  • 'true' - show_ui=true, publicly_queryable=true, exclude_from_search=false, show_in_nav_menus=true

Description

Just like category description, description could have some SEO value but doesn't inherently as of 3.1.

Supports

supports refers to the current existing post/page metaboxes: title, editor, author, thumbnail, excerpt, trackbacks, custom-fields, comments, revisions, and page-attributes.

Meta Boxes

register_meta_box_cb is the way to add more metaboxes that can be built out specifically for the custom post type.

Taxonomies

taxonomies refers to the specific taxonomies that are associated with the custom post type. So if I have a custom post type of movies, I may want my custom taxonomy of producers, stars, etc. attached to it.

Archives

has_archive enables the custom post type to have an archive.

Menu Position

While not inherently important, menu_position could be critical if you want it to appear before posts. So for convenience here are the numbers:

Rewrite

from the Codex:

$args array

  • 'slug' - prepend posts with this slug - defaults to post type's name - use array('slug'=>$slug) to customize permastruct
  • 'with_front' - allowing permalinks to be prepended with front base (example: if your permalink structure is /blog/, then your links will be: false->/news/, true->/blog/news/) - defaults to true
  • 'feeds' - default to has_archive value
  • 'pages' - defaults to true

Capabilities

Justin Tadlock wrote an excellent article regarding capabilities and capability_type: Meta capabilities for custom post types. If you want to segment out someone's capability to read, edit, and/or delete your custom post type, then read Justin's post because this argument allows you to customize and split out those capabilities.

from the Codex:

By default, seven keys are accepted as part of the capabilities array:

  • edit_post, read_post, and delete_post - These three are meta capabilities, which are then generally mapped to corresponding primitive capabilities depending on the context, for example the post being edited/read/deleted and the user or role being checked. Thus these capabilities would generally not be granted directly to users or roles.
  • edit_posts - Controls whether objects of this post type can be edited.
  • edit_others_posts - Controls whether objects of this type owned by other users can be edited. If the post type does not support an author, then this will behave like edit_posts.
  • publish_posts - Controls publishing objects of this post type.
  • read_private_posts - Controls whether private objects can be read.

Note: those last four primitive capabilities are checked in core in various locations.

There are also seven other primitive capabilities which are not referenced directly in core, except in map_meta_cap(), which takes the three aforementioned meta capabilities and translates them into one or more primitive capabilities that must then be checked against the user or role, depending on the context. These additional capabilities are only used in map_meta_cap(). Thus, they are only assigned by default if the post type is registered with the 'map_meta_cap' argument set to true (default is false).

  • read - Controls whether objects of this post type can be read.
  • delete_posts - Controls whether objects of this post type can be deleted.
  • delete_private_posts - Controls whether private objects can be deleted.
  • delete_published_posts - Controls whether published objects can be deleted.
  • delete_others_posts - Controls whether objects owned by other users can be can be deleted. If the post type does not support an author, then this will behave like delete_posts.
  • edit_private_posts - Controls whether private objects can be edited.
  • edit_published_posts - Controls whether published objects can be edited.

For example, check out this blog post: Permissions with WordPress Custom Post Types

EXAMPLES

Simple Example

A simple custom post type registration only requires a few lines of code.

[php] function wps_register_cars_cpt () {<br /> register_post_type ('wps_cars', array( 'label' => 'Cars' , 'public' => true ) );<br />}<br />add_action( 'init' , 'my_register_cpt' );<br />?>[/php]

However, it is only limited to the defaults of registering post types as you can see in the above table. However, to optimize the custom post type, you need to add a few more lines of code.

Complex Example

When registering your post type, it is a best practice to split out labels into a separate array.

[php]<br />add_action('init', 'wps_cpt_init');<br />function wps_cpt_init() {<br /> $labels= array(<br /> 'name' => _x('Cars', 'post type
general name'),<br /> 'singular_name' => _x('Car', 'post type singular name'),<br /> 'add_new' => _x('Add New', 'car'),<br /> 'add_new_item' => __('Add New Car'),<br /> 'edit_item' => __('Edit Car'),<br /> 'new_item' => __('New Car'),<br /> 'view_item' => __('View Car'),<br /> 'search_items' => __('Search Car'),<br /> 'not_found' => __('No cars found'),<br /> 'not_found_in_trash' => __('No cars found in Trash'),<br /> 'parent_item_colon' => '',<br /> 'menu_name' => 'Cars'<br /> );<br /> $args = array(<br /> 'labels' => $labels,<br /> 'public' => true,<br /> 'query_var' => true,<br /> 'rewrite' => true,<br /> 'capability_type' => 'post',<br /> 'has_archive' => true,<br /> 'hierarchical' => false,<br /> 'menu_position' => null,<br /> 'taxonomies' => array('wps_car_model','wps_car_color'),<br /> 'register_meta_box_cb' => 'add_wps_metaboxes',<br /> 'supports' => array('title','editor','author','thumbnail','excerpt','trackbacks','custom-fields','comments','revisions')<br /> );<br /> register_post_type( 'wps_cars' , $args );<br />}<br />[/php]