phpwoocommercecustom-fieldsuser-rolesproduct-variations

Hide specific WooCommerce Product Variations from User Role based on a custom field


In WordPress, I have created "Dealer" and "Wholesale" user roles.

I want to hide specific WooCommerce product variation if the user role has a "Dealer" role for specific product variations based on a custom setting field. I have added a checkbox to the product variation to selectively hide or display the variation.

Partially based on this answer thread I have the following code:

// Here is where I add my custom user roles- Wholesaler and Dealer

function add_custom_roles() {
    add_role(
        'wholesaler',
        __( 'Wholesaler' ),
        get_role( 'customer' )->capabilities
    );

    add_role(
        'dealer',
        __( 'Dealer' ),
        get_role( 'customer' )->capabilities
    );
}
add_action( 'init', 'add_custom_roles' );

// Here i add custom fields to product variations
add_action( 'woocommerce_variation_options', 'add_custom_fields_to_variations', 10, 3 );
function add_custom_fields_to_variations( $loop, $variation_data, $variation ) {
    woocommerce_wp_checkbox(
        array(
            'id'            => '_hide_variation_dealer',
            'wrapper_class' => 'show_if_variation',
            'label'         => __('Hide for dealers', 'woocommerce' ),
            'description'   => '',
            'value'         => get_post_meta( $variation->ID, '_hide_variation_dealer', true ) ? 'yes' : 'no',
        )
    );
}

// Saving custom fields for product variations

add_action( 'woocommerce_save_product_variation', 'save_custom_fields_for_variations', 10, 2 );
function save_custom_fields_for_variations( $variation_id, $i ) {
    $hide_variation_dealer = isset( $_POST['_hide_variation_dealer'][$i] ) ? 'yes' : 'no';
    update_post_meta( $variation_id, '_hide_variation_dealer', $hide_variation_dealer );
}

// Here I filtering function to read custom field values - logged in and dealer.

add_filter( 'woocommerce_variation_is_visible', 'hide_specific_product_variation', 10, 4 );
function hide_specific_product_variation( $is_visible, $variation_id, $variable_product, $variation ) {
    // Check if user is logged in and has dealer role
    if( is_user_logged_in() ) {
        $user = wp_get_current_user();
        if ( in_array( 'dealer', (array) $user->roles ) ) {
            // For dealer user role, hide variations with the custom field set to 'yes'
            $hide_variation_dealer = get_post_meta( $variation->ID, '_hide_variation_dealer', true );
            if ( $hide_variation_dealer === 'yes' ) {
                return false;
            }
        }
    }
    return $is_visible;
}

But the variation is not hidden. I am not able to find why it doesn't work. Any help is appreciated.


Solution

  • The main issue comes from $variation->ID in your last function as $variation function argument is not a WP_Post object but a WC_Product_Variation object (you should have used $variation_id argument directly).

    Now, as WooCommerce is migrating progressively to custom tables, you should avoid using WordPress post meta functions, when it's possible. Instead, always try to use available getter or setter methods introduced in WooCommerce 3.

    Use the following code replacement that will hide specific variation from specific user role based on a custom field (checkbox in variation settings):

    // Conditional function: Check if the user is from specific user role
    function is_user_role( $role ) {
        global $current_user;
        return in_array( $role, $current_user->roles );
    }
    
    // Add a custom setting field to product variation
    add_action( 'woocommerce_variation_options', 'add_variation_setting_field', 10, 3 );
    function add_variation_setting_field( $loop, $variation_data, $variation ) {
        $field_key = '_hide_variation_dealer';
    
        woocommerce_wp_checkbox( array(
            'id'            => $field_key,
            'label'         => __('Hide for dealers', 'woocommerce' ),
            'value'         => get_post_meta( $variation->ID, $field_key, true ) ? 'yes' : 'no',
        ) );
    }
    
    // Save product variation custom setting field value
    add_action('woocommerce_admin_process_variation_object', 'save_variation_setting_field', 10, 2 );
    function save_variation_setting_field($variation, $i) {
        $field_key = '_hide_variation_dealer';
    
        $variation->update_meta_data($field_key, isset($_POST[$field_key][$i]));
    }
    
    // Hide variation based on user role and custom field
    add_filter( 'woocommerce_variation_is_visible', 'hide_conditionally_product_variation', 10, 4 );
    function hide_conditionally_product_variation( $is_visible, $variation_id, $product_id, $variation ) {
        $field_key = '_hide_variation_dealer';
    
        if ( is_user_role('dealer') && $variation->get_meta($field_key) ) {
            return false;
        }
        return $is_visible;
    }
    

    Code goes on functions.php file of your child theme (or in a plugin). Tested and works.