What if you want to show hidden information only to “administrators” or “shop managers?” What about displaying a custom “My Account” tab just for logged-in customers?
Running functions based on user roles by using conditional logic is a common part of WooCommerce customization.
What if you want to show hidden information only to “administrators” or “shop managers?” What about displaying a custom “My Account” tab just for logged-in customers?
Well, wc_current_user_has_role
allows us to check just that: what role group does the logged-in user belong to.
WordPress has six pre-defined roles: Super Admin, Administrator, Editor, Author, Contributor, and Subscriber. WooCommerce adds another two: Shop Manager and Customer. Other plugins may add more. You can theoretically create any number of user roles. Each role is allowed to perform a defined set of tasks called capabilities.
As usual, we’ll study the WooCommerce core function code for wc_current_user_has_role
, see where and why it’s used, and finally, we’ll cover a quick case study. Enjoy!
Function code
The wc_current_user_has_role
function can be found under \woocommerce\includes\wc-user-functions.php
:
/**
* Checks if the current user has a role.
*
* @param string $role The role.
* @return bool
*/
function wc_current_user_has_role( $role ) {
return wc_user_has_role( wp_get_current_user(), $role );
}
The function just returns the result of the wc_user_has_role
function for the logged-in user. This additional function can be found in the same file as wc_current_user_has_role
:
/**
* Checks if a user has a role.
*
* @param int|\WP_User $user The user.
* @param string $role The role.
* @return bool
*/
function wc_user_has_role( $user, $role ) {
if ( ! is_object( $user ) ) {
$user = get_userdata( $user );
}
if ( ! $user || ! $user->exists() ) {
return false;
}
return in_array( $role, $user->roles, true );
}
In a nutshell, wc_user_has_role
checks if a $user
object exists, and if it does, it checks the $role
passed to it against the current list of user roles to see if there’s a match. That’s it.
Function usage
Want to know if the current user is an Administrator? Simple!
if ( wc_current_user_has_role( 'administrator' ) ) {
// do something
}
The same applies to the other roles. The slugs you can use in the wc_current_user_has_role
function are:
'administrator'
'editor'
'author'
'contributor'
'subscriber'
'shop_manager'
'customer'
If you want to know if the current user is in a specific role group — for example, a WooCommerce Shop Manager — you would check this way:
if ( wc_current_user_has_role( 'shop_manager' ) ) {
// do something
}
Now, for a bit of context. If we do a file search for wc_current_user_has_role
inside the WooCommerce plugin code, we’re able to understand where and when it’s used. There are four main results, all inside \woocommerce\includes\wc-user-functions.php
:
/**
* Modify the list of editable roles to prevent non-admin adding admin users.
*
* @param array $roles Roles.
* @return array
*/
function wc_modify_editable_roles( $roles ) {
if ( is_multisite() && is_super_admin() ) {
return $roles;
}
if ( ! wc_current_user_has_role( 'administrator' ) ) {
unset( $roles['administrator'] );
if ( wc_current_user_has_role( 'shop_manager' ) ) {
$shop_manager_editable_roles = apply_filters( 'woocommerce_shop_manager_editable_roles', array( 'customer' ) );
return array_intersect_key( $roles, array_flip( $shop_manager_editable_roles ) );
}
}
return $roles;
}
add_filter( 'editable_roles', 'wc_modify_editable_roles' );
The wc_modify_editable_roles
function clearly defines who can “add/edit specific user roles.” Because WooCommerce adds users to the Shop Manager and Customer role groups, this function makes sure that if the current user is not an Administrator ( ! wc_current_user_has_role( 'administrator' )
) they can’t add Administrators. (This is for the new Customer and Shop Manager roles.) Also, if the logged-in user is a Shop Manager (wc_current_user_has_role( 'shop_manager' )
), they can add/edit customers!
Similarly, wc_current_user_has_role
is used a few lines below by wc_modify_map_meta_cap
:
/**
* Modify capabilities to prevent non-admin users editing admin users.
*
* $args[0] will be the user being edited in this case.
*
* @param array $caps Array of caps.
* @param string $cap Name of the cap we are checking.
* @param int $user_id ID of the user being checked against.
* @param array $args Arguments.
* @return array
*/
function wc_modify_map_meta_cap( $caps, $cap, $user_id, $args ) {
if ( is_multisite() && is_super_admin() ) {
return $caps;
}
switch ( $cap ) {
case 'edit_user':
case 'remove_user':
case 'promote_user':
case 'delete_user':
if ( ! isset( $args[0] ) || $args[0] === $user_id ) {
break;
} else {
if ( ! wc_current_user_has_role( 'administrator' ) ) {
if ( wc_user_has_role( $args[0], 'administrator' ) ) {
$caps[] = 'do_not_allow';
} elseif ( wc_current_user_has_role( 'shop_manager' ) ) {
// Shop managers can only edit customer info.
$userdata = get_userdata( $args[0] );
$shop_manager_editable_roles = apply_filters( 'woocommerce_shop_manager_editable_roles', array( 'customer' ) );
if ( property_exists( $userdata, 'roles' ) && ! empty( $userdata->roles ) && ! array_intersect( $userdata->roles, $shop_manager_editable_roles ) ) {
$caps[] = 'do_not_allow';
}
}
}
}
break;
}
return $caps;
}
add_filter( 'map_meta_cap', 'wc_modify_map_meta_cap', 10, 4 );
Once again, this function dictates what Shop Managers can and cannot do with regard to capabilities. This is a little more complex than the previous function so let’s see some case studies that illustrate how it can be used.
WooCommerce case studies
We often need to check the logged-in user role when our shop applies different rules:
- at checkout (payment gateways by role)
- at the product level (price by role)
- at the shop level (toggle categories by role)
- …and so on
Let’s start with the first example — how can we enable a payment gateway just for logged-in customers?
I already have a PayPal toggle snippet on Business Bloomer — however, I use current_user_can
and not wc_current_user_has_role
, so let’s write a new version. Let’s check for a “cheque” gateway:
/**
* @snippet Enable cheque for logged in customers only
* @how-to Get CustomizeWoo.com FREE
* @author Rodolfo Melogli
* @compatible WooCommerce 6
* @donate $9 https://businessbloomer.com/bloomer-armada/
*/
add_filter( 'woocommerce_available_payment_gateways', 'bbloomer_enable_cheque_customers' );
function bbloomer_enable_cheque_customers( $available_gateways ) {
if ( isset( $available_gateways['cheque'] ) && ! wc_current_user_has_role( 'customer' ) ) {
unset( $available_gateways['cheque'] );
}
return $available_gateways;
}
Yes, in order to “enable” a gateway just for customers, I “disable” (unset) it for all non-customers.
One more example?
Let’s apply a discount to logged-in subscribers.
WooCommerce Subscriptions uses the default Subscriber role when a WooCommerce Customer purchases a subscription. Their goes back to “Customer” when the subscription expires/is cancelled)
/**
* @snippet 20% discount logged in subscribers only
* @how-to Get CustomizeWoo.com FREE
* @author Rodolfo Melogli
* @compatible WooCommerce 6
* @donate $9 https://businessbloomer.com/bloomer-armada/
*/
add_action( 'woocommerce_before_calculate_totals', 'bbloomer_alter_price_cart_subscribers', 9999 );
function bbloomer_alter_price_cart_subscribers( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 ) return;
// IF SUBSCRIBER NOT LOGGED IN, DONT APPLY DISCOUNT
if ( ! wc_current_user_has_role( 'subscriber' ) ) return;
// LOOP THROUGH CART ITEMS & APPLY 20% DISCOUNT
foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
$product = $cart_item['data'];
$price = $product->get_price();
$cart_item['data']->set_price( $price * 0.80 );
}
}
No screenshots this week as I’m getting ready for WCEU 2022 and am short on time — hope to see you there!
Rodolfo Melogli is an author, WooCommerce expert, and WordCamp speaker, Rodolfo has worked as an independent WooCommerce freelancer since 2011. He teaches WooCommerce development at Business Bloomer.