Correcting the author meta box drop-down
If you’ve ever created a custom role with a role management plugin such as Members, you’ve probably run into the issue of users with that role not showing up in the post author drop-down. This is a pretty common occurrence and is a 5-year-old bug in WordPress that has yet to be fixed.
My recent Members – Role Levels plugin fixes the issue by using the deprecated user levels system, which is what WordPress currently relies on.
My Avatars Meta Box plugin also corrects this issue in a different way for WordPress 4.4 users.
If you’re a plugin developer and creating custom post types that rely on the author drop-down, you’re out of luck if your users aren’t using one of those two plugins. However, I have a quick bit of code that I want to share that will fix this for you.
My hope is that we can iterate on this idea and possibly get it pushed into core.
Why this is now possible to fix
Prior to WordPress 4.4, it was pretty tough to actually work around this particular issue without doing multiple user queries or doing a custom database query yourself rather than using the APIs available through WordPress.
The new role__in
argument for the get_users()
function or WP_User_Query()
class is what’s going to make this possible. This argument is only available in WordPress 4.4 and allows multiple roles to be used in the user query.
Why roles? We can query all users who have roles with permission to edit the specific post type.
Getting roles with permission
The first step is writing a custom function to get all roles that have permission to edit, create, or publish posts of a specific post type.
function th_get_roles_for_post_type( $post_type ) {
global $wp_roles;
$roles = array();
$type = get_post_type_object( $post_type );
// Get the post type object caps.
$caps = array( $type->cap->edit_posts, $type->cap->publish_posts, $type->cap->create_posts );
$caps = array_unique( $caps );
// Loop through the available roles.
foreach ( $wp_roles->roles as $name => $role ) {
foreach ( $caps as $cap ) {
// If the role is granted the cap, add it.
if ( isset( $role['capabilities'][ $cap ] ) && true === $role['capabilities'][ $cap ] ) {
$roles[] = $name;
break;
}
}
}
return $roles;
}
Filtering the author drop-down
Now that we can get the correct roles, we can filter the user drop-down and only get users with specific roles.
We also only want to do this for our post type, so make sure to change the two instances of your_post_type
to the actual name of your post type in the code.
add_action( 'load-post.php', 'th_load_user_dropdown_filter' );
add_action( 'load-post-new.php', 'th_load_user_dropdown_filter' );
function th_load_user_dropdown_filter() {
$screen = get_current_screen();
if ( empty( $screen->post_type ) || 'your_post_type' !== $screen->post_type )
return;
add_filter( 'wp_dropdown_users_args', 'th_dropdown_users_args', 10, 2 );
}
function th_dropdown_users_args( $args, $r ) {
global $wp_roles, $post;
// Check that this is the correct drop-down.
if ( 'post_author_override' === $r['name'] && 'your_post_type' === $post->post_type ) {
$roles = th_get_roles_for_post_type( $post->post_type );
// If we have roles, change the args to only get users of those roles.
if ( $roles ) {
$args['who'] = '';
$args['role__in'] = $roles;
}
}
return $args;
}
4 Comments
Thanks! I created my own hack for this (involving custom fields – not ideal). I thought I might shift to using your Members Role Levels plugin, as Members is baked into everything I do anyway.
But now this! Have to say, you must be the first plugin author to post a free alternate solution to an issue so soon after releasing your first commercial plugin that solves the same issue 🙂
Are there any differences here? I’m most interested in future-compatibility. Presumably sites using either Members Role Levels plugin or this code would be fine whatever is eventually used in core? I guess it’s all just interface stuff, with a single user ID stored in the data.
Members – Role Levels works with the current core WordPress method for handling this. The core method relies on a feature that core itself deprecated in version 2.1 (yes, 2.1), which is the user levels system.
The one major difference is that the post author drop-down fix is more of a byproduct of the plugin. Really, it allows you to assign the old, deprecated user levels. It’s just that the only issue with user levels in core just so happens to be the post author drop-down. However, it could potentially solve issues with other plugins if they’re still relying user levels for whatever reason.
The method in this tutorial is the direction I’d like to see core go into in the future. It’s an actual long-term fix for the post author drop-down. To me, this is the ideal method for handling things. This method, if it made it into the core code, would actually make Members – Role Levels and any user levels obsolete.
Both methods would essentially accomplish the same goal. Both are forward-compatible. Like you said, it’s really just changing the interface as far as the average end user is concerned.
Just got round to trying this – works great, thanks! A small correction:
add_filter( 'wp_dropdown_users_args', 'th_dropdown_users_args' );
Should read:
add_filter( 'wp_dropdown_users_args', 'th_dropdown_users_args', 10, 2 );
Thanks. I corrected it in the post.
Comments are closed.