Custom Post Status Generator

Generate register_post_status() code with the label, visibility flags and the admin list counts WordPress shows for a custom status.

Live output

Enable JavaScript to customise; default output below.

Stored in post_status. WordPress caps it at 20 characters.

Shown wherever WordPress names the status.

Used by the generated JavaScript that adds the status to the editor dropdown.

Live preview post-status.php
<?php
/**
 * Registers the "archived" post status.
 */
function my_plugin_register_archived_status() {
	register_post_status(
		'archived',
		array(
			'label'                     => _x( 'Archived', 'post status', 'my-plugin' ),
			'public'                    => false,
			'internal'                  => false,
			'protected'                 => true,
			'private'                   => false,
			'exclude_from_search'       => true,
			'show_in_admin_all_list'    => true,
			'show_in_admin_status_list' => true,
			/* translators: %s: number of posts. */
			'label_count'               => _n_noop(
				'Archived <span class="count">(%s)</span>',
				'Archived <span class="count">(%s)</span>',
				'my-plugin'
			),
		)
	);
}
add_action( 'init', 'my_plugin_register_archived_status' );

/**
 * Adds "Archived" to the classic editor's status menu.
 *
 * WordPress registers the status but never adds it to that dropdown, so the
 * option is appended in the browser and the current value re-selected.
 */
function my_plugin_register_archived_status_editor_option() {
	$screen = get_current_screen();
	$types  = array_map( 'trim', explode( ',', 'post' ) );

	if ( ! $screen || ! in_array( $screen->post_type, $types, true ) ) {
		return;
	}

	$post     = get_post();
	$selected = ( $post && 'archived' === $post->post_status ) ? 'selected' : '';
	?>
	<script>
	jQuery( function( $ ) {
		// JSON_HEX_TAG keeps a label containing </script> from ending this block.
		var label = <?php echo wp_json_encode( 'Archived', JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT ); ?>;
		var value = <?php echo wp_json_encode( 'archived', JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT ); ?>;

		$( 'select#post_status' ).append(
			$( '<option>', { value: value, text: label, selected: <?php echo $selected ? 'true' : 'false'; ?> } )
		);

		<?php if ( $selected ) : ?>
		$( '#post-status-display' ).text( label );
		<?php endif; ?>
	} );
	</script>
	<?php
}
add_action( 'admin_footer-post.php', 'my_plugin_register_archived_status_editor_option' );
add_action( 'admin_footer-post-new.php', 'my_plugin_register_archived_status_editor_option' );

Output is valid and updates as you type.

Register a post status of your own, with the visibility flags that decide who can read those posts and the admin counts WordPress shows beside them.

How to use

  1. Pick the status key. It goes in the post_status column and is capped at 20 characters.
  2. Set visibility. Protected keeps posts out of the front end while editors still see them; public means anyone with the URL can read them.
  3. Decide how the status appears in the post list: inside All, and whether it gets its own filter link with a count.
  4. Leave the editor dropdown option on unless you only set the status in code. WordPress registers the status but never adds it to the classic editor’s Status menu.
  5. Paste the result into your plugin. It hooks init for registration and the admin footer for the dropdown.

Example

An archive status that hides posts from the front end, keeps them out of search, and adds a filter link to the admin list:

register_post_status(
	'archived',
	array(
		'label'                     => _x( 'Archived', 'post status', 'my-plugin' ),
		'public'                    => false,
		'protected'                 => true,
		'exclude_from_search'       => true,
		'show_in_admin_all_list'    => true,
		'show_in_admin_status_list' => true,
		'label_count'               => _n_noop(
			'Archived <span class="count">(%s)</span>',
			'Archived <span class="count">(%s)</span>',
			'my-plugin'
		),
	)
);

label_count is the string above the list table, and it takes singular and plural forms because some languages need more than one.

Pitfalls

  • The status key is capped at 20 characters and is stored on every post that uses it. Renaming it later means an UPDATE across wp_posts.
  • WordPress does not add a custom status to the editor’s status dropdown. Without the appended script, the only way to set it is in code or with a bulk action.
  • The block editor ignores that script entirely. It reads statuses from the REST schema, so a custom status needs editor-side JavaScript rather than an admin-footer snippet.
  • public and protected are not opposites. Public exposes posts to the front end; protected hides them but keeps them visible to editors. Setting both leaves readers confused about which wins.
  • A status with exclude_from_search still appears in queries that name it explicitly, including WP_Query with post_status set.
  • Posts left in a custom status when the plugin is deactivated stay in that status and become invisible, since nothing registers it any more. Plan the deactivation path.
  • show_in_admin_status_list runs a count query per status on the list screen. On a large table that is the cost of the filter link.

Compatibility

register_post_status() has been stable since WordPress 3.0 and the argument names here have not changed since. The generated dropdown snippet uses jQuery, which WordPress still ships in the admin, and applies to the classic editor only. The code targets PHP 7.0 and later; the tool runs in your browser.

Frequently asked questions

Why does my status not appear in the editor?
For the classic editor, the appended script is what adds it. For the block editor, nothing here helps: it builds that menu from REST data, so you need editor JavaScript registered against the post type.
Does the status work with WP_Query?
Yes. Pass it as post_status, either alone or in an array. It is a normal status as far as queries are concerned.
What happens to those posts if I remove the plugin?
They keep the status string, but nothing registers it, so they drop out of the admin lists and the front end. Convert them to draft on deactivation if that matters.
Public, protected or private — which do I want?
Protected for an internal workflow state such as awaiting review. Public for something readers should reach. Private for content limited to users who can read private posts.
Can I use this to build an editorial workflow?
For the states, yes. Moving posts between them, permissions and notifications are separate work; this only registers the state itself.

From the people who built this tool

WP Adminify

The WordPress admin, rebuilt: a dashboard worth looking at, menu and column control, a real file manager and the login page your client sees.

See WP Adminify Free version on WordPress.org

Weekly drops

New tools, when there are new tools

One email when something worth using ships. No schedule to fill, so no filler.

Your address goes nowhere else, and one click unsubscribes.