skip to Main Content

Would you please help me out to optimize my little snippet I wrote to apply a discount after adding products in the cart with tech assigned shipping class and other products with no class specified for WordPress (Woocommerce) website.
How can I optimize the if .. elseif and overall make it better. Also, is adding break a good practise? I’m a PHP newbie, but I’m currently learning and would like to improve my code. Porbably I can use something similar to switch? Any help and examples are greatly appreciated!

add_filter( 'woocommerce_package_rates', 'adjustment_in_rates_of_product_with_shipping_class', 12, 2 );

function adjustment_in_rates_of_product_with_shipping_class( $available_shipping_methods, $package ) {

   // Shipping class slug to be eligible for a discount when combined with no class products
    $shipping_class = array(
        'tech',
    );

   // Discount
    $discounteuro = 3.50;
    $discountgbp = 3.20;
    $discountusd = 4;
    $discountglobalusd = 5;

    // Enter the shipping method value
    $shipping_services = array(
       'flat_rate:5',
    );

    $shipping_class_exists = false;
    foreach(WC()->cart->get_cart_contents() as $key => $values) {
        if ( in_array($values['data']->get_shipping_class() , $shipping_class) ) {
            $shipping_class_exists = true;
            break;
        }
    }

    $shipping_class_no_exists = false;
    foreach(WC()->cart->get_cart_contents() as $key => $values) {
        if ( strlen($values['data']->get_shipping_class()) == 0 ) {
            $shipping_class_no_exists = true;
            break;
        }
    }

    if ($shipping_class_exists && $shipping_class_no_exists) {
        foreach ($available_shipping_methods as $key => $value) {
            if ( in_array($value->get_id() , $shipping_services) && get_woocommerce_currency() == 'EUR' ) {
                $available_shipping_methods[$key]->cost -= $discounteuro;
        break;
            }
        elseif ( in_array($value->get_id() , $shipping_services) && get_woocommerce_currency() == 'GBP' ) {
                $available_shipping_methods[$key]->cost -= $discountgbp;
        break;
        }
        elseif ( in_array($value->get_id() , $shipping_services) && get_woocommerce_currency() == 'USD' ) {
                $available_shipping_methods[$key]->cost -= $discountusd;
        break;
       }
        else {
            $available_shipping_methods[$key]->cost -= $discountglobalusd;   
        break;
       }
        }
    }

    return $available_shipping_methods;
}

2

Answers


  1. I would combine your first two loops into a single loop, because there isn o reason to loop over the data twice. Something like this

    $shipping_class_exists = false;
    $shipping_class_no_exists = false;
    
    foreach(WC()->cart->get_cart_contents() as $key => $values) {
        if(in_array($values['data']->get_shipping_class() , $shipping_class)) {
            $shipping_class_exists = true;
        }
        if(strlen($values['data']->get_shipping_class()) == 0) {
            $shipping_class_no_exists = true;
        }
    }
    

    I would also convert your discounts into an array, to make it easier to call from your loop.

    $discounts = [
        'EUR' => 3.5,
        'GBP' => 3.2,
        'USD' => 4,
        'globalusd' => 5
    ];
    

    Then your loop would become

    if ($shipping_class_exists && $shipping_class_no_exists) {
        foreach ($available_shipping_methods as $key => $value) {
            
            //store currency type in an easier to access variable
            $currency = get_woocommerce_currency();   
            
            //create variable `$discount` defaulting to `$discounts['globalusd']`
            $discount = $discounts['globalusd'];
    
            if(in_array($value->get_id(), $shipping_services) && array_key_exists($currency, $discounts)) {
    
                //if $value->get_id()` is in `$shipping_services` and `$currency` key exists in $discounts
                //then alter $discount to the correct value
                $discount = $discounts[$currency];
            }
    
            //subtract discount from cost        
            $available_shipping_methods[$key]->cost -= $discount;
    
        }
    }
    
    Login or Signup to reply.
  2. Updated 2 Removed some mistakes

    The following optimized code should do the trick (code is commented):

    add_filter( 'woocommerce_package_rates', 'adjustment_in_rates_of_product_with_shipping_class', 12, 2 );
    
    function adjustment_in_rates_of_product_with_shipping_class( $rates, $package ) {
    
        // Shipping class slug to be eligible for a discount when combined with no class products
        $target_shipping_classes = array('tech');
    
        // Enter the shipping method value
        $shipping_rate_ids       = array('flat_rate:5');
    
        // Discount based on currency
        $currency_discounts      = array(
            ''      => 5,
            'EUR'   => 3.50,
            'GBP'   => 3.20,
            'USD'   => 4,
        );
    
        $shipping_class_found    = $other_shipping_classes = $currency_found = false;
    
        $woocommerce_currency    = get_woocommerce_currency();
    
        // Loop through cart items for the current package
        foreach( $package['contents'] as $item ) {
            $shipping_class = $item['data']->get_shipping_class(); // Get item shipping class
    
            if ( in_array( $shipping_class, $target_shipping_classes ) ) {
                $shipping_class_found = true;
            }
            elseif ( ! empty($shipping_class) ) {
                $other_shipping_classes = true;
            }
        }
    
        // When there is only items from the defined shipping classes
        if ( $shipping_class_found && ! $other_shipping_class ) {
            // Loop through available shipping rates in the current shipping package
            foreach ( $rates as $rate_key => $rate ) {
                if ( in_array($rate_key, $shipping_rate_ids) ) {
                    // Loop through defined currency discounts
                    foreach ( $currency_discounts as $currency => $discount ) {
                        if ( $woocommerce_currency === $currency ) {
                            $rates[$rate_key]->cost -= $discount;
                            $currency_found = true;
                            break;
                        }
                    }
                    // If no currency match, we get the default value (the first one)
                    if ( ! $currency_found ) {
                        $rates[$shipping_rate_id]->cost -= reset($currency_discounts);
                    }
                }
            }
        }
    
        return $rates;
    }
    

    Code goes in functions.php file of the active child theme (or active theme). Tested and works.

    Note: You should empty your after saving this code.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search