WordPress ships with built-in statuses: Draft, Pending Review, Published, Scheduled, Private, and Trash. Sometimes you need extra statuses for a custom workflow — for example, “Approved”, “In Review”, or “Archived”. WordPress provides register_post_status() for exactly this.
Problem: How do you register a custom post status in WordPress — for example, "Pending Review" or "Awaiting Approval" — and make it selectable in the admin?
Solution: Use register_post_status() in an init hook, then filter the post status dropdown with JavaScript and make it persist by hooking into save_post.
add_action( 'init', 'register_approved_status' );
function register_approved_status() {
register_post_status( 'approved', [
'label' => __( 'Approved', 'textdomain' ),
'public' => true,
'show_in_admin_all_list' => true,
'show_in_admin_status_list' => true,
// translators: number of posts
'label_count' => _n_noop( 'Approved <span class="count">(%s)</span>',
'Approved <span class="count">(%s)</span>' ),
] );
}
To make the status appear in the post edit screen dropdown, add it via JavaScript on the admin side:
add_action( 'admin_footer-post.php', 'append_approved_status_to_dropdown' );
add_action( 'admin_footer-post-new.php', 'append_approved_status_to_dropdown' );
function append_approved_status_to_dropdown() {
global $post;
if ( 'approved' !== $post->post_status ) return;
?>
<script>
jQuery( document ).ready( function( $ ) {
$( '<option>' ).val( 'approved' )
.text( '<?php esc_html_e( "Approved", "textdomain" ); ?>' )
.appendTo( '#post_status' );
$( '#post-status-display' ).text( '<?php esc_html_e( "Approved", "textdomain" ); ?>' );
} );
</script>
<?php
}
To query posts with the custom status:
$query = new WP_Query( [
'post_type' => 'post',
'post_status' => 'approved',
] );
NOTE: Custom statuses with public => true are visible on the front end. If you only need the status for internal workflow tracking, set public => false and exclude_from_search => true.