Automattic / woocommerce-subscriptions-core

Subscriptions core package for WooCommerce
Other
80 stars 29 forks source link

PHP Fatal error in "class-wcs-cart-renewal.php" #572

Closed mmca101 closed 3 months ago

mmca101 commented 4 months ago

https://github.com/Automattic/woocommerce-subscriptions-core/blob/b49b64021f3417f6d26d6c065330cfcce40aacbc/includes/class-wcs-cart-renewal.php#L418

Im getting a similar error as mentioned in Issue#568 :

PHP Fatal error: Uncaught TypeError: array_sum(): Argument #1 ($array) must be of type array, null given in /wp-content/plugins/woocommerce-subscriptions/vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-renewal.php:449

Adding an extra check in the "get_cart_item_from_session" function (@class-wcs-cart-renewal.php) to see if the line item ID exists in the subscription items array seems to fix this too. Checks added are commented with HOTFIX:


    /**
     * Restore renewal flag when cart is reset and modify Product object with renewal order related info
     *
     * @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.0
     */

     public function get_cart_item_from_session( $cart_item_session_data, $cart_item, $key ) {

        if ( $this->should_honor_subscription_prices( $cart_item ) ) {
            $cart_item_session_data[ $this->cart_item_key ] = $cart_item[ $this->cart_item_key ];

            $_product = $cart_item_session_data['data'];

            // Need to get the original subscription or order price, not the current price
            $subscription = $this->get_order( $cart_item );

            if ( $subscription ) {
                $subscription_items = $subscription->get_items();

                // HOTFIX - Check if the line item ID exists in the subscription items array to prevent a fatal error from wp core
                if ( isset( $cart_item_session_data[ $this->cart_item_key ]['line_item_id'] ) && isset( $subscription_items[ $cart_item_session_data[ $this->cart_item_key ]['line_item_id'] ] ) ) {
                    $item_to_renew = $subscription_items[ $cart_item_session_data[ $this->cart_item_key ]['line_item_id'] ];

                    $price = $item_to_renew['line_subtotal'];

                    if ( $_product->is_taxable() && $subscription->get_prices_include_tax() ) {

                        // If this item's subtracted tax data hasn't been repaired, do that now.
                        if ( isset( $item_to_renew['_subtracted_base_location_tax'] ) ) {
                            WC_Subscriptions_Upgrader::repair_subtracted_base_taxes( $item_to_renew->get_id() );

                            // The item has been updated so get a refreshed version of the item.
                            $item_to_renew = WC_Order_Factory::get_order_item( $item_to_renew->get_id() );
                        }

                        if ( isset( $item_to_renew['_subtracted_base_location_taxes'] ) ) {
                            $price += array_sum( $item_to_renew['_subtracted_base_location_taxes'] ) * $item_to_renew['qty'];
                        } else {
                            // HOTFIX - Check if the taxes array and subtotal key exist before accessing them to prevent fatal errors from wp core
                            if ( isset( $item_to_renew['taxes']['subtotal'] ) ) {
                                $price += array_sum( $item_to_renew['taxes']['subtotal'] ); // Use the taxes array items here as they contain taxes to a more accurate number of decimals.
                            }
                        }
                    }

                    // In rare cases quantity can be zero. Check first to prevent triggering a fatal error in php8+
                    if ( isset( $item_to_renew['qty'] ) && 0 !== (int) $item_to_renew['qty'] ) {
                        $_product->set_price( $price / $item_to_renew['qty'] );
                    }

                    // Don't carry over any sign up fee
                    wcs_set_objects_property( $_product, 'subscription_sign_up_fee', 0, 'set_prop_only' );

                    // Allow plugins to add additional strings to the product name for renewals
                    $line_item_name = is_callable( $item_to_renew, 'get_name' ) ? $item_to_renew->get_name() : $item_to_renew['name'];
                    wcs_set_objects_property( $_product, 'name', apply_filters( 'woocommerce_subscriptions_renewal_product_title', $line_item_name, $_product ), 'set_prop_only' );

                    // Make sure the same quantity is renewed
                    $cart_item_session_data['quantity'] = $item_to_renew['qty'];
                }
            }
        }

        return $cart_item_session_data;
    }
james-allan commented 3 months ago

Hey @mmca101 can you double check which version of Woo Subscriptions you have installed. This should have been fixed in v5.8.0 released in December 2023.

I'm going to close this in the mean time given I'm pretty confident the PR (https://github.com/Automattic/woocommerce-subscriptions-core/pull/544) fixed this very issue.