wppaste
WordPress

register_post_type( string $post_type, array|string $args = array() ): WP_Post_Type|WP_Error

Since
2.9.0, 3.0.0, 4.4.0, 4.6.0, 4.7.0, 5.0.0, 5.3.0, 5.9.0
Source
wp-includes/post.php:1857
Registers a post type.

Description

Note: Post type registrations should not be hooked before the 'init' action. Also, any taxonomy connections should be registered via the $taxonomies argument to ensure consistency when hooks such as 'parse_query' or 'pre_get_posts' are used.

Post types can support any number of built-in core features such as meta boxes, custom fields, post thumbnails, post statuses, comments, and more. See the $supports argument for a complete list of supported features.

Compatibility

WordPress
since 5.9.0
PHP
7.4–8.6-dev
  • 6.7.7
  • 6.8.8
  • 6.9.7
  • 7.0.4
  • 7.1.0

Present in every tracked release (6.7.7 to 7.1.0), and compiles on PHP 7.4 through 8.6-dev.

Parameters

$post_typestring
Post type key. Must not exceed 20 characters and may only contain lowercase alphanumeric characters, dashes, and underscores. See sanitize_key().
$argsarray|stringoptional
Array or string of arguments for registering a post type.Default: array()
  • $labelstringdefault: is value of $labels['name']

    Name of the post type shown in the menu. Usually plural.
  • $labelsstring[]

    An array of labels for this post type. If not set, post labels are inherited for non-hierarchical types and page labels for hierarchical ones. See get_post_type_labels() for a full list of supported labels.
  • $descriptionstringdefault: empty

    A short descriptive summary of what the post type is.
  • $publicbooldefault: false

    Whether a post type is intended for use publicly either via the admin interface or by front-end users. While the default settings of $exclude_from_search, $publicly_queryable, $show_ui, and $show_in_nav_menus are inherited from $public, each does not rely on this relationship and controls a very specific intention.
  • $hierarchicalbooldefault: false

    Whether the post type is hierarchical (e.g. page).
  • $exclude_from_searchbooldefault: is the opposite value of $public

    Whether to exclude posts with this post type from front end search results.
  • $publicly_queryablebool

    Whether queries can be performed on the front end for the post type as part of parse_request(). Endpoints would include: ?post_type={post_type_key} ?{post_type_key}={single_post_slug} * ?{post_type_query_var}={single_post_slug} If not set, the default is inherited from $public.
  • $show_uibooldefault: is value of $public

    Whether to generate and allow a UI for managing this post type in the admin.
  • $show_in_menubool|stringdefault: is value of $show_ui

    Where to show the post type in the admin menu. To work, $show_ui must be true. If true, the post type is shown in its own top level menu. If false, no menu is shown. If a string of an existing top level menu ('tools.php' or 'edit.php?post_type=page', for example), the post type will be placed as a sub-menu of that.
  • $show_in_nav_menusbooldefault: is value of $public

    Makes this post type available for selection in navigation menus.
  • $show_in_admin_barbooldefault: is value of $show_in_menu

    Makes this post type available via the admin bar.
  • $show_in_restbool

    Whether to include the post type in the REST API. Set this to true for the post type to be available in the block editor.
  • $rest_basestringdefault: is $post_type

    To change the base URL of REST API route.
  • $rest_namespacestringdefault: is wp/v2

    To change the namespace URL of REST API route.
  • $rest_controller_classstringdefault: is 'WP_REST_Posts_Controller'

    REST API controller class name.
  • $autosave_rest_controller_classstring|booldefault: is 'WP_REST_Autosaves_Controller'

    REST API controller class name.
  • $revisions_rest_controller_classstring|booldefault: is 'WP_REST_Revisions_Controller'

    REST API controller class name.
  • $late_route_registrationbool

    A flag to direct the REST API controllers for autosave / revisions should be registered before/after the post type controller.
  • $menu_positionintdefault: null (at the bottom)

    The position in the menu order the post type should appear. To work, $show_in_menu must be true.
  • $menu_iconstring

    The URL to the icon to be used for this menu. Pass a base64-encoded SVG using a data URI, which will be colored to match the color scheme -- this should begin with 'data:image/svg+xml;base64,'. Pass the name of a Dashicons helper class to use a font icon, e.g. 'dashicons-chart-pie'. Pass 'none' to leave div.wp-menu-image empty so an icon can be added via CSS. Defaults to use the posts icon.
  • $capability_typestring|arraydefault: 'post'

    The string to use to build the read, edit, and delete capabilities. May be passed as an array to allow for alternative plurals when using this argument as a base to construct the capabilities, e.g. array('story', 'stories').
  • $capabilitiesstring[]

    Array of capabilities for this post type. $capability_type is used as a base to construct capabilities by default. See get_post_type_capabilities().
  • $map_meta_capbooldefault: false

    Whether to use the internal default meta capability handling.
  • $supportsarray|falsedefault: is an array containing 'title' and 'editor'

    Core feature(s) the post type supports. Serves as an alias for calling add_post_type_support() directly. Core features include 'title', 'editor', 'comments', 'revisions', 'trackbacks', 'author', 'excerpt', 'page-attributes', 'thumbnail', 'custom-fields', and 'post-formats'. Additionally, the 'revisions' feature dictates whether the post type will store revisions, the 'autosave' feature dictates whether the post type will be autosaved, and the 'comments' feature dictates whether the comments count will show on the edit screen. For backward compatibility reasons, adding 'editor' support implies 'autosave' support too. A feature can also be specified as an array of arguments to provide additional information about supporting that feature. Example: array( 'my_feature', array( 'field' => 'value' ) ). If false, no features will be added.
  • $register_meta_box_cbcallabledefault: null

    Provide a callback function that sets up the meta boxes for the edit form. Do remove_meta_box() and add_meta_box() calls in the callback.
  • $taxonomiesstring[]default: empty array

    An array of taxonomy identifiers that will be registered for the post type. Taxonomies can be registered later with register_taxonomy() or register_taxonomy_for_object_type().
  • $has_archivebool|stringdefault: false

    Whether there should be post type archives, or if a string, the archive slug to use. Will generate the proper rewrite rules if $rewrite is enabled.
  • $rewritebool|array

    { Triggers the handling of rewrites for this post type. To prevent rewrite, set to false. Defaults to true, using $post_type as slug. To specify rewrite rules, an array can be passed with any of these keys: @type string $slug Customize the permastruct slug. Defaults to $post_type key.
  • $with_frontbooldefault: true

    Whether the permastruct should be prepended with WP_Rewrite::$front.
  • $feedsbooldefault: is value of $has_archive

    Whether the feed permastruct should be built for this post type.
  • $pagesbooldefault: true

    Whether the permastruct should provide for pagination.
  • $ep_maskint

    Endpoint mask to assign. If not specified and permalink_epmask is set, inherits from $permalink_epmask. If not specified and permalink_epmask is not set, defaults to EP_PERMALINK. } @type string|bool $query_var Sets the query_var key for this post type. Defaults to $post_type key. If false, a post type cannot be loaded at ?{query_var}={post_slug}. If specified as a string, the query ?{query_var_string}={post_slug} will be valid.
  • $can_exportbooldefault: true

    Whether to allow this post type to be exported.
  • $delete_with_userbooldefault: null

    Whether to delete posts of this type when deleting a user. If true, posts of this type belonging to the user will be moved to Trash when the user is deleted. If false, posts of this type belonging to the user will not be trashed or deleted. If not set (the default), posts are trashed if post type supports the 'author' feature. Otherwise posts are not trashed or deleted.
  • $templatearraydefault: empty array

    Array of blocks to use as the default initial state for an editor session. Each item should be an array containing block name and optional attributes.
  • $template_lockstring|falsedefault: false

    Whether the block template should be locked if $template is set. If set to 'all', the user is unable to insert new blocks, move existing blocks and delete blocks. If set to 'insert', the user is able to move existing blocks but is unable to insert new blocks and delete blocks. If set to 'contentOnly', the user is only able to edit the content of existing blocks.
  • $_builtinbooldefault: false

    FOR INTERNAL USE ONLY! True if this post type is a native or "built-in" post_type.
  • $_edit_linkstringdefault: 'post.php?post=%d'

    FOR INTERNAL USE ONLY! URL segment to use for edit link of this post type.

