Posted on 6 Comments

How to Hide Products by User Role in WooCommerce with PHP

Sometimes you need to hide a product or make it non-purchasable depending on the visitor’s user role, for example, make all products non-purchasable for not logged users, i.e. “guests”. You can use a plugin for that or add a PHP snippet to your (child) theme’s functions.php file.

There is a number of ways we can make product non-purchasable or hide it from the shop:

In addition we can also:

First of all, we will need functions to determine if we need to hide a product for the current user’s role.

if ( ! function_exists( 'wpf_is_current_user_role' ) ) {
    /**
     * Checks current user's role. Handles multiple roles per user.
     */
    function wpf_is_current_user_role( $roles_to_check ) {
        $current_user       = wp_get_current_user();
        $current_user_roles = ( empty( $current_user->roles ) ? array( '' ) : $current_user->roles );
        $roles_intersect    = array_intersect( $current_user_roles, $roles_to_check );
        return ( ! empty( $roles_intersect ) );
    }
}
if ( ! function_exists( 'wpf_do_hide_product' ) ) {
    /**
     * Checks if the product needs to be hidden.
     */
    function wpf_do_hide_product( $product_id_to_check ) {

        // TODO: You need to replace product IDs & user roles with your own here.
        $products_to_hide  = array( 100, 150 );       // product IDs
        $roles_to_hide_for = array( '', 'customer' ); // empty string is for the "guest" user role

        // Check if the product must be hidden.
        return (
            in_array( $product_id_to_check, $products_to_hide ) && // product ID match
            wpf_is_current_user_role( $roles_to_hide_for )         // user role match
        );
    }
}

Hiding products from the catalog

To hide products from the catalog we can use woocommerce_product_is_visible filter. This will hide selected products in shop and search results. However, the products still will be accessible via direct link.

Before After
How to hide products by user role in WooCommerce - Catalog - Before How to hide products by user role in WooCommerce - Catalog - After
add_filter( 'woocommerce_product_is_visible', 'wpf_product_visible_by_user_role', PHP_INT_MAX, 2 );
if ( ! function_exists( 'wpf_product_visible_by_user_role' ) ) {
    /**
     * Hides product from shop and search results by user role.
     */
    function wpf_product_visible_by_user_role( $visible, $product_id ) {
        return ( wpf_do_hide_product( $product_id ) ? false : $visible );
    }
}

Making products non-purchasable

To make products non-purchasable we can use woocommerce_is_purchasable filter. This will make selected products non-purchasable, i.e. products can’t be added to the cart.

Before After
How to hide products by user role in WooCommerce - Purchasable - Before How to hide products by user role in WooCommerce - Purchasable - After

The algorithm is similar to hiding product in catalog, however, instead of $product_id we are passing $product->get_id().

add_filter( 'woocommerce_is_purchasable', 'wpf_product_purchasable_by_user_role', PHP_INT_MAX, 2 );
if ( ! function_exists( 'wpf_product_purchasable_by_user_role' ) ) {
    /**
     * Makes product non-purchasable by user role.
     */
    function wpf_product_purchasable_by_user_role( $purchasable, $product ) {
        return ( wpf_do_hide_product( $product->get_id() ) ? false : $purchasable );
    }
}

Removing products price

We can remove product price by user role and in addition, as there is no price, WooCommerce will make the product non-purchasable automatically.

Before After
How to hide products by user role in WooCommerce - Purchasable - Before How to hide products by user role in WooCommerce - Price - After

Again, the algorithm is similar to hiding product in catalog or making non-purchasable, however, instead of false we are returning empty string ''.

add_filter( 'woocommerce_product_get_price', 'wpf_remove_product_price_by_user_role', PHP_INT_MAX, 2 );
if ( ! function_exists( 'wpf_remove_product_price_by_user_role' ) ) {
    /**
     * Hides product price by user role.
     */
    function wpf_remove_product_price_by_user_role( $price, $product ) {
        return ( wpf_do_hide_product( $product->get_id() ) ? '' : $price );
    }
}

Hiding products by user ID instead of user role

If we need to check the exact user (instead of user role), we can use user’s ID. “Guest” will have ID at 0.

