Evaluating plugins
A client has the requirement to customize menu options by user role. Before writing the functionality myself I try to find and evaluate plugins in the WordPress repository which might fit my need.
Guidelines
So, which guidelines do I use to evaluate plugins:
- Clean code
- UI implementation
- Recently updated, or at least bumped version compatibility
- No stripped plugins in favour of “Pro” versions
- No Freemius implementation
Available plugins
After digging around I came across the following plugins:
- User Menus
- Nav Menu Roles
- If Menu
- Menu By User Roles
Let’ s evaluate these plugins based on above guidelines like codebase, UI, functionality and distribution model.

Plugin: User Menus
Pros
- Ability to add
{text}
tags to menu
Cons
- Freemius intergration
- Not updated for over a year
- Bulky codebase
- UI when many roles available
Link to WordPress Plugin
Plugin: Nav Menu Roles
Pros
- Does what it is designed for
- Donate based model
Cons
- Bulky codebase
- UI when many roles available
Link to WordPress Plugin


Plugin: If Menu
Pros
- Minimalist UI, but it stands out due to its background and colors choices
Cons
- Not updated for over 6 months
- “Pro” version available
- Bulky codebase (composer packages)
- Lot of custom javascript
Link to WordPress Plugin
Plugin: Menu By User Roles
Pros
- Very nice minimalist UI
- Extemely lean codebase
Cons
- None!
Link to WordPress Plugin.

Conclusion
Clearly the winner is Menu By User Roles plugin! It is ahead by miles in each category. Kudos to the developer by keeping his eye on the functionality required.
What strikes me is that all the other plugins use a form of menu walkers to achieve the goal. While the Menu By User Roles plugin uses the wp_nav_menu_objects
filter. Said filter is much more efficient and elegant.
Code example
I can not stress enough how lean the codebase is. Only four tiny hooks and filters are used to provide the functionality we require! Because the code is so clean I will list it below.
/**
* Enqueue Select2 scripts and styles for the menu.
*/
function menuby_user_roles_enqueue_select2() {
$screen = get_current_screen();
if ( 'nav-menus' === $screen->id ) {
wp_enqueue_style( 'menuby-user-roles-select2-style', plugins_url( 'assets/css/select2.min.css', __FILE__ ), array(), MBUR_PLUGIN_VERSION );
wp_enqueue_script( 'menuby-user-roles-select2-script', plugins_url( 'assets/js/select2.min.js', __FILE__ ), array( 'jquery' ), MBUR_PLUGIN_VERSION, true );
wp_enqueue_script( 'menuby-user-roles-main-script', plugins_url( 'assets/js/main.js', __FILE__ ), array( 'jquery' ), MBUR_PLUGIN_VERSION, true );
}
}
add_action( 'admin_enqueue_scripts', 'menuby_user_roles_enqueue_select2' );
/**
* Render a custom user role selection field for a menu item.
*
* @param int $item_id Menu item ID.
*/
function menuby_user_roles_wp_menu_item_user_role_section( $item_id ) {
$selected_roles = get_post_meta( $item_id, '_wp_menu_item_user_roles', true );
$roles = get_editable_roles();
echo '<p class="field-wp-user-roles description description-wide">';
echo '<label for="edit-menu-item-user-role-' . esc_attr( $item_id ) . '">';
echo 'Choose User Roles <br/>';
echo '<select style="width: 100%" multiple="multiple" class="widefat menuby-user-roles-dropdown" name="menuby_user_roles_menu_item_roles[' . esc_attr( $item_id ) . '][]" id="wp-mbur-menu-item-roles-' . esc_attr( $item_id ) . '">';
// Predefined options.
echo '<option value="all" ' . ( empty( $selected_roles ) || ( is_array( $selected_roles ) && in_array( 'all', $selected_roles, true ) ) ? 'selected' : '' ) . '>All</option>';
echo '<option value="unauthenticated" ' . ( is_array( $selected_roles ) && in_array( 'unauthenticated', $selected_roles, true ) ? 'selected' : '' ) . '>Unauthenticated</option>';
// User roles.
foreach ( $roles as $role_key => $role ) {
$selected = ( is_array( $selected_roles ) && in_array( $role_key, $selected_roles, true ) ) ? 'selected' : '';
echo '<option value="' . esc_attr( $role_key ) . '" ' . esc_attr( $selected ) . '>' . esc_html( $role['name'] ) . '</option>';
}
echo '</select>';
// Add nonce field to the form.
wp_nonce_field( 'menuby_user_roles_nonce_action', 'menuby_user_roles_nonce' );
echo '</label></p>';
}
add_action( 'wp_nav_menu_item_custom_fields', 'menuby_user_roles_wp_menu_item_user_role_section', 10, 2 );
/**
* Save user role data for a menu item.
*
* @param int $menu_id Menu ID.
* @param int $menu_item_db_id Menu item ID.
*/
function menuby_user_roles_save_menu_item_user_role_data( $menu_id, $menu_item_db_id ) {
if ( ! isset( $_POST['menuby_user_roles_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['menuby_user_roles_nonce'] ) ), 'menuby_user_roles_nonce_action' ) ) {
return;
}
$selected_roles = isset( $_POST['menuby_user_roles_menu_item_roles'][ $menu_item_db_id ] )
? array_filter( array_unique( array_map( 'sanitize_text_field', wp_unslash( $_POST['menuby_user_roles_menu_item_roles'][ $menu_item_db_id ] ) ) ) )
: '';
update_post_meta( $menu_item_db_id, '_wp_menu_item_user_roles', $selected_roles );
}
add_action( 'wp_update_nav_menu_item', 'menuby_user_roles_save_menu_item_user_role_data', 10, 2 );
/**
* Filter menu items for display on the front end based on user roles.
*
* @param array $items Menu items.
* @return array Filtered menu items.
*/
function menuby_user_roles_filter_menu_items( $items ) {
$user = wp_get_current_user();
$allowed_items = array();
foreach ( $items as $item ) {
$item_id = $item->ID;
$selected_roles = get_post_meta( $item_id, '_wp_menu_item_user_roles', true );
if (
! is_array( $selected_roles ) ||
( in_array( 'all', $selected_roles, true ) ) ||
( in_array( 'unauthenticated', $selected_roles, true ) && ! is_user_logged_in() ) ||
( is_user_logged_in() && array_intersect( $selected_roles, $user->roles ) )
) {
$allowed_items[] = $item;
}
}
return $allowed_items;
}
add_filter( 'wp_nav_menu_objects', 'menuby_user_roles_filter_menu_items' );
Thanks for reading! Please like this post if it was of any use to you.