Return value

WP_Post_Type|WP_Error
The registered post type object on success, WP_Error object on failure.

Performance profile

How much work a call to register_post_type() does, and what it touches: the algorithmic scaling, the Zend instruction count per call across PHP versions, the hooks it hands control to, and the core code that calls it. Measured from the compiled opcodes, not a stopwatch, so every number is identical on any machine running the same PHP version, and every function in core is ranked by cost.

Cost class
Trivial

Touches nothing outside its own arguments.

Scaling
Constant

No loop in the body: the same number of instructions runs whatever you pass in.

Instructions
27–44

Executed per call on PHP 8.5, depending on the branch taken. The body compiles to 60.

Plugin surface
2 hooks

Third-party callbacks on 'registered_post_type', 'registered_post_type_{$post_type}' run inside this call, and their cost is not bounded by anything here.

Called by
1

1 place in core call this, so the cost is paid more often than your own code shows.

What it touches

  • hookthird-party callbacksdo_action()called directly

Further down the call graph this can also reach query, option, cache, serialize and transient. Those are the worst case, several calls deep and usually down an error path, not what a normal call pays.

What one call costs · 2 distinct outcomes

One number would be a lie: the work depends on which branch runs. These are every distinct cost register_post_type() can have, taken from its control-flow graph on PHP 8.5.

