register_post_status( string $post_status, array|string $args = array() ): object

Registers a post status. Do not use before init.


A simple function for creating or modifying a post status based on the parameters given. The function will accept an array (second optional parameter), along with a string for the post status name.

Arguments prefixed with an _underscore shouldn’t be used by plugins and themes.

Top ↑


$post_status string Required
Name of the post status.
$args array|string Optional
Array or string of post status arguments.
  • label bool|string
    A descriptive name for the post status marked for translation. Defaults to value of $post_status.
  • label_count array|false
    Nooped plural text from _n_noop() to provide the singular and plural forms of the label for counts. Default false which means the $label argument will be used for both the singular and plural forms of this label.
  • exclude_from_search bool
    Whether to exclude posts with this post status from search results. Default is value of $internal.
  • _builtin bool
    Whether the status is built-in. Core-use only.
    Default false.
  • public bool
    Whether posts of this status should be shown in the front end of the site. Default false.
  • internal bool
    Whether the status is for internal use only.
    Default false.
  • protected bool
    Whether posts with this status should be protected.
    Default false.
  • private bool
    Whether posts with this status should be private.
    Default false.
  • publicly_queryable bool
    Whether posts with this status should be publicly- queryable. Default is value of $public.
  • show_in_admin_all_list bool
    Whether to include posts in the edit listing for their post type. Default is the opposite value of $internal.
  • show_in_admin_status_list bool
    Show in the list of statuses with post counts at the top of the edit listings, e.g. All (12) | Published (9) | My Custom Status (2) Default is the opposite value of $internal.
  • date_floating bool
    Whether the post has a floating creation date.
    Default to false.

Default: array()

Top ↑



Top ↑


File: wp-includes/post.php. View all references

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;

Top ↑


Version Description
3.0.0 Introduced.

Top ↑

User Contributed Notes

  1. Skip to note 1 content
    Contributed by ajfleming

    20 is the maximum character length for the $post_status parameter.

    wp shell
    wp> global $wpdb;
    wp> $wpdb->get_col_length('wp_posts','post_status')
    => phar:///usr/local/bin/wp/vendor/wp-cli/shell-command/src/WP_CLI/Shell/REPL.php:52:
    array(2) {
    'type' =>
    string(4) "char"
    'length' =>

    We’re able to register a post status with a $post_status parameter longer than 20 characters, but we’re unable to save/update posts with it. Instead, the wpdb->process_fields() method compares the converted data to the provided data and returns false because they’re different.

  2. Skip to note 2 content
    Contributed by Codex

    An example of registering a post status called “Unread”:

     * Add 'Unread' post status.
    function wpdocs_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>' ),
    	) );
    add_action( 'init', 'wpdocs_custom_post_status' );
  3. Skip to note 3 content
    Contributed by Brent Leavitt

    Something that was not clear in my understanding was the independent nature of Post Statuses in connection with Custom Post Types (CPT). I had always been under the assumption that a specific Post Status had to be linked to a specific post type, but the reality is that post statuses exist separate or independent from any post type or custom post type.

    From what I can see, the only place where Post Status is declared is within the code. A list of available post statuses can be generated from the global variable

    global  $wp_post_statuses;

    . These different post_status are not stored as list or array in the options table of database. The only place where post_status is used in the database is in the wp_posts table as the actual `post_status` value.

    To load a specific set of post_status values in the post editor screen (for example) is beyond the scope of this comment, but you will want to look into filtering the values for the post_status as is relevant to your needs.

You must log in before being able to contribute a note or feedback.