phpwordpresswoocommerceuser-rolesproduct-variations

Different Product Variation Price Based On User Role In WooCommerce


Scenario

7 custom roles in 2 categories are built to serve B2C clients with subscriptions and B2B distributors, which are:

When the user is logged in, the user can see the different discounts for their tiers:

What Has Been Achieved

I've achieved the goal with simple products by adding the snippet from this tutorial. The solution only enables me the solution to accomplish the needs of simple ones by using ACF and some snippets together but not variable ones.

The Code

After some days of research, a great solution by LoicTheAztec came insight from this post. However, I found myself stuck in building the connection between the custom prices and the roles(I'm NOT an engineer and still learning how to code to reduce the dependences for plugins).

// Add custom fields to variations option pricing
add_action( 'woocommerce_variation_options_pricing', 'add_variation_wholesale_options_pricing', 20, 3 );
function add_variation_wholesale_options_pricing( $loop, $variation_data, $post_variation )
{
    $value1  = get_post_meta( $post_variation->ID, '_sp_price_1', true ); // subscription tier 1
    $value2  = get_post_meta( $post_variation->ID, '_sp_price_2', true ); // subscription tier 2
    $value3  = get_post_meta( $post_variation->ID, '_sp_price_3', true ); // distributor tier 1
    $value4  = get_post_meta( $post_variation->ID, '_sp_price_4', true ); // distributor tier 2
    $value5  = get_post_meta( $post_variation->ID, '_sp_price_5', true ); // distributor tier 3
    $value6  = get_post_meta( $post_variation->ID, '_sp_price_6', true ); // distributor tier 4
    $value7  = get_post_meta( $post_variation->ID, '_sp_price_7', true ); // distributor tier 5

    $symbol = ' (' . get_woocommerce_currency_symbol() . ')';

    $key_1 = '_sp_price_1[' . $loop . ']';
    $key_2 = '_sp_price_2[' . $loop . ']';
    $key_3 = '_sp_price_3[' . $loop . ']';
    $key_4 = '_sp_price_4[' . $loop . ']';
    $key_5 = '_sp_price_5[' . $loop . ']';
    $key_6 = '_sp_price_6[' . $loop . ']';
    $key_7 = '_sp_price_7[' . $loop . ']';

    // Field Label For Subscription Tier 1
    echo '<div><p class="form-row form-row-first">
        <label>' . __( "Subscription Tier 1", "woocommerce" ) . $symbol . '</label>
        <input type="text" size="5" name="' . $key_1 .'" value="' . esc_attr( $value1 ) . '" />
    </p></div>';

    // Field Label For Subscription Tier 2
    echo '<div><p class="form-row form-row-first">
        <label>' . __( "Subscription Tier 2", "woocommerce" ) . $symbol . '</label>
        <input type="text" size="5" name="' . $key_2 .'" value="' . esc_attr( $value2 ) . '" />
    </p></div>';

    // Field Label For Distributor Tier 1
    echo '<div><p class="form-row form-row-first">
        <label>' . __( "Distributor Tier ", "woocommerce" ) . $symbol . '</label>
        <input type="text" size="5" name="' . $key_3 .'" value="' . esc_attr( $value3 ) . '" />
    </p></div>';

    // Field Label For Distributor Tier 2
    echo '<div class="variable_wholesale-price"><p class="form-row form-row-first">
        <label>' . __( "Distributor Tier 2", "woocommerce" ) . $symbol . '</label>
        <input type="text" size="5" name="' . $key_4 .'" value="' . esc_attr( $value4 ) . '" />
    </p></div>';

    // Field Label For Distributor Tier 3
    echo '<div class="variable_wholesale-price"><p class="form-row form-row-first">
        <label>' . __( "Distributor Tier 3", "woocommerce" ) . $symbol . '</label>
        <input type="text" size="5" name="' . $key_5 .'" value="' . esc_attr( $value5 ) . '" />
    </p></div>';

    // Field Label For Distributor Tier 4
    echo '<div class="variable_wholesale-price"><p class="form-row form-row-first">
        <label>' . __( "Distributor Tier 4", "woocommerce" ) . $symbol . '</label>
        <input type="text" size="5" name="' . $key_6 .'" value="' . esc_attr( $value6 ) . '" />
    </p></div>';

    // Field Label For Distributor Tier 5
    echo '<div class="variable_wholesale-price"><p class="form-row form-row-first">
        <label>' . __( "Distributor Tier 5", "woocommerce" ) . $symbol . '</label>
        <input type="text" size="5" name="' . $key_7 .'" value="' . esc_attr( $value7 ) . '" />
    </p></div>';
}


// Save variations wholesale prices custom fields values
add_action( 'woocommerce_save_product_variation', 'save_product_variation_wholesale_price', 20, 2 );
function save_product_variation_wholesale_price( $variation_id, $i )
{
    if ( isset( $_POST['_sp_price_1'][$i] ) )
    {
        update_post_meta( $variation_id, '_sp_price_1', floatval( $_POST['_sp_price_1'][$i] ) );
    }
}

// Variable product price range
add_filter('woocommerce_variation_prices_price', 'wholesale_variation_price', 900, 2 );
add_filter('woocommerce_variation_prices_sale_price', 'wholesale_variation_price', 900, 2 );

// Product variations (of a variable product)
add_filter('woocommerce_product_variation_get_price', 'wholesale_variation_price', 900, 2 );
add_filter('woocommerce_product_variation_get_sale_price', 'wholesale_variation_price', 900, 2 );
function wholesale_variation_price( $price, $object )
{
    if ( is_user_logged_in() ) {

        // For Wholesale user levels 1 and 2
        if( in_array($level, [1]) ) {
            $new_price = (float) get_post_meta( $object->get_id(), '_sp_price_1', true );
            $price     = empty($new_price) ? $price : $new_price;
        }

    }
    return $price;
}

// Handling custom variable price range caching
add_filter( 'woocommerce_get_variation_prices_hash', 'wholesale_variation_performances_caching_prices', 99, 1 );
function wholesale_variation_performances_caching_prices( $hash ) {
    if ( is_user_logged_in() ) {
        $level = (int) get_user_meta( get_current_user_id(), 'mokeeper_keen', true );
        // For Wholesale user levels 1 and 2
        if( in_array($level, [1]) ) {
            $hash[] = 'level_' . $level;
        }
        // For customers
        else {
            $hash[] = 'level_0'; // Set the user level to zero here
        }
    }
    return $hash;
}

The custom blank fields are set in the backend but they're not seeable to the logged-in user with the desired tiered role on the frontend.

I've tried my best to build up the correct logic and this is the furthest spot I could get to with my limited knowledge of coding. I know I MUST have missed something(or some things) or did something wrong, but I really couldn't figure out where to audit to make it correct.

Appreciate you for responding in advance. Looking forward to your help.


Solution

  • Try the following optimized and complete code version that handle your user roles too:

    // Field settings (field key / label name)
    function custom_field_settings() {
        return array(
            '_st_price_1' => __( "Subscription Tier 1", "woocommerce" ),
            '_st_price_2' => __( "Subscription Tier 2", "woocommerce" ),
            '_dt_price_1' => __( "Distributor Tier 1", "woocommerce" ),
            '_dt_price_2' => __( "Distributor Tier 2", "woocommerce" ),
            '_dt_price_3' => __( "Distributor Tier 3", "woocommerce" ),
            '_dt_price_4' => __( "Distributor Tier 4", "woocommerce" ),
            '_dt_price_5' => __( "Distributor Tier 5", "woocommerce" ),
        );
    }
    
    // Settings: custom field keys by user role
    function custom_field_key_by_user_role() {
        return array(
            '_st_price_1' => 'subcription_tier1',
            '_st_price_2' => 'subcription_tier2',
            '_dt_price_1' => 'distributor_tier1',
            '_dt_price_2' => 'distributor_tier2',
            '_dt_price_3' => 'distributor_tier3',
            '_dt_price_4' => 'distributor_tier4',
            '_dt_price_5' => 'distributor_tier5',
        );
    }
    
    // Add custom fields to variations option pricing
    add_action( 'woocommerce_variation_options_pricing', 'add_variation_custom_options_pricing', 20, 3 );
    function add_variation_custom_options_pricing( $loop, $variation_data, $post_variation ) {
        $symbol  = ' (' . get_woocommerce_currency_symbol() . ')';
    
        // Loop through field key / label name pairs
        foreach ( custom_field_settings() as $key => $label ) {
            printf( '<div><p class="form-row form-row-first"> <label>%s</label>
            <input type="text" size="5" name="%s[%s]" value="%s" /></p></div>', 
            $label.$symbol, $key, $loop, floatval(get_post_meta($post_variation->ID, $key, true)) );
        }
    }
    
    // Save variations prices custom fields values
    add_action( 'woocommerce_admin_process_variation_object', 'save_variation_custom_options_pricing', 20, 2 );
    function save_variation_custom_options_pricing( $variation, $i ) {
        // Loop through field key / label name pairs
        foreach ( custom_field_settings() as $key => $label ) {
            if ( isset( $_POST[$key][$i] ) ){
                $variation->update_meta_data( $key, floatval($_POST[$key][$i]) );
            }
        }
    }
    
    // Variable product price range
    add_filter('woocommerce_variation_prices_price', 'wholesale_variation_price', 900, 2 );
    add_filter('woocommerce_variation_prices_sale_price', 'wholesale_variation_price', 900, 2 );
    // Product variations (of a variable product)
    add_filter('woocommerce_product_variation_get_price', 'wholesale_variation_price', 900, 2 );
    add_filter('woocommerce_product_variation_get_sale_price', 'wholesale_variation_price', 900, 2 );
    function wholesale_variation_price( $price, $object ) {
        global $current_user;
    
        if ( ! is_user_logged_in() ) return $price;
    
        // Loop through field key / user role pairs
        foreach ( custom_field_key_by_user_role() as $key => $role ) {
            if( in_array($role, $current_user->roles) ) {
                $new_price = (float) $object->get_meta($key);
                $price     = empty($new_price) ? $price : $new_price;
            }
        }
        return $price;
    }
    
    // Handling custom variable price range caching
    add_filter( 'woocommerce_get_variation_prices_hash', 'wholesale_variation_performances_caching_prices', 99, 1 );
    function wholesale_variation_performances_caching_prices( $hash ) {
        global $current_user;
    
        if ( ! is_user_logged_in() ) return $hash;
    
        // Loop through field key / user role pairs
        foreach ( custom_field_key_by_user_role() as $key => $role ) {
            if( in_array($role, $current_user->roles) ) {
                $hash[] = $key;
            }
        }
        return $hash;
    }
    

    It should work.