Fixing WooCommerce cart session dropping on checkout submission with Redis cache

WooCommerce session loss during checkout submission with Redis active occurs when the PHP session or WooCommerce session handler (WC_Session_Handler) gets flushed or invalidated during the transient object lifecycle. When Redis cache key eviction policies are improperly configured (such as volatile-lru or allkeys-lru), high-traffic memory pressure forces Redis to drop active wc_session_ keys. Additionally, race conditions occur if object caching is enabled without proper key exclusion for WooCommerce session transients.

Root Cause Diagnosis

When a user submits the checkout form, WooCommerce updates the cart state and validates the session token stored in the wp_woocommerce_session_ cookie against the Redis cache. If Redis evicts the wc_session_* transient or fails to persist session writes before the POST request completes, the session drops, resetting the user’s cart to empty. This is primarily caused by Redis eviction policies clearing active session keys under memory pressure, or persistent object caching interfering with transient persistence.

Quick Fix

Force Redis to exclude WooCommerce session transients from volatile object eviction, or flush and reset the WooCommerce session store via WP-CLI:

# Flush Redis object cache without clearing persistent database sessions
wp cache flush

# Set Redis eviction policy via CLI to prevent session eviction
redis-cli CONFIG SET maxmemory-policy noeviction

Step-by-Step Resolution

1. Update Redis MaxMemory Eviction Policy

Configure Redis to reject non-volatile evictions or use an eviction policy that spares active keys.

Edit your Redis configuration file (/etc/redis/redis.conf):

# Change eviction policy to prevent purging keys with expiry unless necessary
maxmemory-policy volatile-lru

Ensure memory allocation is sufficient for session retention:

maxmemory 2gb

Restart the Redis service:

sudo systemctl restart redis-server

2. Exclude WooCommerce Session Groups in Redis Object Cache

If using Redis Object Cache (such as redis-cache by Till Krüss), add wc_session_ and transient patterns to non-routable or uncacheable groups in wp-config.php.

Add the following configuration above the /* That's all, stop editing! */ line:

// Prevent Redis object cache from intercepting WooCommerce session transients
$wp_redis_ignored_groups = [
    'counts',
    'plugins',
    'wc_session_id',
];

$wp_redis_unflushable_groups = [
    'wc_session_id',
];

If using Redis Cache Pro, add the following to your wp-config.php:

define('WP_REDIS_CONFIG', [
    'token' => 'YOUR_LICENSE_KEY',
    'host' => '127.0.0.1',
    'port' => 6379,
    'database' => 0,
    'maxttl' => 3600 * 24, // 24 hours
    'non_persistent_groups' => [
        'counts',
        'wc_session_id',
    ],
    'analytics' => false,
]);

3. Force WooCommerce Session Fallback to Database

If Redis memory pressure remains unpredictable, force WooCommerce sessions to bypass Redis object caching completely while maintaining Redis for other object groups.

See also  WordPress wp_cron.php causing high CPU usage: Proper CLI systemd timer setup

Add this snippet to your active child theme’s functions.php or a custom MU-plugin (wp-content/mu-plugins/wc-session-fix.php):

<?php
/**
 * Plugin Name: Bypass Redis for WC Sessions
 * Description: Forces WooCommerce session transients to write directly to database options/tables.
 */

add_filter('woocommerce_session_handler', function ($handler) {
    // Retain default session handler but disable external object cache caching for sessions
    if (function_exists('wp_cache_add_non_persistent_groups')) {
        wp_cache_add_non_persistent_groups(['wc_session_id', 'transients']);
    }
    return $handler;
});

4. Verify Session Persistence

Check session keys directly in Redis to confirm ttl (time-to-live) and key retention:

redis-cli --scan --pattern '*wc_session_*'

Inspect the TTL of an active session:

redis-cli TTL "wp:wc_session_id:1234567890abcdef"

A return value of -1 indicates no expiration, while positive integers reflect remaining TTL in seconds. Values returning -2 indicate key eviction prior to expiration.

Why This Fails for Some Users

  • Nginx/FastCGI Microcaching: If FastCGI cache or Nginx microcaching is active and not configured to bypass cache on woocommerce_items_in_cart or wp_woocommerce_session_ cookies, GET requests following POST checkout submissions return cached, empty-cart states.
  • PHP-FPM Session Lock Timeouts: High-concurrency AJAX calls (such as address updates during checkout) lock the session file/key. If max_execution_time is reached before the previous lock releases, subsequent write operations drop.
  • Redis OOM (Out of Memory) Errors: When Redis reaches maxmemory and policy is set to noeviction, Redis rejects all write operations (including new cart session creations), resulting in silent session loss.
  • Multi-Server / Load Balanced Setup Without Redis Cluster: If load balancing without sticky sessions routes the checkout POST request to Server A (with local Redis) and the redirect GET request to Server B, the session appears dropped unless a centralized Redis instance is utilized.

Leave a Comment