Issue
The Time to First Byte (TTFB) for individual product pages in a WooCommerce store is as high as 2.5 seconds, even though WP Rocket page caching is enabled and the homepage loads quickly (0.18s).
Tracing the request step-by-step using curl reveals that the product page undergoes three server-side redirects before reaching the final cached page:
/item/flarum/ →301→ /item/flarum (0.78s, WordPress removes trailing slash)
/item/flarum →307→ /item/flarum/?v=160222... (0.81s, WC geolocation appends ?v= with trailing slash)
/item/flarum/?v= →301→ /item/flarum?v=160222... (0.75s, WordPress again removes trailing slash)
/item/flarum?v= →200 (0.18s, cache hit)
Although the final page is successfully served from WP Rocket’s cache (0.18s), users endure three costly server-side redirects (~2.3s total) just to reach it.
Root Cause Analysis
The root cause lies in WooCommerce core’s WC_Cache_Helper::geolocation_ajax_redirect() method (class-wc-cache-helper.php).
When woocommerce_default_customer_address is set to geolocation_ajax, WooCommerce performs a 307 redirect on every non-cart/non-checkout page, appending a ?v= parameter containing a geolocation hash to the URL—enabling cache differentiation per user region.
The problem stems from how the redirect URL is constructed:
$redirect_url = trailingslashit( home_url( $wp->request ) );
trailingslashit() forcibly adds a trailing slash. However, if WordPress’s permalink structure does not include trailing slashes (e.g., /%category%/%postname%), WordPress itself will issue another 301 redirect to strip it off. This creates a chain:
- WordPress 301 — removes trailing slash
- WooCommerce 307 — appends
?v=and reinstates the trailing slash - WordPress 301 — removes trailing slash again
- Final cached page is served
Each redirect incurs a full round-trip server request (~0.7–0.8s), resulting in ~2.3s of pure overhead.
Solution
For digital-goods stores (e.g., plugins, themes, software) that do not require region-specific pricing or tax rates, simply disable geolocation_ajax:
wp option update woocommerce_default_customer_address base_address --url=mall.weixiaoduo.com
This changes the default customer address setting from geolocation_ajax to base_address, meaning all users receive the store’s base address without geolocation-based redirects.
After applying this change, clear your page cache so WP Rocket regenerates cached files without the ?v= parameter.
Results After Fix
| Metric | Before Fix | After Fix |
|---|---|---|
| Product Page TTFB (first visit) | ~2.5s (3 redirects) | ~1.2s (direct render) |
| Product Page TTFB (cached) | ~2.5s (redirects are never cached) | 0.17s (direct cache hit) |
| 307 Redirects | Triggered on every visit | Fully eliminated |
| Homepage TTFB | 0.18s (unaffected) | 0.17s (unchanged) |
Applicability
This fix applies when:
- You operate a digital-goods store (plugins, themes, SaaS tools, etc.) where pricing/tax rules are uniform globally
- You use WP Rocket or similar page-caching plugins
- Your permalink structure excludes trailing slashes (e.g.,
/%postname%/)
If your store does require region-specific pricing or tax calculations, disabling geolocation_ajax entirely is not viable. Instead, implement a must-use plugin (mu-plugin) that hooks into the redirect logic before geolocation_ajax_redirect() and bypasses trailingslashit(). This eliminates at least one unnecessary redirect.
Diagnostic Commands
Use curl to trace the redirect chain:
# Check for 307 redirects
curl -sS -D - -o /dev/null "https://yourdomain.com/product/slug" 2>&1 | grep -iE "HTTP/|location|cache"
# Trace full redirect chain and measure TTFB per hop
curl -sS -o /dev/null -w "TTFB: %{time_starttransfer}s | HTTP: %{http_code}\n" -L "https://yourdomain.com/product/slug"
# Verify current setting
wp option get woocommerce_default_customer_address
If you observe a 307 redirect with a Location header containing ?v=, geolocation_ajax is active and causing the issue.