skip to Main Content

I’d like to do per product shipping programmatically. And I don’t want to use the plugin. This seems like it would easy:

  1. add meta field called “shipping_price” for each product.
  2. hook into checkout and update shipping based off each products “shipping_price” that’s in your cart

I know how to do #1. but any ideas on the best way to achieve #2?

2

Answers


  1. Chosen as BEST ANSWER

    Expanding on 7uc1f3rs answer. I had to slightly modify to get it to work with WooCommerce 3.0+ new way of doing it.

    $rates[$rate_key]->cost = $cost;
    

    needs to be

    $rates[$rate_key]->set_cost($cost);
    

    You can use functions from https://docs.woocommerce.com/wc-apidocs/class-WC_Shipping_Rate.html for $rates

    function filter_woocommerce_package_rates( $rates, $package ) {
    if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return;
    
    // Set variable
    $cost = 0; 
    
    // Loop through line items
    foreach( $package['contents'] as $line_item ) {
        // Get product id
        $product_id = $line_item['product_id'];
    
        // Quantity
        $quantity = $line_item['quantity'];
    
        // Get post meta
        //$shipping_price = get_post_meta( $product_id, 'shipping_price', true);
    
        // DEBUG, for testing purposes, REMOVE AFTERWARDS!!
        $shipping_price = 10;
    
        if ( $shipping_price ) {
            $cost += $shipping_price * $quantity;
        }
    }
    
    if ( $cost > 0 ) {
        // (Multiple)
        foreach ( $rates as $rate_key => $rate ) {
    
            // Targeting
            if ( in_array( $rate->method_id, array( 'free_shipping', 'flat_rate' ) ) ) {
                // Set rate cost
                // use functions from https://docs.woocommerce.com/wc-apidocs/class-WC_Shipping_Rate.html
                $rates[$rate_key]->set_cost($cost);
            }
        }
    
        // Single
        // Set rate cost
        //$rates['flat_rate:1']->set_cost($cost);
    
        // use this to see your rates
        //echo '<pre>'; print_r($rates); echo '</pre>';
    }
    
    return $rates;
    }
    add_filter( 'woocommerce_package_rates', 'filter_woocommerce_package_rates', 100, 2 );
    

  2. This can be done in the following way, using get_post_meta to get the meta field 'shipping_price'

    Note 1: to test this code added a line with dummy data

    Note 2: Don’t forget to specify the $rate->method_id

    function filter_woocommerce_package_rates( $rates, $package ) {
        if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return;
    
        // Set variable
        $cost = 0; 
    
        // Loop through line items
        foreach( $package['contents'] as $line_item ) {
            // Get product id
            $product_id = $line_item['product_id'];
    
            // Quantity
            $quantity = $line_item['quantity'];
    
            // Get post meta
            $shipping_price = get_post_meta( $product_id, 'shipping_price', true);
    
            // DEBUG, for testing purposes, REMOVE AFTERWARDS!!
            $shipping_price = 10;
    
            if ( $shipping_price ) {
                $cost += $shipping_price * $quantity;
            }
        }
    
        if ( $cost > 0 ) {
            // (Multiple)
            foreach ( $rates as $rate_key => $rate ) {
    
                // Targeting
                if ( in_array( $rate->method_id, array( 'free_shipping', 'distance_rate', 'table_rate' ) ) ) {
                    // Set rate cost
                    $rates[$rate_key]->cost = $cost;
                }
            }   
    
            // Single
            // Set rate cost
            // $rates['free_shipping']->cost = $cost;
        }
    
        return $rates;
    }
    add_filter( 'woocommerce_package_rates', 'filter_woocommerce_package_rates', 100, 2 );
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search