if ( ! function_exists( 'wpf_is_current_user_id' ) ) {
    /**
     * Checks current user's ID.
     */
    function wpf_is_current_user_id( $user_ids_to_check ) {
        $current_user = wp_get_current_user();
        return ( in_array( $current_user->ID, $user_ids_to_check ) );
    }
}

We’ll need to replace wpf_is_current_user_role() with wpf_is_current_user_id() in wpf_do_hide_product() function.

if ( ! function_exists( 'wpf_do_hide_product' ) ) {
    /**
     * Checks if the product needs to be hidden.
     */
    function wpf_do_hide_product( $product_id_to_check ) {

        // TODO: You need to replace product & user IDs with your own here.
        $products_to_hide  = array( 100, 150 ); // product IDs
        $users_to_hide_for = array( 10, 20 );   // user IDs

        // Check if the product must be hidden.
        return (
            in_array( $product_id_to_check, $products_to_hide ) && // product ID match
            wpf_is_current_user_id( $users_to_hide_for )           // user ID match
        );
    }
}

Hiding products by product category instead of product ID

If we need to hide product by category:

if ( ! function_exists( 'wpf_is_product_cat' ) ) {
    /**
     * Checks product's category.
     */
    function wpf_is_product_cat( $product_id, $product_cats ) {
        $current_cats = get_the_terms( $product_id, 'product_cat' );
        if ( $current_cats && ! is_wp_error( $current_cats ) ) {
            $current_cats   = wp_list_pluck( $current_cats, 'slug' );
            $cats_intersect = array_intersect( $current_cats, $product_cats );
            return ( ! empty( $cats_intersect ) );
        }
        return false;
    }
}

And in wpf_do_hide_product() function:

if ( ! function_exists( 'wpf_do_hide_product' ) ) {
    /**
     * Checks if the product needs to be hidden.
     */
    function wpf_do_hide_product( $product_id_to_check ) {

        // TODO: You need to replace product categories & user roles with your own here.
        $product_cats_to_hide = array( 'hoodies', 'hats' ); // product categories (slugs)
        $roles_to_hide_for    = array( '', 'customer' );    // empty string is for the "guest" user role

        // Check if the product must be hidden.
        return (
            wpf_is_product_cat( $product_id_to_check, $product_cats_to_hide ) && // product category
            wpf_is_current_user_role( $roles_to_hide_for )                       // user role match
        );
    }
}

6 thoughts on “How to Hide Products by User Role in WooCommerce with PHP

  1. Thank you, I had to change this

    $current_user_roles = ( empty( $current_user->roles ) ? array( '' ) : $current_user->roles );
    $roles_intersect    = array_intersect( $current_user_roles, $roles_to_check );

    to this

    $current_user_roles = $current_user->roles;

    to work for me, still figuring out why?

    1. Hi Ramses,

      I assume you are referring only to the differences in the first line, i.e. you are still calling the second line:

      $roles_intersect = array_intersect( $current_user_roles, $roles_to_check );

      If that’s correct – the difference between our code and yours only affects not logged users, i.e. “guests”.

      Your code will return an empty array for the roles property, i.e. for the guests, this:

      $current_user_roles = $current_user->roles;

      will result in this:

      $current_user_roles = array();

      Our code will return an array with an empty string element in it, i.e. for the guests, this:

      $current_user_roles = ( empty( $current_user->roles ) ? array( '' ) : $current_user->roles );

      will result in this:

      $current_user_roles = array( '' );

      So when we are checking if the current user’s role is a “guest”, we are checking if an empty string is present in the roles array. And in your case, you should check if the current user’s roles array is empty instead.

      So to sum up – basically it’s possible to make it work as you did, however, the code will be different when checking for the “guest” role.

      Hope that helps. And please let me know if you have any questions.

  2. Hi when I hide a lots of products in the shop pages there are a lot of blank spaces, it seems that the shop count the hidden products.
    What I have to do?

    1. Hi Pietro,

      I’ve just re-tested it on my server, but it seems to be working fine here – there are no blank spaces instead of the products. Which theme do you have installed on your site?

  3. Great article, nice and clear. It really helped me out!

Leave a Reply

Your email address will not be published. Required fields are marked *