最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

plugins - Make specific products accessible only to a user role in WooCommerce

programmeradmin1浏览0评论

I am making a plugin to hide specific product category only for a user role.

add_action( 'woocommerce_product_query', 'wcpp_hide_product' );
function wcpp_hide_product( $q ) {
    //if main query, skip
    if ( ! $q->is_main_query() ) return;
    //jika admin, skip
    if(is_admin()) return;
    //if user is not logged in, or dont have PRIVATE_MEMBER roles hide the product
    $current_user = wp_get_current_user();
    if(!isset($current_user->roles) || !in_array('PRIVATE_MEMBER', $current_user->roles)){ 
        $tax_query = (array) $q->get( 'tax_query' );
        $tax_query[] = array(
           'taxonomy' => 'product_cat',
           'field' => 'id',
           'terms' => 'PRIVATE_CATEGORY',
           'operator' => 'NOT IN'
        );
        $q->set( 'tax_query', $tax_query );
    }

}

Thats code will hide product from search. But other users still can access the product detail page from direct link.

Here my code that hide the product single pages (which is not works):

add_action( 'woocommerce_before_single_product', 'wcpp_hide_product_detail' );
//add_action( 'pre_get_posts', 'wcpp_hide_product_detail' );

function wcpp_hide_product_detail() {
    if(is_admin()) return;
    global $post;
    $terms = get_the_terms( $post->ID, 'product_cat' );
    if(empty($terms)) return;
    $is_private=false;
    foreach($terms as $term){
        if('PRIVATE_CATEGORY'==$term->term_id){
            $is_private = true;
            break;
        } 
    }
    if(!$is_private) return;
    $current_user = wp_get_current_user();
    if(!isset($current_user->roles) || !in_array('PRIVATE_MEMBER', $current_user->roles)){ 
        //need do something here, but not works
        //maybe redirect
        //wp_redirect(home_url());
        /* or like set 404
        global $wp_query;
        $wp_query->set_404();
        status_header(404);
        */
    }
}

If I set a redirect script, it says: "Cannot modify header information - headers already sent by ..."

I think this will works if I can modify the product query to negative ID number which will trigger the "product not found" page. But I dont know which is the action hook name to do it. Then I may be my code could works using wp action hook like add_action( 'wp', 'wcpp_hide_product_detail' );. But I dont know the right hook.

Any help is appreciated.

I am making a plugin to hide specific product category only for a user role.

add_action( 'woocommerce_product_query', 'wcpp_hide_product' );
function wcpp_hide_product( $q ) {
    //if main query, skip
    if ( ! $q->is_main_query() ) return;
    //jika admin, skip
    if(is_admin()) return;
    //if user is not logged in, or dont have PRIVATE_MEMBER roles hide the product
    $current_user = wp_get_current_user();
    if(!isset($current_user->roles) || !in_array('PRIVATE_MEMBER', $current_user->roles)){ 
        $tax_query = (array) $q->get( 'tax_query' );
        $tax_query[] = array(
           'taxonomy' => 'product_cat',
           'field' => 'id',
           'terms' => 'PRIVATE_CATEGORY',
           'operator' => 'NOT IN'
        );
        $q->set( 'tax_query', $tax_query );
    }

}

Thats code will hide product from search. But other users still can access the product detail page from direct link.

Here my code that hide the product single pages (which is not works):

add_action( 'woocommerce_before_single_product', 'wcpp_hide_product_detail' );
//add_action( 'pre_get_posts', 'wcpp_hide_product_detail' );

function wcpp_hide_product_detail() {
    if(is_admin()) return;
    global $post;
    $terms = get_the_terms( $post->ID, 'product_cat' );
    if(empty($terms)) return;
    $is_private=false;
    foreach($terms as $term){
        if('PRIVATE_CATEGORY'==$term->term_id){
            $is_private = true;
            break;
        } 
    }
    if(!$is_private) return;
    $current_user = wp_get_current_user();
    if(!isset($current_user->roles) || !in_array('PRIVATE_MEMBER', $current_user->roles)){ 
        //need do something here, but not works
        //maybe redirect
        //wp_redirect(home_url());
        /* or like set 404
        global $wp_query;
        $wp_query->set_404();
        status_header(404);
        */
    }
}

If I set a redirect script, it says: "Cannot modify header information - headers already sent by ..."

I think this will works if I can modify the product query to negative ID number which will trigger the "product not found" page. But I dont know which is the action hook name to do it. Then I may be my code could works using wp action hook like add_action( 'wp', 'wcpp_hide_product_detail' );. But I dont know the right hook.

Any help is appreciated.

Share Improve this question edited Apr 14, 2019 at 1:07 LoicTheAztec 3,39117 silver badges24 bronze badges asked Apr 13, 2019 at 1:42 plonknimbuzzplonknimbuzz 1131 silver badge6 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 3

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.

发布评论

评论列表(0)

  1. 暂无评论