skip to Main Content

I face a problem in woocommerce shipping class. To explain it better I describe it with an example:

  • Product A has Air Shipping class
  • Product B has Road Shipping class
  • product C has Possible shipping in road and air

I use the following code to split the order based on shipping class:

add_filter( 'woocommerce_cart_shipping_packages', 'wf_split_cart_by_shipping_class_group' );
function wf_split_cart_by_shipping_class_group($packages){
    //Reset packages
    $packages               = array();
    
    //Init splitted package
    $splitted_packages      =   array();
    
    // Group of shipping class ids
    $class_groups =  array(
        'group1'    => array('plane'),
        'group2'    =>  array('truck'),
        // 'group3' =>  array(11,15,17),        
    );  
    
    foreach ( WC()->cart->get_cart() as $item_key => $item ) {
        if ( $item['data']->needs_shipping() ) {
            
            $belongs_to_class_group =   'none';
            
            $item_ship_class_id =   $item['data']->get_shipping_class();
            
            if($item_ship_class_id){
                
                foreach($class_groups as $class_group_key   =>  $class_group){
                    if(in_array($item_ship_class_id, $class_group)){                
                        $belongs_to_class_group = $class_group_key;
                        continue;
                    }
                }
                
            }           
            
            $splitted_packages[$belongs_to_class_group][$item_key]  =   $item;
        }
    }
    
    // Add grouped items as packages 
    if(is_array($splitted_packages)){
        
        foreach($splitted_packages as $splitted_package_items){
            $packages[] = array(
                'contents'        => $splitted_package_items,
                'contents_cost'   => array_sum( wp_list_pluck( $splitted_package_items, 'line_total' ) ),
                'applied_coupons' => WC()->cart->get_applied_coupons(),
                'user'            => array(
                     'ID' => get_current_user_id(),
                ),
                'destination'    => array(
                    'country'    => WC()->customer->get_shipping_country(),
                    'state'      => WC()->customer->get_shipping_state(),
                    'postcode'   => WC()->customer->get_shipping_postcode(),
                    'city'       => WC()->customer->get_shipping_city(),
                    'address'    => WC()->customer->get_shipping_address(),
                    'address_2'  => WC()->customer->get_shipping_address_2()
                )
            );
        }
    }
    return $packages;
}

In this code plan class and truck class separated. But in the case of product number 3, user should select between air and road, since it is optional. When user selects road in the total price the shipping cost apply twice, while I expect to add the weight to the first line and just calculate the shipping class once.

Update with a real example:

I am using Free version of WooCommerce Advanced Shipping By sormano.

In another word, obviously, I want to do as following:
Some products like pork and meat they need to be kept frozen, so we must send them by airplane, In some cases, the weight of the product is too heavy, let’s say 20 KG, so this is not logical to send this type of product by airplane, since it is too expensive, to make the shipping fee fair enough we send them by truck. In another case, there are some products shipping them whether by airplane or truck doesn’t matter, hence the customer decides the shipping method. This the scenario: a customer orders pork which must be shipped by airplane also a 10 KG package of olive which must be shipped by truck, and the third product in his basket is a product that the shipping method is not important. For the third product, the customer chooses the truck shipping method.
In a normal situation, each product’s shipping method is calculated separately, but I want to add the weight of the third product to the first product (olive package). what should I do to solve this problem?
Any help to handle this problem will be appreciated.

2

