[]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 woocommerceincludeswc-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 woocommerceincludeswc-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
[]Author, WooCommerce expert and WordCamp speaker, Rodolfo has worked as an independent WooCommerce freelancer since 2011.