Post Status Generator
register_post_status() alone gets you a status nobody can select. This adds the editor dropdown, the list-table link and the label the display shows.
<?php // Generated with WP CodeKit — powered by GrowQuest (https://growquest.io). /** * Plugin Name: In review post status * Description: Registers the in-review status for post. * Version: 1.0.0 * Requires PHP: 7.4 * Text Domain: acme */ defined( 'ABSPATH' ) || exit; /** * Register the In review status. */ function acme_register_status() { register_post_status( 'in-review', array( 'label' => _x( 'In review', 'post status', 'acme' ), 'label_count' => _n_noop( 'In review <span class="count">(%s)</span>', 'In review <span class="count">(%s)</span>', 'acme' ), 'public' => false, 'internal' => false, 'exclude_from_search' => true, 'show_in_admin_all_list' => true, 'show_in_admin_status_list' => true, 'date_floating' => true, 'post_type' => array( 'post' ), ) ); } add_action( 'init', 'acme_register_status' ); /** * Show the status beside the title in the posts list. * * @param string[] $states Existing state labels. * @param WP_Post $post The post. * @return string[] */ function acme_display_state( $states, $post ) { if ( 'in-review' === get_post_status( $post ) ) { $states['in-review'] = _x( 'In review', 'post status', 'acme' ); } return $states; } add_filter( 'display_post_states', 'acme_display_state', 10, 2 ); /** * Add the status to the classic editor dropdown. * * The block editor ignores PHP-registered statuses, so this only * affects the classic editor and Quick Edit. * * @param WP_Post $post The post being edited. */ function acme_submitbox_status( $post ) { if ( ! in_array( $post->post_type, array( 'post' ), true ) ) { return; } $label = _x( 'In review', 'post status', 'acme' ); $option = sprintf( '<option value="%1$s"%2$s>%3$s</option>', esc_attr( 'in-review' ), selected( get_post_status( $post ), 'in-review', false ), esc_html( $label ) ); ?> <script> jQuery( function ( $ ) { var option = <?php echo wp_json_encode( $option ); ?>; var label = <?php echo wp_json_encode( $label ); ?>; $( 'select#post_status' ).append( option ); <?php if ( get_post_status( $post ) === 'in-review' ) : ?> $( '#post-status-display' ).text( label ); <?php endif; ?> } ); </script> <?php } add_action( 'post_submitbox_misc_actions', 'acme_submitbox_status' );
About this generator
Post Status Generator Online
Build a custom post status in WordPress — In review, Awaiting legal, Archived — and get more than the bare register_post_status() call. The generator writes the registration with a properly nooped label_count, the display_post_states filter that labels the post in the list table, the classic-editor Status dropdown entry, and an optional pre_get_posts helper so posts in the status still appear under All.
A Reference tab explains every argument and what it actually changes in the admin, including the ones whose defaults are derived from internal rather than from public. Free, no account, and nothing you type leaves the browser.
Reviewed Output tested on WordPress 6.8 · PHP 8.3
Why a custom post status needs more than register_post_status()
Registering a status takes six lines and gives you almost nothing: the status exists, but nobody can select it, no post shows it in the list table, and the filter link at the top of the screen is missing. The visible half of the feature is four separate hooks that no reference page collects in one place. This generator writes them together and tells you which ones you have left out.
The 20-character limit and the core status list
The post_status column is 20 characters wide, so a longer slug registers but silently fails to save on a post. publish, draft, pending, private, future, trash, auto-draft and inherit are refused outright, because re-registering one overrides core behaviour site-wide.
label_count built with _n_noop()
The count label needs singular and plural forms and a %s placeholder for the number. Leave the placeholder out and the filter link shows the label with no count at all — a warning with a one-click fix that rebuilds the string for you.
Contradictory flags caught
public and internal together is an error, because internal is core plumbing for auto-draft and inherit. A public status that is not excluded from search is a warning, since unfinished posts then surface in site search and in feeds. A status that is neither public nor in either admin list is an error: nobody would ever see it.
The label beside the title
Without a display_post_states filter a post in your status looks identical to a published one in the posts list. The generator adds the filter, correctly registered with two accepted arguments, and warns when you turn it off.
An honest classic-editor dropdown
PHP-registered statuses do not appear in the block editor status control. The generator emits the post_submitbox_misc_actions snippet that adds the option to the classic editor and Quick Edit, and states in a code comment and in the Checks tab that this is exactly what it does and does not cover.
The All view, handled deliberately
Turn show_in_admin_all_list off and posts vanish from the default view. An optional pre_get_posts helper adds the status back for the main admin query only, scoped by get_current_screen() and skipped when a status filter is already active.
How does the custom post status generator work?
Name the status, decide how visible it is, add the pieces that make it usable, then export.
- 01
Name the status
Enter the label editors will see and the slug stored in the database, plus the count label used in the filter link. The slug is lowercased and dashed, and capped at the 20 characters the column allows.
- 02
Scope it to post types
Choose
post,page,productor type any custom post type slug. The list is written into the registration args and reused by the editor dropdown and the query helper, which is what actually keeps the status from being offered everywhere. - 03
Set the visibility flags
Toggle public, internal, exclude from search, the two admin list flags and
date_floating. The Checks tab explains the consequence of each combination rather than just listing the arguments. - 04
Add the usable parts, then export
Turn on the list-table label, the classic-editor dropdown and the All-view helper as needed, clear the checks, then copy the snippet or download the plugin file.
Worked example — an In review status on posts
Not public, excluded from search, visible in both admin lists, with a floating date so the publish date is only set on publish. This is the registration exactly as it is generated.
/**
* Register the In review status.
*/
function acme_register_status() {
register_post_status(
'in-review',
array(
'label' => _x( 'In review', 'post status', 'acme' ),
'label_count' => _n_noop(
'In review <span class="count">(%s)</span>',
'In review <span class="count">(%s)</span>',
'acme'
),
'public' => false,
'internal' => false,
'exclude_from_search' => true,
'show_in_admin_all_list' => true,
'show_in_admin_status_list' => true,
'date_floating' => true,
'post_type' => array( 'post' ),
)
);
}
add_action( 'init', 'acme_register_status' );Leave the list-table label and the editor dropdown toggles on and the generator appends the display_post_states filter and the post_submitbox_misc_actions callback beneath this, in the same file.
Custom post statuses — frequently asked questions
What people actually run into after registering their first custom status.
Why does my custom post status not appear in the block editor?
Because the block editor does not read PHP-registered statuses into its status control. register_post_status() makes the status real for queries, the list table and the classic editor, but Gutenberg builds its own list. The practical routes are Quick Edit, a classic-editor dropdown snippet, setting the status programmatically with wp_insert_post(), or a small block-editor plugin.
How do I add a custom status to the editor Status dropdown?
In the classic editor, hook post_submitbox_misc_actions and append an <option> to select#post_status, updating #post-status-display when the current post already uses it. That is exactly what this generator emits. It affects the classic editor and Quick Edit only.
Where should register_post_status() be called?
On the init action, and not before it. The reference is explicit that the function must not be used before init, because the status registry is set up as part of that hook. Registering it in a plugin file at load time gives inconsistent results.
What is the maximum length of a post status slug?
Twenty characters. post_status is a 20-character column in the posts table, so a longer slug registers happily and then fails when a post is saved with it — the database write is rejected and the change silently does not stick. The generator raises this as an error.
Can I limit a custom post status to one post type?
Partly. The post_type array is stored on the registered status object, and the generated helpers use it: the classic-editor dropdown only appends the option when $post->post_type matches, and the query helper only adds the status for those types. Core itself does not gate statuses by post type, so those guards are what does the limiting.
What does date_floating actually do?
It leaves post_date unset until the post is published, the way draft behaves. That is right for a status that sits before publication in a workflow, and wrong for anything users see dated — an archived post with a floating date loses its original publish date the first time it moves.
Where do I paste the code from the Post Status generator?
You have three good options and one bad one. Best is a small site-specific plugin — the generator can output one for you, and it keeps working when you change theme. A code-snippets plugin is fine too. A child theme's functions.php works but ties the code to that theme. Never edit the parent theme: the next update overwrites it and your code is gone.
Why isn't my new post status showing up, or why do I get a 404?
Almost always stale rewrite rules. WordPress caches the URL routing table, so anything that adds URLs is invisible until that cache is rebuilt. Go to Settings → Permalinks and press Save Changes — you do not need to alter anything, just saving the page flushes the rules. Never call flush_rewrite_rules() on every page load; it is an expensive write and belongs in an activation hook.
Can I use the generated code in client work or a commercial plugin?
Yes. The output is ordinary WordPress API calls that you configured — there is no licence attached to it and no attribution required. Use it in client sites, commercial plugins and themes, or products you sell. The generated file carries a short credit comment you are free to delete.
The other Content generators in the library, plus the WordPress tools most often used alongside this one.