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
- Always prefix your custom status names to avoid conflicts
- Use translatable strings for labels
- Consider visibility settings carefully
- 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
- Not considering status visibility in queries
- Forgetting to update the status display in admin
- Not handling status transitions properly
- Missing capability checks
Plugin Solutions
If you prefer a plugin solution:
-
Edit Flow (Website)
- Offers custom statuses with workflow management
- Includes editorial comments and notifications
-
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.