Caching Architecture
Scottsdale Mint uses a multi-layer caching strategy designed for a high-traffic precious metals store with real-time pricing constraints.
Caching Layersโ
User Request
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Layer 1: CloudFront CDN โ โ Static assets, product pages (TTL: minutes to hours)
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ (cache miss or bypass)
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Layer 2: WordPress/Lambda โ โ PHP page generation
โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ Layer 2a: Valkey โ โ โ Object cache (WP transients, DB query results, sessions)
โ โ Redis Object Cache โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ (object cache miss)
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Layer 3: Aurora MySQL โ โ Database (read replica)
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Layer 1: CloudFront CDNโ
What Is Cachedโ
- Product pages, category pages, and blog posts (HTML responses)
- Static assets: CSS, JavaScript, fonts, images in
/uploads/ - Processed images: CloudFront performs on-the-fly image resizing
Cache Invalidationโ
CloudFront cache is invalidated automatically by:
- Ymir after a new deployment
- The W Rocket / Perfmatters integration (plugin fires CloudFront invalidation)
- Price update endpoint: invalidates product page cache after price changes
Cookie Whitelist (WooCommerce Session Awareness)โ
CloudFront is configured to pass these cookies to Lambda (they vary the cache key):
| Cookie | Purpose |
|---|---|
woocommerce_cart_hash | Identifies cart state; triggers cart-aware responses |
woocommerce_items_in_cart | Whether the cart has items |
woocommerce_recently_viewed | Recently viewed products |
wp_woocommerce_session_* | WooCommerce session data (wildcard) |
Any request with a WooCommerce session cookie will bypass CDN caching for dynamic content.
Never-Cached Pathsโ
These paths always pass through to Lambda โ CloudFront never caches them:
/cartโ Shopping cart/checkoutโ Checkout page/my-accountโ Customer account pages/uploads/elementor/*โ Elementor builder assets/addonsโ Add-on products
Layer 2a: Valkey / Redis Object Cacheโ
Plugin: Object Cache Pro (with object-cache.php drop-in)
Client: Relay PHP extension (RESP3 protocol support)
Production Configurationโ
WP_REDIS_CLIENT = 'relay'
WP_REDIS_COMPRESSION = 'zstd' // Zstandard โ fast, high ratio
WP_REDIS_IGBINARY = true // igbinary binary serializer (compact)
WP_REDIS_HOST = [from YMIR_REDIS_ENDPOINT]
Local Configurationโ
WP_REDIS_CLIENT=phpredis
WP_REDIS_COMPRESSION=none
WP_REDIS_SERIALIZER=php
Advanced Redis Settings (from config/application.php)โ
| Setting | Value | Purpose |
|---|---|---|
split_alloptions | enabled | Splits WordPress alloptions cache into individual keys to prevent cache stampedes |
prefetch | disabled | Avoids prefetching all alloptions on every request |
network_flush | site-level | For single-site; flushes only the current site's keys |
What Is Cached in Redisโ
| Cache Group | Contents |
|---|---|
| WordPress transients | Temporary API responses, computed values (TTL-based) |
| WooCommerce sessions | Active customer sessions, cart data |
| WP option values | All get_option() calls cached in Redis |
| Database query results | WP_Query and WP_Term_Query results |
| User meta | Frequently accessed user metadata |
| Product stock counts | Reserved stock, available quantities |
| Pricing cache | suma_pricing_cache โ spot price data |
Product Meta TTL for Price Freshnessโ
Scottsdale Mint now applies a custom TTL for Redis entries in the WordPress post_meta and WooCommerce products cache group when the key is a numeric product post ID.
- Hook:
suma_object_cache_expire - Integration class:
Suma\Integration\ObjectCache - Method:
set_product_meta_cache_expire() - Behavior: returns
60seconds for productpost_meta, falls back to default TTL for everything else
This creates a hard one-minute expiration window for cached WooCommerce product meta so price-related metadata cannot remain stale longer than one pricing cycle.
The suma_object_cache_expire hook, is available because Scottsdale Mint applies a custom patch to the plugin:
- Patch file:
patches/0001-Dev-object-cache-pro-add-expire-filter-hook.patch - Apply command:
patch -l -p1 < patches/0001-Dev-object-cache-pro-add-expire-filter-hook.patch - Patched class:
web/app/plugins/object-cache-pro/src/ObjectCaches/PhpRedisObjectCache.php
The patch adds apply_filters( 'suma_object_cache_expire', ... ) before Redis writes in key write paths (add, replace, set, and setMultiple behavior), allowing runtime TTL overrides per cache group/key/value.
Without this patch, the Suma\Integration\ObjectCache TTL filter would never run and product post_meta entries would continue using default Object Cache Pro expiration behavior.
Cache Invalidationโ
- Full flush:
wp cache flush(via WP-CLI or/wp-json/suma/v1/utils/clear_cache) - Per-object: Automatically invalidated when posts/options are updated
- Price updates: Price update endpoint flushes product-specific cache keys after price changes
Accessing Remote Redis (Valkey) Cachingโ
Follow these instructions to safely securely connect and inspect Production, Staging, or Dev remote caching instances using your local Windows/WSL development environment.
Step 1: Establish the Secure SSH Tunnelโ
Run the following tunnel command from your WSL command line interface:
Ymir cache:tunnel
You will be prompted with a choice between the Production and Dev remote servers. Select the server environment you wish to inspect.
Step 2: Install Another Redis Desktop Manager (ARDM)โ
Open Windows Terminal as an Administrator and install the desktop client via winget:
winget install qishibo.AnotherRedisDesktopManager
Step 3: Install PHP Dependencies in Herdโ
Because remote data payload structures utilize igbinary serialization and zstd compression, your local environment requires specific PHP 8.4 binaries to successfully extract and translate the cache values.
- Ensure PHP 8.4 is fully active in your local Laravel Herd installation.
- Download the required extension components: PHP 8.4 Redis Extensions ZIP.
- Navigate to the following local folder path and extract both
.dllfiles (php_igbinary.dllandphp_zstd.dll) inside it:
%USERPROFILE%\.config\herd\bin\php84\ext
- Open the PHP configuration file
%USERPROFILE%\.config\herd\bin\php84\php.iniand append the following structural definitions to the absolute bottom of the file:
extension=C:\Users\<username>\.config\herd\bin\php84\ext\php_igbinary.dll
extension=C:\Users\<username>\.config\herd\bin\php84\ext\php_zstd.dll
Explicitly swap out <username> for your active Windows profile username. Shared system notation mappings like %USERPROFILE% do not resolve when parsing initialization rules in php.ini.
- Restart Laravel Herd services to load the newly introduced libraries.
Step 4: Map the Decoding Scriptโ
- Navigate to the root directory of your local Z: Drive network path.
- Create a subfolder named
ardm. - Download the decoder logic: redis_decoder.php.
- Save the file directly into your newly configured directory path:
Z:\ardm\redis_decoder.php.
Step 5: Configure the Client Connectionโ
- Launch Another Redis Desktop Manager.
- Click the + New Connection button and fill out the mapping values:
- Host:
localhost - Port:
6378 - Auth: None (Leave blank)
- Connection Name:
Scottsdale Mint
- Click OK. Upon a successful initialization, your workspace sidebar will list Scottsdale Mint.
- Double-click the instance node to view the database index partitions. Select the numeric database block that aligns with your active environment inspection:
- DB 0: Production
- DB 1: Staging
- DB 2: Development
Step 6: Assign Custom Deserialization Rulesโ
By default, values inside the database are stored compressed, generating binary Hex format reads. Map the custom formatter extension to display data cleanly:
- Click on any active key parameter inside the workspace database tree.
- Locate the format management dropdown filter element situated immediately above the main body value block window (this option natively defaults to Hex).
- Expand this selection control layout list, navigate to the bottom area, and select Customize.
- Click New and submit the configuration properties:
- Name:
Zstd + Igbinary - Command:
C:\Users\<username>\.config\herd\bin\php84\php.exe - Params:
Z:\ardm\redis_decoder.php {HEX}(Ensure you change<username>to match your real Windows system user identity string).
- Confirm the action. Now, toggling the format mode view option value filter over to Zstd + Igbinary will correctly decode and print complex object schemas in readable configurations.
Performance Toolsโ
Perfmattersโ
Plugin: perfmatters (with MU-plugin override a-suma-perfmatters-filters.php)
Features used:
- Script/style management per page (disable unnecessary scripts)
- Database cleanup (auto-draft posts, transients, revisions)
- Lazy loading for images
- Google Fonts hosting locally (GDPR)
- Cache path override:
uploads/perfmatters/cache/(set in MU plugin)
Scalability Proโ
Plugin: scalability-pro
Features:
- Deferred term count updates (prevents lock contention on high-traffic stores)
- Query optimization for large WooCommerce product catalogs
Caching and Pricingโ
Precious metals prices change every minute. The cache strategy accounts for this:
- Product pages are cached at CloudFront. When the Laravel middleware calls the price update endpoint:
- Product prices are updated in Aurora
- Redis object cache for those products is flushed
- CloudFront cache for those product URLs is invalidated
- Product
post_metacache entries also expire after 60 seconds even if a targeted flush is missed
- Cart pricing is always real-time (cart page bypasses CloudFront)
- Spot price widget (NFusion live chart) fetches directly from NFusion CDN โ not cached by WordPress
In practice, this means customers moving from product page to cart/checkout are far less likely to encounter stale cached pricing when NFusion-driven updates run every minute.
Disabling Cache for Developmentโ
In .env:
WP_CACHE=false
This disables the Redis object cache drop-in. Useful for development to see fresh database queries.
Never set WP_CACHE=false on staging or production โ it will dramatically increase Aurora database load.