How to Fix “Attempt to Read Property ‘cart’ on Null” in WooCommerce

The PHP warning “Attempt to read property ‘cart’ on null” can appear on WooCommerce websites after upgrading the server to PHP 8.1 or PHP 8.2.

In this case, the warning was generated by the Abandoned Cart Recovery for WooCommerce plugin:

PHP Warning: Attempt to read property "cart" on null in
/wp-content/plugins/woo-abandoned-cart-recovery/includes/execute/abandoned-cart.php
on line 299

The warning does not always break the checkout, but it can repeatedly fill the PHP error log, hide more important errors, and indicate that the plugin is trying to process invalid or empty cart data.

This guide explains why the warning occurs and provides a safe repair that validates the cart data before attempting to access its cart property.

What Causes the “Attempt to Read Property cart on Null” Warning?

The warning means PHP expected an object but received null.

The problematic code is commonly similar to this:

$cart_1 = json_decode( $cart_1 )->cart;
$cart_2 = json_decode( $cart_2 )->cart;

The code assumes that json_decode() will always return an object containing a property named cart.

However, abandoned-cart data can sometimes be:

  • An empty string
  • Invalid JSON
  • Incomplete session data
  • Previously deleted cart data
  • A cart that became empty after checkout
  • A malformed or expired abandoned-cart record

When json_decode() cannot decode the supplied value, PHP returns null. The plugin then immediately attempts to access:

->cart

Because null is not an object, PHP generates the warning.

The PHP manual confirms that json_decode() returns null when JSON cannot be decoded or exceeds the permitted nesting depth.

Why It Becomes More Visible Under PHP 8.2

Older PHP versions were often more forgiving about code that attempted to read properties from unexpected values.

PHP 8 produces clearer warnings for unsafe object-property access. The warning is therefore usually exposing an existing edge case in the plugin rather than indicating that WooCommerce itself has suddenly lost the customer’s cart.

The Abandoned Cart Recovery for WooCommerce plugin is developed by VillaTheme and stores cart information so unfinished WooCommerce orders can be recovered later.

Back Up the Website Before Editing

The repair requires editing a plugin file. Before continuing:

  1. Create a full website backup.
  2. Download a copy of the original PHP file.
  3. Test the change on staging when possible.
  4. Confirm that WooCommerce and the abandoned-cart plugin are updated.
  5. Record the current plugin version.

The affected file is normally located at:

/wp-content/plugins/woo-abandoned-cart-recovery/includes/execute/abandoned-cart.php

A future plugin update may replace the edited file, so this should be treated as a temporary compatibility patch until the plugin developer includes an official fix.

First Check the Exact Problematic Line

Line numbers can change between plugin versions.

Open:

/wp-content/plugins/woo-abandoned-cart-recovery/includes/execute/abandoned-cart.php

Then locate line 299 or search the file for:

json_decode

You may find code resembling:

$cart_1 = json_decode( $cart_1 )->cart;
$cart_2 = json_decode( $cart_2 )->cart;

You may also find it inside a method named:

compare_cart

This is the most likely source when the warning occurs while the plugin compares the previously saved cart with the current cart.

Recommended Fix: Safely Validate Decoded Cart Data

Replace the existing compare_cart() method with the version below.

Do not paste this code into functions.php. It must replace the existing method inside the plugin’s Abandoned_Cart class.