WhenInstructionsCalls it makes
always27–31sanitize_key(), __(), _doing_it_wrong(), __()
!empty($post_type)43–44sanitize_key(), ->add_supports(), ->add_rewrite_rules(), ->register_meta_boxes(), ->add_hooks(), ->register_taxonomies(), do_action(), do_action()

Across PHP versions

Compiles the same on PHP 7.4, 8.1, 8.2, 8.3, 8.4, 8.5 and 8.6-dev: 60 instructions, 27–44 executed per call, 3 branches. The work does not change between versions.

An instruction is not a fixed amount of time, so a matching count is not necessarily the same speed; what it rules out is a difference in the work itself.

Hooks and filters fired · 2

2 hooks fire while register_post_type() runs, in this order:

  1. do_action( registered_post_type )actionline 1891 (+34 into the body)

    Fires after a post type is registered.

  2. do_action( registered_post_type_{$post_type} )actionline 1908 (+51 into the body)

    Fires after a specific post type is registered.

Uses · 6

Used by · 1

Source code

function register_post_type( $post_type, $args = array() ) {	global $wp_post_types; 	if ( ! is_array( $wp_post_types ) ) {		$wp_post_types = array();	} 	// Sanitize post type name.	$post_type = sanitize_key( $post_type ); 	if ( empty( $post_type ) || strlen( $post_type ) > 20 ) {		_doing_it_wrong( __FUNCTION__, __( 'Post type names must be between 1 and 20 characters in length.' ), '4.2.0' );		return new WP_Error( 'post_type_length_invalid', __( 'Post type names must be between 1 and 20 characters in length.' ) );	} 	$post_type_object = new WP_Post_Type( $post_type, $args );	$post_type_object->add_supports();	$post_type_object->add_rewrite_rules();	$post_type_object->register_meta_boxes(); 	$wp_post_types[ $post_type ] = $post_type_object; 	$post_type_object->add_hooks();	$post_type_object->register_taxonomies(); 	/**	 * Fires after a post type is registered.	 *	 * @since 3.3.0	 * @since 4.6.0 Converted the `$post_type` parameter to accept a WP_Post_Type object.	 *	 * @param string       $post_type        Post type.	 * @param WP_Post_Type $post_type_object Arguments used to register the post type.	 */	do_action( 'registered_post_type', $post_type, $post_type_object ); 	/**	 * Fires after a specific post type is registered.	 *	 * The dynamic portion of the filter name, `$post_type`, refers to the post type key.	 *	 * Possible hook names include:	 *	 *  - `registered_post_type_post`	 *  - `registered_post_type_page`	 *	 * @since 6.0.0	 *	 * @param string       $post_type        Post type.	 * @param WP_Post_Type $post_type_object Arguments used to register the post type.	 */	do_action( "registered_post_type_{$post_type}", $post_type, $post_type_object ); 	return $post_type_object;}

Changelog

Introduced in 4.7.0. Unchanged from 6.7.7 through 7.1.0.

  1. 6.7.7
  2. 6.8.8
  3. 6.9.7
  4. 7.0.4
  5. 7.1.0

Signature, return type and hooks compared across 5 parsed releases.

5.9.0
The rest_namespace argument was added.from the docblock
5.3.0
The supports argument will now accept an array of arguments for a feature.from the docblock
5.0.0
The template and template_lock arguments were added.from the docblock
4.7.0
Introduced show_in_rest, rest_base and rest_controller_class arguments to register the post type in REST API.from the docblock
4.6.0
Post type object returned is now an instance of WP_Post_Type.from the docblock
4.4.0
The show_ui argument is now enforced on the post type listing screen and post editing screen.from the docblock
3.0.0
The show_ui argument is now enforced on the new post screen.from the docblock
2.9.0
Introduced.from the docblock

About this page

Parsed data
Generated from the wordpress-develop 7.1.0 tag, from src/wp-includes/post.php, and regenerated for each WordPress release so it tracks the code rather than a snapshot of it.
Corrections
Something wrong on this page? Report it and it gets fixed in the next regeneration.