register_post_status()WP 3.0.0

Function for creating a new or editing an old post status, based on the provided parameters.

This function should be called during or after the init event.

Functionality of statuses is incomplete

This function does not add a new post status to the admin panel (as an option when editing a post or in quick edit). The function is under development.

Workarounds for the status issue are discussed here:
https://stackoverflow.com/q/20298346/612253

Statuses are not tied to post type
Post statuses in WordPress exist independently of post types — they are global.
That is, they are not tied to a specific post type (for example, to post or page).

Statuses are declared in code, and their list can be obtained through:

global $wp_post_statuses;

They are not stored in the database as a separate list — they are simply used as values of the post_status field in the wp_posts table.

If you need only specific statuses to be displayed for a particular post type, you will have to use a filter to modify the list.

Use get_post_status_object() to get data of the registered status.

No Hooks.

Returns

Object.

Usage

register_post_status( $post_status, $args );
$post_status(string) (required)

Name of the post status. No more than 20 characters!

Statuses already registered in WP:

  • publish - published post;
  • inherit - revision;
  • pending - pending review;
  • private - private post (accessible only to the author);
  • future - future publication;
  • draft - draft;
  • trash - post is in the trash.

Maximum number of characters for $post_status - 20

This limitation is set in the DB for the post_status field. If a string longer than this is specified, all excess will be truncated. See wp_posts table schema.

If a status longer than 20 characters is specified, it will be registered, but the post will not be updated. Instead, the method $wpdb->process_fields() compares the transformed data with the provided data and returns false because they differ.

global $wpdb;
$res = $wpdb->get_col_length( $wpdb->posts, 'post_status' );

print_r( $res );
// Array( [type] => char  [length] => 20 )
$args(string/array)

Array of post status arguments. By default:

// Arguments starting with _ are reserved for internal use.
$defaults = array(
	'label'                     => false,
	'label_count'               => false,
	'exclude_from_search'       => null,
	'_builtin'                  => false,
	'public'                    => null,
	'internal'                  => null,
	'protected'                 => null,
	'private'                   => null,
	'publicly_queryable'        => null,
	'show_in_admin_status_list' => null,
	'show_in_admin_all_list'    => null,
);
  • label(string)
    Description name for the post status intended for translation.
    Default: $post_status

  • label_count(string)
    Text displayed in the admin panel console (if you do not want the count of posts with this status).
    Default: false

  • exclude_from_search(boolean)
    Whether to exclude posts with this status from search results. true - exclude.
    Default: value of $internal

  • public(boolean)
    Whether to show posts with this status on the front end of the site. true - show.
    Default: null

  • $internal(true/false)
    Status intended for internal use only.
    Default: false

  • $protected(true/false)
    Should the post with this status be protected?
    Default: false

  • $private(true/false)
    Should the post with this status be private?
    Default: false

  • $publicly_queryable(true/false)
    Should the post with this status participate in public queries?
    Default: value of $public

  • show_in_admin_all_list(boolean)
    Should posts with this status be included in the list of posts in the admin panel.
    If true:

    • then the value of the field show_in_list in the REST request will receive this value.
    • posts with this status will appear in the general list "All" in the posts table in the admin panel and will be counted in the counter.
    • are included in the query for WP_Query by default when the status is not specified or any.

    Default: opposite value of $internal

  • show_in_admin_status_list(boolean)
    Whether to show the status in the status list at the top of the posts table:

    status-in-head

    Default: opposite value of $internal

  • $_builtin(true/false)
    Is the status built-in. For core use only.
    Default: false

Examples

0

#1 An example of registering the status of a post called Unread:

add_action( 'init', 'my_custom_post_status' );

function my_custom_post_status(){

	register_post_status( 'unread', array(
		'label'                     => _x( 'Unread', 'post' ),
		'public'                    => true,
		'exclude_from_search'       => false,
		'show_in_admin_all_list'    => true,
		'show_in_admin_status_list' => true,
		'label_count'               => _n_noop( 'Unread <span class="count">(%s)</span>', 'Unread <span class="count">(%s)</span>' ),
	) );
}

Notes

  • Global. stdClass[]. $wp_post_statuses Inserts new post status object into the list

Changelog

Since 3.0.0 Introduced.

register_post_status() code WP 6.8.1

function register_post_status( $post_status, $args = array() ) {
	global $wp_post_statuses;

	if ( ! is_array( $wp_post_statuses ) ) {
		$wp_post_statuses = array();
	}

	// Args prefixed with an underscore are reserved for internal use.
	$defaults = array(
		'label'                     => false,
		'label_count'               => false,
		'exclude_from_search'       => null,
		'_builtin'                  => false,
		'public'                    => null,
		'internal'                  => null,
		'protected'                 => null,
		'private'                   => null,
		'publicly_queryable'        => null,
		'show_in_admin_status_list' => null,
		'show_in_admin_all_list'    => null,
		'date_floating'             => null,
	);
	$args     = wp_parse_args( $args, $defaults );
	$args     = (object) $args;

	$post_status = sanitize_key( $post_status );
	$args->name  = $post_status;

	// Set various defaults.
	if ( null === $args->public && null === $args->internal && null === $args->protected && null === $args->private ) {
		$args->internal = true;
	}

	if ( null === $args->public ) {
		$args->public = false;
	}

	if ( null === $args->private ) {
		$args->private = false;
	}

	if ( null === $args->protected ) {
		$args->protected = false;
	}

	if ( null === $args->internal ) {
		$args->internal = false;
	}

	if ( null === $args->publicly_queryable ) {
		$args->publicly_queryable = $args->public;
	}

	if ( null === $args->exclude_from_search ) {
		$args->exclude_from_search = $args->internal;
	}

	if ( null === $args->show_in_admin_all_list ) {
		$args->show_in_admin_all_list = ! $args->internal;
	}

	if ( null === $args->show_in_admin_status_list ) {
		$args->show_in_admin_status_list = ! $args->internal;
	}

	if ( null === $args->date_floating ) {
		$args->date_floating = false;
	}

	if ( false === $args->label ) {
		$args->label = $post_status;
	}

	if ( false === $args->label_count ) {
		// phpcs:ignore WordPress.WP.I18n.NonSingularStringLiteralSingular,WordPress.WP.I18n.NonSingularStringLiteralPlural
		$args->label_count = _n_noop( $args->label, $args->label );
	}

	$wp_post_statuses[ $post_status ] = $args;

	return $args;
}