public function compare_cart( $cart_1, $cart_2 ) {

	/*
	 * Extract the cart safely from JSON, arrays, or objects.
	 * Invalid and empty values are converted to empty arrays.
	 */
	$extract_cart = static function ( $value ) {

		if ( is_string( $value ) ) {

			if ( '' === trim( $value ) ) {
				return array();
			}

			$decoded = json_decode( $value );

			if (
				! is_object( $decoded ) ||
				! isset( $decoded->cart )
			) {
				return array();
			}

			$value = $decoded->cart;

		} elseif (
			is_object( $value ) &&
			isset( $value->cart )
		) {
			$value = $value->cart;
		}

		if (
			! is_array( $value ) &&
			! is_object( $value )
		) {
			return array();
		}

		return (array) $value;
	};

	$cart_1 = $extract_cart( $cart_1 );
	$cart_2 = $extract_cart( $cart_2 );

	if ( count( $cart_1 ) !== count( $cart_2 ) ) {
		return false;
	}

	$temp_1 = array();
	$temp_2 = array();

	foreach ( $cart_1 as $item ) {

		if ( is_array( $item ) ) {
			$item = (object) $item;
		}

		if ( ! is_object( $item ) ) {
			continue;
		}

		$product_id = ! empty( $item->variation_id )
			? (int) $item->variation_id
			: ( ! empty( $item->product_id )
				? (int) $item->product_id
				: 0
			);

		if ( ! $product_id ) {
			continue;
		}

		$quantity = isset( $item->quantity )
			? (float) $item->quantity
			: 0;

		$temp_1[ $product_id ] = $quantity;
	}

	foreach ( $cart_2 as $item ) {

		if ( is_array( $item ) ) {
			$item = (object) $item;
		}

		if ( ! is_object( $item ) ) {
			continue;
		}

		$product_id = ! empty( $item->variation_id )
			? (int) $item->variation_id
			: ( ! empty( $item->product_id )
				? (int) $item->product_id
				: 0
			);

		if ( ! $product_id ) {
			continue;
		}

		$quantity = isset( $item->quantity )
			? (float) $item->quantity
			: 0;

		$temp_2[ $product_id ] = $quantity;
	}

	ksort( $temp_1 );
	ksort( $temp_2 );

	return $temp_1 === $temp_2;
}

What This Repair Changes

The revised method no longer assumes that every value contains valid JSON.

It first checks whether the value is a string. When it is empty, it returns an empty cart instead of passing the value to json_decode().

When the value contains JSON, it checks that the decoded result is an object and that the cart property exists before reading it.

The essential safety check is:

if (
	! is_object( $decoded ) ||
	! isset( $decoded->cart )
) {
	return array();
}

This prevents code such as the following from being executed on a null value:

$decoded->cart

Smaller Patch for the Existing Method

When you prefer to keep the rest of the original method unchanged, replace only the unsafe cart-decoding section.

Use:

if ( is_string( $cart_1 ) ) {

	$decoded_1 = '' !== trim( $cart_1 )
		? json_decode( $cart_1 )
		: null;

	$cart_1 = (
		is_object( $decoded_1 ) &&
		isset( $decoded_1->cart )
	)
		? $decoded_1->cart
		: array();

} elseif (
	is_object( $cart_1 ) &&
	isset( $cart_1->cart )
) {
	$cart_1 = $cart_1->cart;
} elseif ( ! is_array( $cart_1 ) ) {
	$cart_1 = array();
}

if ( is_string( $cart_2 ) ) {

	$decoded_2 = '' !== trim( $cart_2 )
		? json_decode( $cart_2 )
		: null;

	$cart_2 = (
		is_object( $decoded_2 ) &&
		isset( $decoded_2->cart )
	)
		? $decoded_2->cart
		: array();

} elseif (
	is_object( $cart_2 ) &&
	isset( $cart_2->cart )
) {
	$cart_2 = $cart_2->cart;
} elseif ( ! is_array( $cart_2 ) ) {
	$cart_2 = array();
}

This is close to the original plugin behavior while preventing the PHP warning.

Alternative Cause: WooCommerce Session Is Null

The same warning can also occur when the affected line contains:

WC()->session->cart

or:

wc()->session->cart

In that situation, PHP is warning that session is null when the code attempts to read its cart property.

Add a session guard before accessing cart data:

if (
	! function_exists( 'WC' ) ||
	! WC() ||
	! WC()->cart ||
	! WC()->session
) {
	return;
}

Then replace direct magic-property access:

WC()->session->cart

with the official session getter:

WC()->session->get( 'cart', array() )

For example:

$cart_count  = WC()->cart->get_cart_contents_count();
$session_cart = WC()->session->get( 'cart', array() );

$abdc_data = $cart_count
	? wp_json_encode(
		array(
			'cart'     => is_array( $session_cart )
				? $session_cart
				: array(),
			'currency' => get_woocommerce_currency(),
		)
	)
	: '';

WooCommerce’s WC_Session class provides the get() method for reading a session variable and permits a default value when the requested variable is unavailable.

Do Not Use Curly Quotes in PHP

Make sure the code contains normal straight quotation marks:

'cart'

Do not use typographic or curly quotes such as:

‘cart’
“cart”

Curly quotation marks are commonly introduced when PHP code is copied from word processors, email clients, or formatted documents. They are not valid replacements for normal PHP string delimiters and can produce a syntax error.

Always copy the code directly from a code block.

How to Test the Repair

After saving the modified file, clear every relevant cache layer:

  • WordPress page cache
  • Object cache
  • Server cache
  • CDN or Cloudflare cache
  • PHP OPcache, when available

Then test these actions:

  1. Visit a product page in an incognito window.
  2. Add a product to the cart.
  3. Change the product quantity.
  4. Remove the product from the cart.
  5. Restore the removed product when the option is available.
  6. Add the product again.
  7. Complete a test checkout.
  8. Log in while a guest cart exists.
  9. Check the abandoned-cart records in WordPress.
  10. Review the PHP error log.

The warning should no longer be added to the log.

Also confirm that:

  • Products remain in the cart normally.
  • Abandoned carts are still being recorded.
  • Cart recovery links still work.
  • Completed orders remove or mark the abandoned-cart record correctly.
  • Recovery emails are not sent repeatedly.
  • Guest and logged-in carts are both handled properly.

Clear the Existing Error Log

Once the repair has been tested, download a copy of the old error log and then clear or rotate it.

This makes it easier to determine whether the warning returns after the repair.

Do not assume the issue is fixed merely because the warning is no longer visible on the frontend. WordPress often hides PHP warnings from visitors while continuing to write them into server logs.

Do Not Fix It by Hiding PHP Warnings

It may be tempting to suppress the warning by changing error_reporting, disabling WordPress debugging, or hiding warnings through the hosting panel.

That does not repair the underlying problem.

The plugin would continue attempting to read a property from invalid data, but the warning would no longer be visible. This can hide related checkout, session, or abandoned-cart problems.

The correct approach is to validate the value before accessing the property.

Will a Plugin Update Remove the Repair?

Yes. Editing a file inside:

/wp-content/plugins/

means the modification can be overwritten when the plugin is updated.

After every Abandoned Cart Recovery update:

  1. Review the plugin changelog.
  2. Check whether the developer has fixed the null-cart warning.
  3. Compare the updated compare_cart() method with your repair.
  4. Remove the custom patch when the official version includes equivalent validation.
  5. Retest the cart and checkout process.

The plugin’s official WordPress.org page provides its current version, changelog, support link, and development information.

Should the Whole Plugin File Be Replaced?

No.

Do not replace the entire abandoned-cart.php file with code copied from another website or a different plugin version.

Plugin files can change between releases. Replacing the complete file may remove:

  • Security improvements
  • WooCommerce compatibility changes
  • Database handling changes
  • HPOS compatibility
  • New hooks
  • Bug fixes
  • Translation updates

Edit only the affected method or unsafe lines unless you have compared both complete files carefully.

Can This Code Be Added to functions.php?

No.

The compare_cart() method belongs to the plugin’s namespaced Abandoned_Cart class. Adding another function with the same name to the active theme will not replace the class method.

The repair must be made inside the affected class unless the plugin developer provides a filter, action, class override, or another extension mechanism.

Is This a WooCommerce Core Error?

The file path shows that the warning originates from the abandoned-cart plugin:

/wp-content/plugins/woo-abandoned-cart-recovery/

WooCommerce provides the cart and session systems, but the unsafe property access occurs in the extension’s cart-comparison logic.

The repair therefore belongs in the abandoned-cart plugin code rather than WooCommerce core.

Never edit files inside:

/wp-content/plugins/woocommerce/

to repair a warning that originates from a different plugin.

Final Solution

The “Attempt to read property ‘cart’ on null” warning occurs because the abandoned-cart code assumes that decoded JSON or a WooCommerce session will always contain valid cart data.

Empty or invalid JSON causes json_decode() to return null. Accessing ->cart immediately afterward generates the PHP warning.

The correct solution is to:

  • Check that JSON decoding returned an object.
  • Confirm that the cart property exists.
  • Convert invalid or empty data to an empty array.
  • Confirm that WooCommerce cart and session objects exist.
  • Use WC()->session->get() rather than unsafe direct access where appropriate.
  • Test cart removal, login, recovery, and checkout actions.
  • Report the issue to the plugin developer for a permanent update-safe fix.

This repair prevents the warning without simply hiding PHP errors and allows the abandoned-cart process to handle empty or malformed cart data safely.

Leave a Comment