Article WooCommerce

PHP 8.6 is coming: a small change that can break the return from a payment gateway

PHP 8.6 ships in November and, alongside new features, makes session defaults stricter. For stores that handle the return from a bank gateway with PHP sessions, that can mean orders that were paid but never get confirmed.

Hamid Aarab Senior WordPress and WooCommerce Backend Developer
Published
Reading time
5 min read

Hamid Aarab October 27, 2026 5 min read

Pixel cover: a bitten cookie and the PHP 8.6 session settings
Contents (8)

Every new PHP release comes with a list of exciting features, and PHP 8.6 is no exception. But this time the most important change for many stores is not on the feature list. It is on the list of backward-incompatible changes, as three lines that change the session defaults.

According to the official schedule, PHP 8.6 ships on 19 November 2026, about three weeks from now. If you run a store or a plugin that talks to a bank payment gateway, read on.

Three new session defaults

The “Secure Session Configuration Defaults” RFC was accepted almost unanimously. From PHP 8.6, these three settings are on by default:

  • **session.use_strict_mode = 1:** PHP no longer accepts a session ID it did not create.
  • **session.cookie_httponly = 1:** JavaScript can no longer read the session cookie through document.cookie.
  • **session.cookie_samesite = Lax:** the browser does not send the session cookie with POST requests coming from another site.

All three are right from a security point of view. The first two are painless for most sites. The third hits exactly where many payment integrations live.

Where it breaks: the return from the bank

With many bank gateways, the payment flow looks like this: the customer clicks “Pay” on your site, goes to the bank’s page, pays, and the bank sends them back to your return URL with a POST form.

To the browser, that is a POST from the bank’s domain to yours: a cross-site POST. With the new SameSite=Lax default, the browser does not send PHP’s session cookie with that request.

The return from a bank gateway and the session cookie left behind by SameSite=Lax
With SameSite=Lax, PHP’s session cookie is not sent on the bank’s POST back to your site.

Now suppose your gateway plugin stored the order number or amount in $_SESSION before sending the customer to the bank, and reads it back on return. On PHP 8.6 with default settings, the session is empty at that moment. The result can be an order whose money left the customer’s account but which stays “unpaid” on your site: exactly the support ticket no store owner wants.

An important detail: WordPress core does not use PHP sessions, and WooCommerce manages its own session with a cookie and the database. So the problem lies with plugins, themes and custom code that call session_start() themselves. In payment gateway plugins, that pattern is far from rare.

First: find out whether you are affected

A simple search through plugins and the theme is enough:

grep -rnE "session_start|\$_SESSION" wp-content/plugins wp-content/themes \
  --include=*.php | grep -v "/vendor/"

Any hit inside a payment gateway plugin or on the return path from the bank needs a closer look.

Second: the right fix

The real fix is for the return path not to depend on the session at all. This pattern works on PHP 8.6 and is safer anyway:

  1. Put the order identifier in the return URL itself. WooCommerce gives each order a random key (order_key); build the return URL with the order ID and that key.
  2. On return, find the order from the URL, compare the key with hash_equals(), and read the amount from the order itself, not from anything that came from outside.
  3. Always finalise the payment through the bank’s verify API. Never trust only the parameters the bank sent back.
// Building the return URL before redirecting to the bank.
$callback = add_query_arg(
	array(
		'order' => $order->get_id(),
		'key'   => $order->get_order_key(),
	),
	WC()->api_request_url( 'my_gateway' )
);

// On return: find the order from the URL, not from $_SESSION.
$order = wc_get_order( absint( $_GET['order'] ?? 0 ) );
if ( ! $order || ! hash_equals( $order->get_order_key(), (string) ( $_GET['key'] ?? '' ) ) ) {
	wp_die( esc_html__( 'Invalid payment return.', 'my-gateway' ), 400 );
}
// Then verify the transaction with the bank's API using $order->get_total().

If the plugin’s code is not yours, open a ticket with its author and ask explicitly whether it has been tested with session.cookie_samesite=Lax.

A temporary workaround, with care

If you cannot fix it before PHP 8.6 arrives, you can restore the old default: leave session.cookie_samesite empty in php.ini, or, for that path only, set None with secure via session_set_cookie_params(). Remember that this removes a layer of protection against CSRF. Treat it as a painkiller, not a cure.

New features worth a look

PHP 8.6 is not only about sessions. A few features make everyday code cleaner:

  • Partial function application: pre-fill some arguments and leave the rest as ?. It pairs nicely with PHP 8.5’s pipe operator, which only accepts single-argument callables.
  • **clamp():** keeps a value between a minimum and a maximum, such as a discount percentage that must stay between 0 and 100.
  • **Time\Duration:** a class for time spans, with methods for arithmetic and direct comparison.
$slug = str_replace( ' ', '-', ? );          // partial application
echo $slug( 'Hello World' );                 // Hello-World
echo 'Hello World' |> $slug;                 // works with the pipe operator too
$percent = clamp( $discount, min: 0, max: 100 );

Summary

PHP 8.6 is not a loud release, but its new session defaults are the kind of change that breaks things silently. The good news: you still have three weeks. Search your payment gateway code once, fix it if it relies on $_SESSION, and before upgrading the server, run one test payment end to end on PHP 8.6.

Sources

$ ./request_review

Facing the same problem in your own store?

Senior WordPress and WooCommerce backend engineering for complex production problems.

Request a Technical Assessment

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *