Make specific products accessible only to a user role in WooCommerce

I have revisited your code as there was some mistakes (everything is commented in the code). Also:

  • You can use current_user_can() to check a user role for the current user.

  • You can use has_term() conditional function to check for post terms of any taxonomy.

The following code will hide products that belongs to a specific product category from user that have not a specific user role. If they try to access that specific products, they will be redirected to shop page with a custom notice…

Additionally the ajax add to cart button or the “Read more” button is replaced on all products loop for that specific products by a disable greyed button (in front end only).

Here is the code:

// Hide specific products from shop and archives pages
add_action( 'woocommerce_product_query', 'wcpp_hide_product' );
function wcpp_hide_product( $q ) {
    // skip for main query and  on admin
    if ( ! $q->is_main_query() || is_admin() )
        return;

    // Hide specific products for unlogged users or users without PRIVATE_MEMBER user role
    if ( is_user_logged_in() || ! current_user_can('PRIVATE_MEMBER') ) {
        $tax_query = (array) $q->get( 'tax_query' );
        $tax_query[] = array(
           'taxonomy' => 'product_cat',
           'field' => 'term_id', // it's not 'id' but 'term_id' (or 'name' or 'slug')
           'terms' => 'PRIVATE_CATEGORY',
           'operator' => 'NOT IN'
        );
        $q->set( 'tax_query', $tax_query );
    }
}

// Replace add to cart button by a disabled button on specific products in Shop and archives pages
add_filter( 'woocommerce_loop_add_to_cart_link', 'wcpp_replace_loop_add_to_cart_button', 10, 2 );
function wcpp_replace_loop_add_to_cart_button( $button, $product  ) {
    if ( ( is_user_logged_in() || ! current_user_can('PRIVATE_MEMBER') )
    && has_term( 'PRIVATE_CATEGORY', 'product_cat', $product->get_id() ) ) {;
        $button = '<a class="button alt disabled">' . __( "Private", "woocommerce" ) . '</a>';
    }
    return $button;
}

// On single product pages, redirect to shop and display a custom notice for specific products
add_action( 'template_redirect', 'wcpp_redirect_hiding_product_detail' );
function wcpp_redirect_hiding_product_detail() {
    if ( ( is_user_logged_in() || ! current_user_can('PRIVATE_MEMBER') )
    && has_term( 'PRIVATE_CATEGORY', 'product_cat' ) && is_product() ) {
        // Add a notice (optional)
        wc_add_notice(__("Sorry, but you are not allowed yet to see this product."), 'notice' );

        // Shop redirection url
        $redirect_url = get_permalink( get_option('woocommerce_shop_page_id') );
        wp_redirect($redirect_url); // Redirect to shop

        exit(); // Always exit
    }
}

Code goes in function.php file of your active child theme (or active theme), or in a plugin file.

Tested and works.