How to Create a Custom Post Status in WordPress

Filip N. Dec 21, 2024 Custom Post Types
How can I make a new status for my posts, like 'In Review'?
What are the steps to register a custom post status in WordPress using the 'register_post_status' function and apply it to custom post types?
Andy answered Dec 21, 2024

Creating Custom Post Statuses in WordPress

Basic Implementation

Here's how to register a new 'In Review' post status:

function register_in_review_post_status() {
    register_post_status('in_review', array(
        'label'                     => _x('In Review', 'post'),
        'public'                    => true,
        'exclude_from_search'       => false,
        'show_in_admin_all_list'    => true,
        'show_in_admin_status_list' => true,
        'label_count'               => _n_noop('In Review <span class="count">(%s)</span>',
                                             'In Review <span class="count">(%s)</span>')
    ));
}
add_action('init', 'register_in_review_post_status');

Adding the Status to Post Edit Screen

To make the status available in the post editor dropdown:

function append_post_status_list() {
    global $post;
    $complete = '';
    $label = '';
    
    if($post->post_status == 'in_review'){
        $complete = ' selected="selected"';
        $label = '<span id="post-status-display">In Review</span>';
    }
    
    echo '<script>
    jQuery(document).ready(function($){
        $("select#post_status").append(\'<option value="in_review"'.$complete.'>In Review</option>\');
        $(".misc-pub-section label").append("'.$label.'");
    });
    </script>';
}
add_action('admin_footer-post.php', 'append_post_status_list');
add_action('admin_footer-post-new.php', 'append_post_status_list');

Applying to Custom Post Types

To apply the status to specific post types:

function apply_custom_status_to_cpt() {
    register_post_status('in_review', array(
        'label'                     => _x('In Review', 'post'),
        'public'                    => true,
        'exclude_from_search'       => false,
        'show_in_admin_all_list'    => true,
        'show_in_admin_status_list' => true,
        'label_count'               => _n_noop('In Review <span class="count">(%s)</span>',
                                             'In Review <span class="count">(%s)</span>'),
        'post_type'                 => array('post', 'your_custom_post_type'),
    ));
}
add_action('init', 'apply_custom_status_to_cpt');

Best Practices

  1. Always prefix your custom status names to avoid conflicts
  2. Use translatable strings for labels
  3. Consider visibility settings carefully
  4. Test status transitions thoroughly

Security Considerations

  • Add capability checks before status changes
  • Validate status transitions
  • Sanitize all inputs

Here's a security-enhanced status transition check:

function check_status_transition($new_status, $old_status, $post) {
    if ('in_review' === $new_status && !current_user_can('edit_posts')) {
        wp_die('You do not have permission to change to this status');
    }
}
add_action('transition_post_status', 'check_status_transition', 10, 3);

Common Pitfalls

  1. Not considering status visibility in queries
  2. Forgetting to update the status display in admin
  3. Not handling status transitions properly
  4. Missing capability checks

Plugin Solutions

If you prefer a plugin solution:

  1. Edit Flow (Website)

    • Offers custom statuses with workflow management
    • Includes editorial comments and notifications
  2. PublishPress (Website)

    • Advanced custom status management
    • Editorial workflow features
    • Content calendar integration

Additional Tips

  • Use post_status parameter in WP_Query to include custom statuses
  • Consider adding custom admin filters
  • Add custom colors for status labels in admin
  • Create transition hooks for status changes

CSS for styling custom status in admin:

function add_status_css() {
    echo '<style>
        .status-in_review {
            background: #f7c948;
            color: #fff;
        }
    </style>';
}
add_action('admin_head', 'add_status_css');

Remember to test thoroughly in a staging environment before implementing in production, especially when working with custom post statuses as they can affect content visibility and workflow.