0

WordPress 5.9.2 and WooCommerce 6.3.1 Using this code:

public function calculate_shipping( $package = array() ) {

    global $woocommerce;

    $address['suburb']   = $package['destination']['city'];
    $address['state']    = $package['destination']['state'];
    $address['postcode'] = $package['destination']['postcode'];
    $address['country']  = $package['destination']['country'];

    $i           = 0;
    $totalweight = 0;
    $totalprice  = 0;

    foreach ( $woocommerce->cart->get_cart() as $item_id => $values ) {
        $_product = $values['data'];
        $q        = 1;
        while ( $values['quantity'] >= $q ) {
            $products[ $i ]->length = $_product->length;
            $products[ $i ]->height = $_product->height;
            $products[ $i ]->width  = $_product->width;
            $products[ $i ]->weight = $_product->weight;
            $totalweight           += $_product->weight;
            $totalprice            += $_product->get_price();
            $q++;
            $i++;
        }
    }
}

relating to length, height, width and weight:
$products[$i]->length = $_product->length;

Howard E
  • 5,454
  • 3
  • 15
  • 24
  • Well it means that `$products[$i]` is null (or not set at all), for the current value of $i. I don't see where `$products` is supposed to come from here at all, it does not get passed into the method as a parameter, is not imported via `global`, and does not get created before those lines either. – CBroe Apr 13 '22 at 06:55
  • It is an extension of WC_Shipping_Method, the code has always worked and was able to retrieve/obtain the products dimensions and weight to use in a API request, it may have had a warning for a while although in PHP 8 it fails, just though I would ask if anyone had run into the same issue, looks like a will be recoding if I cannot find a fix.:( – AquaMarine1 Apr 13 '22 at 07:52
  • 1
    I can't tell if those `$products` are supposed to exist at this point already, or if they should get created - if the latter, then try `if(!isset($products[$i])) { $products[$i] = new stdClass; }` as first line inside the while loop. – CBroe Apr 13 '22 at 07:59
  • `$products` is un-declared as an array, aside from that, `$_product` which should be defined isn't. Look at these answers https://stackoverflow.com/questions/28576667/get-cart-item-name-quantity-all-details-woocommerce as it would appear you are getting the `$_product` incorrectly. – Howard E Apr 13 '22 at 09:55
  • @CBroe Your last suggestion worked – AquaMarine1 Apr 14 '22 at 03:58

1 Answers1

0

Firstly, let's create a standalone example that can be tested more easily:

class Example {
    public $length, $height, $width, $weight;
    
    public function __construct($length, $height, $width, $weight) {
        $this->length = $length;
        $this->height = $height;
        $this->width = $width;
        $this->weight = $weight;
    }
    
    public function get_price() {
        return 1.23;
    }
}

$sample_data = [
    42 => ['quantity' => 2, 'data' => new Example(42, 42, 42, 42)],
    69 => ['quantity' => 1, 'data' => new Example(69, 69, 69, 69)],
];

$i           = 0;
$totalweight = 0;
$totalprice  = 0;

foreach ( $sample_data as $item_id => $values ) {
    $_product = $values['data'];
    $q        = 1;
    while ( $values['quantity'] >= $q ) {
        $products[ $i ]->length = $_product->length;
        $products[ $i ]->height = $_product->height;
        $products[ $i ]->width  = $_product->width;
        $products[ $i ]->weight = $_product->weight;
        $totalweight           += $_product->weight;
        $totalprice            += $_product->get_price();
        $q++;
        $i++;
    }
}

var_dump($products);

Now we can see what this did on older versions of PHP, for instance using this handy tool which runs the same code on multiple versions.

The output in PHP 7.4 is this:

Warning: Creating default object from empty value in /in/1Imu2 on line 31

Warning: Creating default object from empty value in /in/1Imu2 on line 31

Warning: Creating default object from empty value in /in/1Imu2 on line 31
array(3) {
  [0]=>
  object(stdClass)#3 (4) {
    ["length"]=>
    int(42)
    ["height"]=>
    int(42)
    ["width"]=>
    int(42)
    ["weight"]=>
    int(42)
  }
  [1]=>
  object(stdClass)#4 (4) {
    ["length"]=>
    int(42)
    ["height"]=>
    int(42)
    ["width"]=>
    int(42)
    ["weight"]=>
    int(42)
  }
  [2]=>
  object(stdClass)#5 (4) {
    ["length"]=>
    int(69)
    ["height"]=>
    int(69)
    ["width"]=>
    int(69)
    ["weight"]=>
    int(69)
  }
}

So we can see that what's happening is that for each item, the code is implicitly creating a stdClass object, before assigning properties on it. The fix is therefore to make that creation explicit by writing $products[ $i ] = new stdClass; just before $products[ $i ]->length = $_product->length; While we're at it, we should also create $products as an empty array with $products = []; before the foreach loop.

Running our modified code in the same tool we can see that it now gives the same result on every PHP version from PHP 5.4 up to and including 8.1, with no Warnings.

IMSoP
  • 89,526
  • 13
  • 117
  • 169