Custom User role user can't be assigned in post

We created a custom user role with permissions to edit pending and draft posts, but other users when creating a new post, can't assign as an author, users that belong to this custom role. There was a similar bug reported a few years ago, although the fix is not working.
http://blog.netgloo.com/2014/05/20/assigning-user-with-custom-role-as-author-to-posts-in-wordpress/

Please advise.

  • Konstantinos Xenos

    Hi Inspired Agency ,

    Your code looks fine. There's an issue with WordPress and Custom roles that is actually ~7 years old and tracked on Core Trac. The only way to add users from custom roles at the moment into the Author lists ( so you can select any of them ) is by filtering the actual dropdown and inserting the extra users created.

    This should do the trick for you and enable all new users with custom roles to be selected from the Author dropdown.

    Simply copy / paste this following code right under your custom role creation snippets.

    Tell us if you need further assistance!

    Regards,
    Konstantinos

    function ia_get_roles( $post_type ) {
    	global $wp_roles;
    	$roles = array();
    	$type  = get_post_type_object( $post_type );
    	$caps  = array( $type->cap->edit_posts, $type->cap->publish_posts, $type->cap->create_posts );
    	$caps  = array_unique( $caps );
    	foreach ( $wp_roles->roles as $name => $role ) {
    		foreach ( $caps as $cap ) {
    			if ( isset( $role['capabilities'][ $cap ] ) && true === $role['capabilities'][ $cap ] ) {
    				$roles[] = $name;
    				break;
    			}
    		}
    	}
    	return $roles;
    }
    
    // Add a custom filter to the user dropdown
    function ia_user_dropdown_filter() {
    	add_filter( 'wp_dropdown_users_args', 'ia_dropdown_users_args', 10, 2 );
    }
    
    function ia_dropdown_users_args( $args, $r ) {
    	global $wp_roles, $post;
    	$roles = ia_get_roles( $post->post_type );
    	if ( $roles ) {
    		$args['who']      = '';
    		$args['role__in'] = $roles;
    	}
    	return $args;
    }
    
    add_action( 'load-post.php', 'ia_user_dropdown_filter' );
    add_action( 'load-post-new.php', 'ia_user_dropdown_filter' );
  • Inspired Agency

    Hi, Thank you for this!

    I've added it to my code, but for some reason I can't seem to see the author on custom post types, but I can on posts?

    My code is as follows;

    ///////////////////////////////////
    // Adding new user for draft pages
    ///////////////////////////////////
    // Add custom role Testrole
    add_role('testrole', 'Testrole', array(
    	'read'                    => true, // Allows access to Dashboard, Your Profile
    	'level_1' => true,
    	// Capabilities for Posts
    	'publish_posts'           => false,
    	'edit_posts'              => true, // Allows access to Posts, Comments
    	'edit_published_posts'    => false,
    	'delete_posts'            => false,
    	'delete_published_posts'  => false,
    	// Capabilities for Pages
    	'publish_pages'           => false,
    	'edit_pages'              => false, // Allows access to Pages
    	'edit_published_pages'    => false,
    	'delete_pages'            => false,
    	'delete_published_pages'  => false,
    
    	)
      );
      //Hide published pages for the TestRole
      function posts_for_current_author($query) {
      global $user_level;
    
      if($query->is_admin && $user_level <= 7) { // Valid for all users except the administrators
    	global $user_ID;
    	$query->set('author', $user_ID);
    	unset($user_ID);
      }
      unset($user_level);
    
      return $query;
      }
      add_filter('pre_get_posts', 'posts_for_current_author');
    
      //Hide Pages menus for testrole
      function remove_menus(){
    	if ( current_user_can( 'testrole' ) ) {
    		remove_menu_page( 'edit.php?post_type=page' );    //Pages
    		?>
    		<style>
    		  .page-title-action {
    			 display:none;
    		  }
    		  ul.wp-submenu.wp-submenu-wrap {
    			display: none;
    		  }
    		</style>
    		<?php
    
    	}
    	add_action( 'admin_head', function() {
    
    	});
      }
    
      add_action( 'admin_menu', 'remove_menus' );
    
      // Filter new users with custom roles to be added into the author transfer list. This is to fix a glitch older than 7 years old on WP.
      function ia_get_roles( $post_type ) {
    	global $wp_roles;
    	$roles = array();
    	$type  = get_post_type_object( $post_type );
    	$caps  = array( $type->cap->edit_posts, $type->cap->publish_posts, $type->cap->create_posts );
    	$caps  = array_unique( $caps );
    	foreach ( $wp_roles->roles as $name => $role ) {
    		foreach ( $caps as $cap ) {
    			if ( isset( $role['capabilities'][ $cap ] ) && true === $role['capabilities'][ $cap ] ) {
    				$roles[] = $name;
    				break;
    			}
    		}
    	}
    	return $roles;
    }
    
    // Add a custom filter to the user dropdown
    function ia_user_dropdown_filter() {
    	add_filter( 'wp_dropdown_users_args', 'ia_dropdown_users_args', 10, 2 );
    }
    
    function ia_dropdown_users_args( $args, $r ) {
    	global $wp_roles, $post;
    	$roles = ia_get_roles( $post->post_type );
    	if ( $roles ) {
    		$args['who']      = '';
    		$args['role__in'] = $roles;
    	}
    	return $args;
    }
    
    add_action( 'load-post.php', 'ia_user_dropdown_filter' );
    add_action( 'load-post-new.php', 'ia_user_dropdown_filter' );
  • Konstantinos Xenos

    Hi again Inspired Agency ,

    I just did a copy/paste of the code you mentioned in my functions as well as adding some custom post types and worked without any issues.

    Could you share your CPT code also so I can give it a look? Maybe there's an issue there that might not be adding correct capabilities or something else needed for the role to work properly. Without the code though it's hard to imagine what could it be.

    Regards,
    Konstantinos

  • Inspired Agency

    Hi again,

    CPT code attached, it is strange, i thought it should work too. Appreciate the help!

    // Register Custom Post Type
    	function custom_post_type() {
    
    		$labels = array(
    			'name'                => _x( 'Products', 'Post Type General Name', 'text_domain' ),
    			'singular_name'       => _x( 'Product', 'Post Type Singular Name', 'text_domain' ),
    			'menu_name'           => __( 'Products', 'text_domain' ),
    			'parent_item_colon'   => __( 'Parent Item:', 'text_domain' ),
    			'all_items'           => __( 'All Items', 'text_domain' ),
    			'view_item'           => __( 'View Item', 'text_domain' ),
    			'add_new_item'        => __( 'Add New Product', 'text_domain' ),
    			'add_new'             => __( 'Add New', 'text_domain' ),
    			'edit_item'           => __( 'Edit Product', 'text_domain' ),
    			'update_item'         => __( 'Update Product', 'text_domain' ),
    			'search_items'        => __( 'Search Item', 'text_domain' ),
    			'not_found'           => __( 'Not found', 'text_domain' ),
    			'not_found_in_trash'  => __( 'Not found in Trash', 'text_domain' ),
    		);
    
    		$rewrite = array(
    			'slug'                => '',
    			'with_front'          => false,
    			'pages'               => true,
    			'feeds'               => true,
    		);
    
    		$args = array(
    			'label'               => __( 'products', 'text_domain' ),
    			'description'         => __( 'IDS Products', 'text_domain' ),
    			'labels'              => $labels,
    			'supports'            => array( 'title', 'editor', 'thumbnail', 'revisions', 'page-attributes', 'post-formats', 'author' ),
    			'taxonomies'          => array(),
    			'hierarchical'        => true,
    			'public'              => true,
    			'show_ui'             => true,
    			'show_in_menu'        => true,
    			'show_in_nav_menus'   => true,
    			'show_in_admin_bar'   => true,
    			'menu_position'       => 5,
    			'can_export'          => true,
    			'has_archive'         => true,
    			'exclude_from_search' => false,
    			'publicly_queryable'  => true,
    			'rewrite'             => $rewrite,
    			'capability_type'     => 'page',
    		);
    		register_post_type( 'products', $args );
    
    		$labels = array(
    			'name'                => _x( 'Vacancies', 'Post Type General Name', 'text_domain' ),
    			'singular_name'       => _x( 'Vacancy', 'Post Type Singular Name', 'text_domain' ),
    			'menu_name'           => __( 'Vacancies', 'text_domain' ),
    			'parent_item_colon'   => __( 'Parent Item:', 'text_domain' ),
    			'all_items'           => __( 'All Items', 'text_domain' ),
    			'view_item'           => __( 'View Item', 'text_domain' ),
    			'add_new_item'        => __( 'Add New Vacancy', 'text_domain' ),
    			'add_new'             => __( 'Add New', 'text_domain' ),
    			'edit_item'           => __( 'Edit Vacancy', 'text_domain' ),
    			'update_item'         => __( 'Update Vacancy', 'text_domain' ),
    			'search_items'        => __( 'Search Item', 'text_domain' ),
    			'not_found'           => __( 'Not found', 'text_domain' ),
    			'not_found_in_trash'  => __( 'Not found in Trash', 'text_domain' ),
    		);
    
    		$rewrite = array(
    			'slug'                => '',
    			'with_front'          => false,
    			'pages'               => true,
    			'feeds'               => true,
    		);
    
    		$args = array(
    			'label'               => __( 'Vacancies', 'text_domain' ),
    			'description'         => __( 'IDS Vacancies', 'text_domain' ),
    			'labels'              => $labels,
    			'supports'            => array( 'title', 'editor', 'thumbnail', 'revisions', 'page-attributes', 'post-formats', 'author' ),
    			'taxonomies'          => array(),
    			'hierarchical'        => true,
    			'public'              => true,
    			'show_ui'             => true,
    			'show_in_menu'        => true,
    			'show_in_nav_menus'   => true,
    			'show_in_admin_bar'   => true,
    			'menu_position'       => 5,
    			'can_export'          => true,
    			'has_archive'         => true,
    			'exclude_from_search' => false,
    			'publicly_queryable'  => true,
    			'rewrite'             => $rewrite,
    			'capability_type'     => 'page',
    		);
    		register_post_type( 'vacancies', $args );
    
    	}
    
    	// Hook into the 'init' action
    	add_action( 'init', 'custom_post_type', 0 );
  • Konstantinos Xenos

    Hey !

    You have your CPTs set as " 'capability_type' => 'page' " if you change that to "post" everything should be working. As far as I'm concerned if you don't want to have them as posts you'll have to declare your own custom capabilities as well, for example edit_posts would become edit_vacancies , so on so forth. It's way easier though to just add the 'post' capabilities as they're already in there :slight_smile:.

    Regards,
    Konstantinos

  • Inspired Agency

    Hi again,

    That did work, it now shows the author!

    Last issue i'm having! When I am logged in as an administrator, and make a post or a CPT a draft and change the author to my new account, it now shows in the new accounts CMS which is great.

    Issue is - on the new account, none of the ACF (advanced custom fields) show, so they technically can't edit the page. Also, when you go to publish, you instead get a 'Submit to review' (See attached).

    Do you have any idea how to change this? It's the last thing and it's all fixed! You's have been such a help!

  • Konstantinos Xenos

    Hey Inspired Agency , I think that your database must still have some wrong values from all the tests and changes that haven't been updated.

    I'm attaching 2 screenshots and the full code I'm using, you'll see that ACF works as expected on 'testusr' and he can also Publish without a problem, this is on a clean WP install with only the code included in functions.php and ACF installed.

    If you're still having issues the only easy way of 'cleaning' up the caps in the database that I can think of ( instead of re-installing a fresh WordPress ) is to install the "User Role Editor" plugin that is actively maintained and go through the capabilities of Testrole to see what hasn't been read or updated, or even just set it all up from there.

    <?php
    
    // Register Custom Post Type
    function custom_post_types() {
    
    	$args = array(
    		'label'               => __( 'products', 'text_domain' ),
    		'description'         => __( 'IDS Products', 'text_domain' ),
    		'labels'              => array(
    			'name'               => _x( 'Products', 'Post Type General Name', 'text_domain' ),
    			'singular_name'      => _x( 'Product', 'Post Type Singular Name', 'text_domain' ),
    			'menu_name'          => __( 'Products', 'text_domain' ),
    			'parent_item_colon'  => __( 'Parent Item:', 'text_domain' ),
    			'all_items'          => __( 'All Items', 'text_domain' ),
    			'view_item'          => __( 'View Item', 'text_domain' ),
    			'add_new_item'       => __( 'Add New Product', 'text_domain' ),
    			'add_new'            => __( 'Add New', 'text_domain' ),
    			'edit_item'          => __( 'Edit Product', 'text_domain' ),
    			'update_item'        => __( 'Update Product', 'text_domain' ),
    			'search_items'       => __( 'Search Item', 'text_domain' ),
    			'not_found'          => __( 'Not found', 'text_domain' ),
    			'not_found_in_trash' => __( 'Not found in Trash', 'text_domain' ),
    		),
    		'supports'            => array(
    			'title',
    			'editor',
    			'thumbnail',
    			'revisions',
    			'page-attributes',
    			'post-formats',
    			'author',
    		),
    		'taxonomies'          => array(),
    		'hierarchical'        => true,
    		'public'              => true,
    		'show_ui'             => true,
    		'show_in_menu'        => true,
    		'show_in_nav_menus'   => true,
    		'show_in_admin_bar'   => true,
    		'menu_position'       => 5,
    		'can_export'          => true,
    		'has_archive'         => true,
    		'exclude_from_search' => false,
    		'publicly_queryable'  => true,
    		'rewrite'             => array(
    			'slug'       => '',
    			'with_front' => false,
    			'pages'      => true,
    			'feeds'      => true,
    		),
    		'capability_type'     => 'post',
    	);
    	register_post_type( 'products', $args );
    
    	$args = array(
    		'label'               => __( 'Vacancies', 'text_domain' ),
    		'description'         => __( 'IDS Vacancies', 'text_domain' ),
    		'labels'              => array(
    			'name'               => _x( 'Vacancies', 'Post Type General Name', 'text_domain' ),
    			'singular_name'      => _x( 'Vacancy', 'Post Type Singular Name', 'text_domain' ),
    			'menu_name'          => __( 'Vacancies', 'text_domain' ),
    			'parent_item_colon'  => __( 'Parent Item:', 'text_domain' ),
    			'all_items'          => __( 'All Items', 'text_domain' ),
    			'view_item'          => __( 'View Item', 'text_domain' ),
    			'add_new_item'       => __( 'Add New Vacancy', 'text_domain' ),
    			'add_new'            => __( 'Add New', 'text_domain' ),
    			'edit_item'          => __( 'Edit Vacancy', 'text_domain' ),
    			'update_item'        => __( 'Update Vacancy', 'text_domain' ),
    			'search_items'       => __( 'Search Item', 'text_domain' ),
    			'not_found'          => __( 'Not found', 'text_domain' ),
    			'not_found_in_trash' => __( 'Not found in Trash', 'text_domain' ),
    		),
    		'supports'            => array(
    			'title',
    			'editor',
    			'thumbnail',
    			'revisions',
    			'page-attributes',
    			'post-formats',
    			'author',
    		),
    		'taxonomies'          => array(),
    		'hierarchical'        => true,
    		'public'              => true,
    		'show_ui'             => true,
    		'show_in_menu'        => true,
    		'show_in_nav_menus'   => true,
    		'show_in_admin_bar'   => true,
    		'menu_position'       => 5,
    		'can_export'          => true,
    		'has_archive'         => true,
    		'exclude_from_search' => false,
    		'publicly_queryable'  => true,
    		'rewrite'             => array(
    			'slug'       => '',
    			'with_front' => false,
    			'pages'      => true,
    			'feeds'      => true,
    		),
    		'capability_type'     => 'post',
    	);
    	register_post_type( 'vacancies', $args );
    
    }
    add_action( 'init', 'custom_post_types', 0 );
    
    // Add custom role Testrole
    add_role( 'testrole', 'Testrole', array(
    	'read'                   => true, // Allows access to Dashboard, Your Profile
    	// Capabilities for Posts
    	'publish_posts'          => true,
    	'edit_posts'             => true,
    	'edit_published_posts'   => true,
    	'delete_posts'           => false,
    	'delete_published_posts' => false,
    	// Capabilities for Pages
    	'publish_pages'          => false,
    	'edit_pages'             => true,
    	'edit_published_pages'   => false,
    	'delete_pages'           => false,
    	'delete_published_pages' => false,
    ));
    
    function ia_get_roles( $post_type ) {
    	global $wp_roles;
    	$roles = array();
    	$type  = get_post_type_object( $post_type );
    	$caps  = array(
    		$type->cap->edit_posts,
    		$type->cap->edit_published_posts,
    		$type->cap->publish_posts,
    		$type->cap->create_posts,
    	);
    	$caps  = array_unique( $caps );
    	foreach ( $wp_roles->roles as $name => $role ) {
    		foreach ( $caps as $cap ) {
    			if ( isset( $role['capabilities'][ $cap ] ) && true === $role['capabilities'][ $cap ] ) {
    				$roles[] = $name;
    				break;
    			}
    		}
    	}
    	return $roles;
    }
    
    // Add a custom filter to the user dropdown
    function ia_user_dropdown_filter() {
    	add_filter( 'wp_dropdown_users_args', 'ia_dropdown_users_args', 10, 2 );
    }
    
    function ia_dropdown_users_args( $args, $r ) {
    	global $wp_roles, $post;
    	$roles = ia_get_roles( $post->post_type );
    	if ( $roles ) {
    		$args['who']      = '';
    		$args['role__in'] = $roles;
    	}
    	return $args;
    }
    
    add_action( 'load-post.php', 'ia_user_dropdown_filter' );
    add_action( 'load-post-new.php', 'ia_user_dropdown_filter' );

    Best regards,
    Konstantinos

  • Inspired Agency

    Hi again,

    So - The code you supplied works, but misses a fair bit from the original code.

    One of the main issues is the only viewing draft pages:
    //Hide published pages for the TestRole
    function posts_for_current_author($query) {
    global $user_level;

    if($query->is_admin && $user_level <= 7) { // Valid for all users except the administrators
    global $user_ID;
    $query->set('author', $user_ID);
    unset($user_ID);
    }
    unset($user_level);

    return $query;
    }
    add_filter('pre_get_posts', 'posts_for_current_author');

    When this is added to your code, we can't see the ACFs or the Send for approval button, but we see publish. Without this code, everything works great except the only seeing draft pages.

    Any ideas?

    Thanks!

  • Konstantinos Xenos

    If you remove $query->set('author', $user_ID); the end result is:

    A Testrole user can only see / edit the posts assigned to him ( Draft, Published, Scheduled ) and will have access to ACF fields.

    Is this what you're trying to achieve? I'm a bit confused now with what this Testrole should be able to do and what should he have access to.

    If you only want them to edit Draft posts, I'm not sure if there's a way with this customization since they're already the Authors so basically have access to all options of the posts assigned to them.

    Regards,
    Konstantinos

Thank NAME, for their help.

Let NAME know exactly why they deserved these points.

Gift a custom amount of points.