Hiding Products, Categories & Prices 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:
- hide products in the catalog and search results,
- make products non-purchasable,
- remove the price (and “add to cart” button) from the products.
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 |
---|---|
![]() |
![]() |
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 |
---|---|
![]() |
![]() |
The algorithm is similar to hiding products in a 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 |
---|---|
![]() |
![]() |
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 ); } }
Hi! i was trying to hide some product for some user ID,
it does’nt seems to work for me here , maybe i lost a part ! Can you please tell me what i did wrong , i try to hide one product , for one user with this code :
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 ) );
}
}
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(1162); // product IDs
$users_to_hide_for = array(109); // 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
);
}
}
Is there a way to hide only products that have a ‘*’ in price like 100β¬* from user role?
I have an issue when I use wp_query and use wc_get_template_part( ‘content’, ‘product’ );
Just perfect, thank you
I tried your code but It didn’t work for me π
I would like to HIDE specific CATEGORY for a specific USER ROLE.
could you help please ?
Hi Tao,
First of all, you are missing the
wpf_is_current_user_role()
function:Then you need to decide how you are going to hide the products. For example, to hide products from shop and search results:
And the last note – please make sure that
MY_CATEGORY_PRODUCT
andMY_CUUSTOMER_01
don’t have typos in them.Hope this helps. Please give it a try and let me know what you think.
Hey there! Thanks so much for posting this tutorial. Unfortunately, I canβt seem to get it to work for my site..
This is the code:
Hi Mario,
I’ve just tested your code on my server, but it seems to be working fine here. If you wish, I can take a look at it on your website – you can contact me via [email protected].
Hello,
Thank you for the really useful snippets.
I am trying to find a way to modify the non-purchasable snippet so that instead of making it non purchasable, it re-directs non authorised users back to another page. Would you have any suggestions on how would be best to go about this?
Cheers,
Hi Dan,
Happy to help π
There are probably several ways to do it. The first approach that comes to mind – you start by using our
wpf_product_purchasable_by_user_role()
snippet to make the selected products non-purchasable. Then you can redirect single product pages for all non-purchasable products with this snippet:I would suggest this approach because making products non-purchasable will ensure that your customers won’t add these products to the cart from the shop pages. If you don’t need that, you can simplify it by skipping the
wpf_product_purchasable_by_user_role()
part, and replacingwith
I.e., you simply check it by product’s ID.
I hope this helps. Please let me know if you have any questions.
Hey there! Thanks so much for posting this tutorial. Unfortunately, I can’t seem to get it to work for my site..
What I’m trying to do is to hide 3 product categories (for example the category slugs would be: ‘hello_1’, ‘hello_2’ and ‘hello_3’) for guests and for the user role ‘personal_account’.
This is the code that I’ve came up with:
I’m not very experienced in PHP so I’m not quite sure as to where I went wrong with the code. Guests and personal_account users could still see the products from category hello_1, hello_2 and hello_3. And the code that was meant to hide those categories in the catalog would end up showing the there was a serious error on your website message.
Hi Ella,
I think you forgot to add our
wpf_is_current_user_role()
function to your code, i.e.:Please give it a try and let me know if that helps.
Hello and thank you very much for this very useful post!
I have a question:
– if I would need to hide some products only for customers (i.e. product ids 54, 62) and to hide some other products only for guests (i.e. product ids 32, 36), what do you suggest?
Thank you very much!
Riccardo
Hi Riccardo,
Thank you π
You’ll need to modify our
wpf_do_hide_product()
function. Like this:Please give it a try and let me know if you have any questions.
Thank you very much Tom! I really appreciate!
It works but I still have a problem with the view.
I have to hide some products for guests and other products for logged in user in the same category.
The code actually hides the products properly according to the user role but the products are still in the category page even if the user can’t see them and they ara counted in the pages.
Let me explain:
– I have 100 products in the category “CATEGORY1”
– I need to hide 50 products (ID from 1 to 50) for logged-in clients and show them only products with Id from 51 to 100
– I need to hide 50 products (ID from 51 to 10) for guests and show them only products with Id from 1 to 50.
When I apply the code, the user can’t see the products but (let’s say default settings for the view is to show 50 products per page):
– The logged-in client (that will see only products from id 51 to 100), when opens the category he sees a blank page with the page count on the bottom showing the numbers of page (1-2).
To see the products he has to click on page 2 and see the products (IDs 51-100).
– At the same time, a guest sees page 1 with the products (ID 1-51) and when he clicks on page 2 he sees a blank page (hidden products for guests IDs 51-100).
The problem is that the client will see an empty page when he should see his products without browsing pages to find them.
Any suggestion?
Thank you very very much.
Riccardo
Hi Riccardo,
Ok, let’s try a bit different approach, and modify
woocommerce_product_query
instead. Here is the new code, please give it a try and let me know if it’s working as expected:Thank you, I had to change this
to this
to work for me, still figuring out why?
Hi Ramses,
I assume you are referring only to the differences in the first line, i.e. you are still calling the second line:
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:
will result in this:
Our code will return an array with an empty string element in it, i.e. for the guests, this:
will result in this:
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.
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?
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?
Great article, nice and clear. It really helped me out!
Thank you, Jack!