Answers


  1. for my convenience I have created the data structure of your Woocommerce in the most similar way possible.

    You can test it with php client php x.php

    <?php
    function get_current_user_id(){
        return 1;
    }
    function wp_list_pluck($items,$column){
        $ares=[];
        foreach($items as $item){
            foreach($item as $k=>$v){
                if( $k==$column){
                    $ares[]=$v;
                }
            }
        }
        return $ares;
    }
    $wc=[
        "customer"=>[
            "get_shipping_country"=>"Italy",
            "get_shipping_state"=>"Not yet shipped",
            "get_shipping_postcode"=>"32029",
            "get_shipping_city"=>"Beautiful Field",
            "get_shipping_address"=>"Road of Trees",
            "get_shipping_address_2"=>""
        ],
        "cart"=> [
            "get_contents" => [
                    ["prod_id"=>1, "shipping_group"=>["plane"],'line_total'=>11.00 ,'needs_shipping'=>true],
                    ["prod_id"=>2, "shipping_group"=>["truck"],'line_total'=>14.00 ,'needs_shipping'=>true],
                    ["prod_id"=>3, "shipping_group"=>[ 11, 15, 17],'line_total'=>16.00,'needs_shipping'=>true],
                    ["prod_id"=>4, "shipping_group"=>["plane"],'line_total'=>22.00 ,'needs_shipping'=>true],
                    ["prod_id"=>5, "shipping_group"=>["truck"],'line_total'=>24.00 ,'needs_shipping'=>true],
                    ["prod_id"=>6, "shipping_group"=>[ 11, 15, 17],'line_total'=>26.00,'needs_shipping'=>true],
                    ["prod_id"=>7, "shipping_group"=>["plane"],'line_total'=>32.00 ,'needs_shipping'=>true],
                    ["prod_id"=>8, "shipping_group"=>["truck"],'line_total'=>34.00 ,'needs_shipping'=>true],
                    ["prod_id"=>9, "shipping_group"=>[ 11, 15, 17],'line_total'=>36.00,'needs_shipping'=>true]
                ]
        ]
    ];
    
    $wc["cart"]["get_cart"]=[
                    'contents' => $wc["cart"]["get_contents"],
                    'contents_cost'   => array_sum( wp_list_pluck( $wc["cart"]["get_contents"], 'line_total' ) ),
                    'user'            => array('ID' => get_current_user_id()),
                    'destination'    => [
                        'country'    => $wc["customer"]["get_shipping_country"],
                        'state'      => $wc["customer"]["get_shipping_state"],
                        'postcode'   => $wc["customer"]["get_shipping_postcode"],
                        'city'       => $wc["customer"]["get_shipping_city"],
                        'address'    => $wc["customer"]["get_shipping_address"],
                        'address_2'  => $wc["customer"]["get_shipping_address_2"]
                    ]   
                ];
    
    function arrarr_unique($a){
        $l=[];$r=[];
        foreach($a as $e){
           $l[]=json_encode($e);
        }
        $lu = array_unique($l);
        foreach($lu as $e){
            $r[]=json_decode($e);
        }
        return $r;
    }
    
    function filter_match_shipping($items, $array_group){
        $res=[];
        foreach($items as $item){
            if ($item["shipping_group"]==$array_group){
                $res[]=$item;
            }
        }
        return $res;
    }
    function add_filter(){
        //do nothing
    }
    
    
    add_filter( 'woocommerce_cart_shipping_packages', 'wtf' );
    
    function wtf($wc,$packages=[]){
        
        $cts = $wc["cart"]["get_contents"];
        $groups = arrarr_unique(wp_list_pluck($cts,'shipping_group'));
    
        //Settings 
        $splitted_packages=[];
        foreach($groups as $g){
            $k=json_encode($g);        
            $splitted_packages[$k]=[];
        }
        //Fill 
        foreach($groups as $g){
            $k=json_encode($g);        
            $splitted_packages[$k][] = filter_match_shipping( $cts,$g );
        }
    
        // Add grouped items as packages 
        if(is_array($splitted_packages)){
            $c=0;        
            foreach($splitted_packages as $k => $splitted_package_items){
                    $packages[] = array(
                        'contents'        => $splitted_package_items,
                        'contents_cost'   => array_sum( wp_list_pluck( $splitted_package_items, 'line_total' ) ),
                        'user'            => array(
                             'ID' => get_current_user_id(),
                        ),
                        'destination'    => array(
                            'country'    => $wc["customer"]["get_shipping_country"],
                            'state'      => $wc["customer"]["get_shipping_state"],
                            'postcode'   => $wc["customer"]["get_shipping_postcode"],
                            'city'       => $wc["customer"]["get_shipping_city"],
                            'address'    => $wc["customer"]["get_shipping_address"],
                            'address_2'  => $wc["customer"]["get_shipping_address_2"]
                        )
                    );
            }
        }
    
        return $packages;
    
    }
    
    $pks = wtf($wc);
    echo print_r($pks,1);
    
    ?>
    

    Here the result:

    Array
    (
        [0] => Array
            (
                [contents] => Array
                    (
                        [0] => Array
                            (
                                [0] => Array
                                    (
                                        [prod_id] => 1
                                        [shipping_group] => Array
                                            (
                                                [0] => plane
                                            )
    
                                        [line_total] => 11
                                        [needs_shipping] => 1
                                    )
    
                                [1] => Array
                                    (
                                        [prod_id] => 4
                                        [shipping_group] => Array
                                            (
                                                [0] => plane
                                            )
    
                                        [line_total] => 22
                                        [needs_shipping] => 1
                                    )
    
                                [2] => Array
                                    (
                                        [prod_id] => 7
                                        [shipping_group] => Array
                                            (
                                                [0] => plane
                                            )
    
                                        [line_total] => 32
                                        [needs_shipping] => 1
                                    )
    
                            )
    
                    )
    
                [contents_cost] => 0
                [user] => Array
                    (
                        [ID] => 1
                    )
    
                [destination] => Array
                    (
                        [country] => Italy
                        [state] => Not yet shipped
                        [postcode] => 32029
                        [city] => Beautiful Field
                        [address] => Road of Trees
                        [address_2] => 
                    )
    
            )
    
        [1] => Array
            (
                [contents] => Array
                    (
                        [0] => Array
                            (
                                [0] => Array
                                    (
                                        [prod_id] => 2
                                        [shipping_group] => Array
                                            (
                                                [0] => truck
                                            )
    
                                        [line_total] => 14
                                        [needs_shipping] => 1
                                    )
    
                                [1] => Array
                                    (
                                        [prod_id] => 5
                                        [shipping_group] => Array
                                            (
                                                [0] => truck
                                            )
    
                                        [line_total] => 24
                                        [needs_shipping] => 1
                                    )
    
                                [2] => Array
                                    (
                                        [prod_id] => 8
                                        [shipping_group] => Array
                                            (
                                                [0] => truck
                                            )
    
                                        [line_total] => 34
                                        [needs_shipping] => 1
                                    )
    
                            )
    
                    )
    
                [contents_cost] => 0
                [user] => Array
                    (
                        [ID] => 1
                    )
    
                [destination] => Array
                    (
                        [country] => Italy
                        [state] => Not yet shipped
                        [postcode] => 32029
                        [city] => Beautiful Field
                        [address] => Road of Trees
                        [address_2] => 
                    )
    
            )
    
        [2] => Array
            (
                [contents] => Array
                    (
                        [0] => Array
                            (
                                [0] => Array
                                    (
                                        [prod_id] => 3
                                        [shipping_group] => Array
                                            (
                                                [0] => 11
                                                [1] => 15
                                                [2] => 17
                                            )
    
                                        [line_total] => 16
                                        [needs_shipping] => 1
                                    )
    
                                [1] => Array
                                    (
                                        [prod_id] => 6
                                        [shipping_group] => Array
                                            (
                                                [0] => 11
                                                [1] => 15
                                                [2] => 17
                                            )
    
                                        [line_total] => 26
                                        [needs_shipping] => 1
                                    )
    
                                [2] => Array
                                    (
                                        [prod_id] => 9
                                        [shipping_group] => Array
                                            (
                                                [0] => 11
                                                [1] => 15
                                                [2] => 17
                                            )
    
                                        [line_total] => 36
                                        [needs_shipping] => 1
                                    )
    
                            )
    
                    )
    
                [contents_cost] => 0
                [user] => Array
                    (
                        [ID] => 1
                    )
    
                [destination] => Array
                    (
                        [country] => Italy
                        [state] => Not yet shipped
                        [postcode] => 32029
                        [city] => Beautiful Field
                        [address] => Road of Trees
                        [address_2] => 
                    )
    
            )
    
    )
    
    

    To clarify, I divide the script into its basic parts below

    Data structure: I used Array of array but the sintax of your WC Class and methods call can be simply identify.

    $wc=[
        "customer"=>[
            "get_shipping_country"=>"Italy",
            "get_shipping_state"=>"Not yet shipped",
            "get_shipping_postcode"=>"32029",
            "get_shipping_city"=>"Beautiful Field",
            "get_shipping_address"=>"Road of Trees",
            "get_shipping_address_2"=>""
        ],
        "cart"=> [
            "get_contents" => [
                    ["prod_id"=>1, "shipping_group"=>["plane"],'line_total'=>11.00 ,'needs_shipping'=>true],
                    ["prod_id"=>2, "shipping_group"=>["truck"],'line_total'=>14.00 ,'needs_shipping'=>true],
                    ["prod_id"=>3, "shipping_group"=>[ 11, 15, 17],'line_total'=>16.00,'needs_shipping'=>true],
                    ["prod_id"=>4, "shipping_group"=>["plane"],'line_total'=>22.00 ,'needs_shipping'=>true],
                    ["prod_id"=>5, "shipping_group"=>["truck"],'line_total'=>24.00 ,'needs_shipping'=>true],
                    ["prod_id"=>6, "shipping_group"=>[ 11, 15, 17],'line_total'=>26.00,'needs_shipping'=>true],
                    ["prod_id"=>7, "shipping_group"=>["plane"],'line_total'=>32.00 ,'needs_shipping'=>true],
                    ["prod_id"=>8, "shipping_group"=>["truck"],'line_total'=>34.00 ,'needs_shipping'=>true],
                    ["prod_id"=>9, "shipping_group"=>[ 11, 15, 17],'line_total'=>36.00,'needs_shipping'=>true]
                ]
        ]
    ];
    
    $wc["cart"]["get_cart"]=[
                    'contents' => $wc["cart"]["get_contents"],
                    'contents_cost'   => array_sum( wp_list_pluck( $wc["cart"]["get_contents"], 'line_total' ) ),
                    'user'            => array('ID' => get_current_user_id()),
                    'destination'    => [
                        'country'    => $wc["customer"]["get_shipping_country"],
                        'state'      => $wc["customer"]["get_shipping_state"],
                        'postcode'   => $wc["customer"]["get_shipping_postcode"],
                        'city'       => $wc["customer"]["get_shipping_city"],
                        'address'    => $wc["customer"]["get_shipping_address"],
                        'address_2'  => $wc["customer"]["get_shipping_address_2"]
                    ]   
                ];
    

    The i create Fake Woocommerce function in order for the script to work

    function get_current_user_id(){
        return 1;
    }
    function wp_list_pluck($items,$column){
        $ares=[];
        foreach($items as $item){
            foreach($item as $k=>$v){
                if( $k==$column){
                    $ares[]=$v;
                }
            }
        }
        return $ares;
    }
    function add_filter(){
        //do nothing
    }
    
    

    Then some function to support the process

    
    function arrarr_unique($a){
        $l=[];$r=[];
        foreach($a as $e){
           $l[]=json_encode($e);
        }
        $lu = array_unique($l);
        foreach($lu as $e){
            $r[]=json_decode($e);
        }
        return $r;
    }
    
    function filter_match_shipping($items, $array_group){
        $res=[];
        foreach($items as $item){
            if ($item["shipping_group"]==$array_group){
                $res[]=$item;
            }
        }
        return $res;
    }
    
    

    The function of the Woocommerce Filter to add .

    add_filter( 'woocommerce_cart_shipping_packages', 'wtf' );
    
    function wtf($wc,$packages=[]){
        
        $cts = $wc["cart"]["get_contents"];
        $groups = arrarr_unique(wp_list_pluck($cts,'shipping_group'));
    
        //Settings 
        $splitted_packages=[];
        foreach($groups as $g){
            $k=json_encode($g);        
            $splitted_packages[$k]=[];
        }
        //Fill 
        foreach($groups as $g){
            $k=json_encode($g);        
            $splitted_packages[$k][] = filter_match_shipping( $cts,$g );
        }
    
        // Add grouped items as packages 
        if(is_array($splitted_packages)){
            $c=0;        
            foreach($splitted_packages as $k => $splitted_package_items){
                    $packages[] = array(
                        'contents'        => $splitted_package_items,
                        'contents_cost'   => array_sum( wp_list_pluck( $splitted_package_items, 'line_total' ) ),
                        'user'            => array(
                             'ID' => get_current_user_id(),
                        ),
                        'destination'    => array(
                            'country'    => $wc["customer"]["get_shipping_country"],
                            'state'      => $wc["customer"]["get_shipping_state"],
                            'postcode'   => $wc["customer"]["get_shipping_postcode"],
                            'city'       => $wc["customer"]["get_shipping_city"],
                            'address'    => $wc["customer"]["get_shipping_address"],
                            'address_2'  => $wc["customer"]["get_shipping_address_2"]
                        )
                    );
            }
        }
    
        return $packages;
    
    }
    
    $pks = wtf($wc);
    echo print_r($pks,1);
    

    It is possible that there are some tweaks to do that I will do with pleasure. For any clarification or problem solving. write me in the comments.

    Login or Signup to reply.
  2. At this point you should be able to overcome the obstacle. Please note that you have not given any information on the data structure of $ packages so it was a great stretch of the imagination. You could change the script a bit to fit the data structure of $packages from woocommerce.

    You need this two function to support the process

    function arrarr_unique($a){
        $l=[];$r=[];
        foreach($a as $e){
           $l[]=json_encode($e);
        }
        $lu = array_unique($l);
        foreach($lu as $e){
            $r[]=json_decode($e);
        }
        return $r;
    }
    
    function filter_match_shipping($items, $array_group,$fieldname='shipping_group'){
    
        $res=[];
        foreach($items as $item){
            if ($item[$fieldname]==$array_group){
                $res[]=$item;
            }
        }
        return $res;
    }
    
    

    And here wf_split_cart_by_shipping_class_group function

    #Please consider that i do not have your data structure so it can differ a little to works properly
    
    #However, it would be nice to know what the data structure of $packages is to Help you.
    
    
    add_filter( 'woocommerce_cart_shipping_packages', 'wf_split_cart_by_shipping_class_group');
    
    function wf_split_cart_by_shipping_class_group($packages){
    
        
        $cts = WC()->cart->get_cart();
    
        # Try also:
        # $cts = $packages;
        
        # shipping_group is the field name in your woocommerce? if not , change it with the name of your table cart item field name
        $groups = arrarr_unique(wp_list_pluck($cts,'shipping_group'));
    
        //Settings 
        $splitted_packages=[];
        foreach($groups as $g){
            $k=json_encode($g);
            $splitted_packages[$k]=[];
        }
        //Fill 
        foreach($groups as $g){
            $k=json_encode($g);
            $splitted_packages[$k][] = filter_match_shipping( $cts,$g,'shipping_group');
        }
    
        // Add grouped items as packages 
        if(is_array($splitted_packages)){
            foreach($splitted_packages as $k => $splitted_package_items){
    
                $packages[] = array(
                    'contents'        => $splitted_package_items,
                    'contents_cost'   => array_sum( wp_list_pluck( $splitted_package_items, 'line_total' ) ),
                    #'applied_coupons' => WC()->cart->get_applied_coupons(),
                    'user'            => array(
                         'ID' => get_current_user_id(),
                    ),
                    'destination'    => array(
                        'country'    => WC()->customer->get_shipping_country(),
                        'state'      => WC()->customer->get_shipping_state(),
                        'postcode'   => WC()->customer->get_shipping_postcode(),
                        'city'       => WC()->customer->get_shipping_city(),
                        'address'    => WC()->customer->get_shipping_address(),
                        'address_2'  => WC()->customer->get_shipping_address_2()
                    )
                );
    
            }
        }
    
        return $packages;
    
    }
    
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search