WordPress Performance FAQ


Mike

I have Redis Object Cache enabled on my WordPress/WooCommerce store, but the cart and checkout still do not feel noticeably faster.

Why doesn't Redis automatically make dynamic WooCommerce requests fast? Is the problem that Redis is not working, or could it be that the cart request still has to execute a lot of PHP, WooCommerce logic, plugin hooks, session handling, and checkout-related code even when database lookups are cached?

Sam

Yes — what you're describing is often exactly what happens on WooCommerce sites, and it does not necessarily mean Redis is broken.

The key misconception is that Redis Object Cache speeds up database access, but many WooCommerce cart and checkout requests are dominated by application-layer work, not database queries.

What Redis Object Cache actually does

When WordPress or WooCommerce asks for something that can be cached:

  • Options (wp_options)
  • Product metadata
  • Taxonomies
  • User metadata
  • Query results
  • Transients

Redis can return the data from memory instead of MySQL.

So instead of:

PHP → MySQL → PHP

you get:

PHP → Redis → PHP

which is much faster.

However, the request still has to run through WordPress and WooCommerce.


What still happens during a cart request

Even with Redis hits, WooCommerce still has to:

  1. Bootstrap WordPress
  2. Load WooCommerce
  3. Load active plugins
  4. Fire hundreds of actions and filters
  5. Load customer session data
  6. Recalculate cart contents
  7. Validate products
  8. Calculate shipping
  9. Calculate taxes
  10. Apply coupons
  11. Run plugin customizations
  12. Generate the response

A simplified flow:

HTTP Request
    ↓
PHP starts
    ↓
WordPress loads
    ↓
WooCommerce loads
    ↓
Plugins load
    ↓
Cart session loaded
    ↓
Cart recalculated
    ↓
Shipping calculated
    ↓
Taxes calculated
    ↓
Checkout fields generated
    ↓
Response sent

Redis may reduce the time spent fetching data, but it does not eliminate the rest of the processing.


Why cart and checkout are special

WooCommerce intentionally treats cart and checkout as highly dynamic pages.

These pages usually cannot be fully page-cached because:

  • Cart contents differ per user
  • Shipping rates differ per address
  • Tax calculations differ per customer
  • Coupons differ per session
  • Inventory checks may be real-time

So every request often requires PHP execution.

For example:

Product page:
20 ms PHP
80 ms database

Redis helps a lot.

versus

Checkout page:
300 ms PHP
40 ms database

Redis helps only a little.

In the second example, removing most of the database cost barely changes the total request time.


WooCommerce plugins can dominate execution time

On many stores, the biggest delays come from:

  • Dynamic pricing plugins
  • Membership plugins
  • Subscription plugins
  • Shipping plugins
  • ERP integrations
  • Tax services
  • Payment gateway extensions
  • Marketing/tracking plugins

A checkout request might spend:

50 ms database
600 ms plugin code

Redis can only improve the first part.


Session handling is another factor

WooCommerce carts rely heavily on session data.

Even if Redis stores session information, WooCommerce still needs to:

  • Read the session
  • Deserialize it
  • Rebuild cart objects
  • Recalculate totals

Redis makes the storage retrieval faster, but the cart reconstruction work still happens in PHP.


How to tell whether Redis is helping

Look at profiling metrics rather than page feel alone.

Common scenarios:

Scenario A: Redis working well

Before:

Database queries: 500
DB time: 300 ms
Total request: 900 ms

After:

Database queries: 500
DB time: 40 ms
Total request: 640 ms

Redis helped significantly, but checkout still feels "slow."

Scenario B: Redis not actually being used

Before:

DB time: 300 ms

After:

DB time: 290 ms

Almost no change.

Then you investigate:

  • Low Redis hit rate
  • Cache not persistent
  • Frequent cache flushes
  • Misconfigured object cache

What usually improves WooCommerce cart speed more than Redis

For cart and checkout performance, profiling often reveals bigger gains from:

  • Reducing expensive plugin hooks
  • Optimizing shipping calculations
  • Simplifying tax calculations
  • Removing unnecessary checkout customizations
  • Eliminating slow API calls
  • Using WooCommerce's newer checkout/cart implementations where appropriate
  • PHP 8.x upgrades
  • OPcache tuning
  • Faster hosting CPUs

Redis is still valuable, but it is usually one layer of optimization, not a complete solution.

The short answer

Your reasoning is correct. Redis Object Cache primarily reduces database lookup time. A WooCommerce cart or checkout request can still spend most of its time executing PHP, WooCommerce business logic, plugin hooks, session processing, shipping calculations, tax calculations, and checkout-related code. Therefore, a cart page can remain relatively slow even when Redis is functioning perfectly and serving cached database objects.

Mike

That makes sense. So Redis can reduce the cost of database and object lookups, but it does not prevent WordPress, WooCommerce, plugins, hooks, sessions, and checkout logic from executing in the first place.

Would it therefore be fair to say that Redis is mainly a work-reuse or cost-reduction layer, while the remaining bottleneck may be the amount of PHP/application work that still happens per cart request?

In other words: if Redis makes some lookups cheaper but the cart request still loads the full WordPress/WooCommerce/plugin runtime, shouldn't the deeper performance question be which parts of that runtime are actually needed for the cart, and which parts are only executing because WordPress loads the same general plugin environment for almost every request?

Sam

Yes, that's a very good way to think about it.

Redis Object Cache is fundamentally a cost-reduction and work-reuse layer. It makes certain operations cheaper by avoiding repeated database work, but it does not eliminate the need for WordPress and WooCommerce to execute the request lifecycle.

A useful mental model is:

Request Cost
=
Framework Cost
+
Application Cost
+
Data Access Cost

Where:

  • Framework Cost = WordPress bootstrap, plugin loading, hook registration
  • Application Cost = WooCommerce cart calculations, shipping logic, taxes, coupons, session handling
  • Data Access Cost = MySQL queries, option lookups, metadata retrieval

Redis primarily attacks the third category.

If Data Access Cost was only 10–20% of the total request time, then even a perfect cache cannot produce dramatic overall gains.


The deeper performance question

What you're getting at is arguably the more important architectural question:

How much of the WordPress/WooCommerce runtime is actually necessary for this request?

Because in traditional WordPress architecture, most requests load a very large shared runtime.

A cart request may trigger:

WordPress core
↓
WooCommerce core
↓
Theme
↓
20-50 plugins
↓
Thousands of registered hooks
↓
Request-specific execution

Even though only a fraction of that code may actually contribute to the cart response.

The challenge is that WordPress was designed around:

load everything
then decide what runs

rather than:

load only what is needed

Loading versus executing

An important distinction is:

1. Code that gets loaded

Examples:

require plugin.php
register hooks
initialize classes
build service containers

This consumes:

  • CPU
  • memory
  • autoloading time

even if the plugin ultimately does nothing for the current request.

2. Code that gets executed

Examples:

calculate shipping
validate coupons
rebuild cart totals

This is the work that directly affects the cart.

Sometimes the loading overhead is surprisingly large.

On heavily customized WooCommerce stores, a substantial portion of request time can disappear before the cart is even processed.


Why WordPress tends toward over-loading

WordPress's plugin system is intentionally generic.

A plugin can hook into virtually anything:

init
wp_loaded
template_redirect
woocommerce_before_calculate_totals
woocommerce_cart_calculate_fees

Because WordPress cannot know ahead of time which plugin might affect the current request, it usually loads all active plugins.

That gives tremendous flexibility but less request-specific optimization.


Why profiling often reveals unexpected bottlenecks

Many store owners assume:

Slow cart
=
Slow database

But profiling frequently shows:

Database: 50 ms
Redis: working correctly

WooCommerce calculations: 150 ms

Shipping plugin: 250 ms

Marketing plugin: 180 ms

Custom code: 120 ms

Total: 750 ms

In that situation:

Database = 7%
Application layer = 93%

So further database optimization has very little remaining leverage.


The highest-value question

For mature WooCommerce performance work, the question often changes from:

"How do I make queries faster?"

to:

"Why is this code executing at all?"

Examples:

  • Does this plugin need to load on checkout?
  • Does this hook need to run for every AJAX cart update?
  • Is this shipping calculation being repeated unnecessarily?
  • Is an external API being called on every request?
  • Is cart recalculation occurring multiple times?
  • Is expensive custom code attached to broad WooCommerce hooks?

Those questions typically uncover larger wins than another layer of caching.


A practical hierarchy

For a WooCommerce cart request, I generally think of performance optimization in this order:

  1. Eliminate unnecessary work

    • Remove unneeded plugins
    • Reduce expensive hooks
    • Avoid redundant calculations
  2. Reduce application-layer cost

    • Optimize shipping/tax logic
    • Optimize custom code
    • Reduce repeated recalculations
  3. Reduce framework overhead

    • Plugin loading efficiency
    • PHP autoloading efficiency
    • OPcache optimization
  4. Reduce data-access cost

    • Redis Object Cache
    • Query optimization
    • Database tuning

Redis remains valuable because it removes a whole category of overhead. But once Redis is working properly, the next major gains usually come from understanding what the PHP runtime is actually doing during the request and whether all of that work is truly required. That's where application profiling tools (such as Query Monitor, Xdebug traces, Blackfire, Tideways, New Relic, etc.) often become more revealing than cache statistics.

Mike

That hierarchy makes sense, but it still sounds like most of the optimization happens after WordPress, WooCommerce, and the active plugin stack have already entered the request.

For example, reducing hooks, optimizing custom code, improving autoloading, or using OPcache can make the existing runtime cheaper. But they do not necessarily answer whether unrelated plugins, hooks, services, and PHP files needed to be part of the cart request in the first place.

If Redis is a work-reuse layer and code/hook optimization is a cost-reduction layer, would a deeper layer be request-aware execution reduction: identifying the cart or checkout context early enough to prevent unrelated plugin/PHP execution before it begins?

In other words, should mature WooCommerce performance distinguish between:

  • making the loaded runtime faster,
  • and reducing the runtime that gets loaded for this specific request?
Sam

Yes. In fact, you're describing a distinction that many performance discussions blur together:

  1. Make the current runtime cheaper
  2. Reduce how much runtime exists for a given request

Those are related but fundamentally different optimization strategies.

A useful hierarchy might look like this:

Level 1: Faster storage
  Redis
  Database tuning

Level 2: Faster execution
  Better PHP
  OPcache
  Hook optimization
  Query optimization

Level 3: Less execution
  Don't run unnecessary code
  Don't load unnecessary services
  Don't initialize unnecessary plugins

Level 4: No execution
  Full-page cache
  Edge cache
  Static responses

Most WooCommerce optimization efforts focus heavily on Levels 1 and 2 because they are relatively safe and compatible with the WordPress ecosystem.

What you're calling "request-aware execution reduction" is Level 3.


The architectural limitation

The challenge is that classic WordPress was not designed around aggressive request-specific dependency loading.

The model is roughly:

Load WordPress
Load all active plugins
Register all hooks
Determine request
Execute hooks
Render response

not:

Determine request
Load only relevant modules
Execute response

By the time WordPress fully understands:

is_cart()
is_checkout()
is_product()

a large amount of loading has already occurred.

This is why many performance engineers eventually realize that there are two different questions:

Optimization question

How can I make this code run faster?

Architecture question

Why is this code running at all?

The second question often produces larger gains.


Why mature systems move toward execution reduction

Many high-performance systems eventually discover that:

Unused code has a cost

even if it never reaches business logic.

For example:

Plugin loaded
  ↓
Autoloader initialized
  ↓
Configuration loaded
  ↓
Services instantiated
  ↓
Hooks registered

Even if none of the plugin's features are relevant to checkout.

The cost may be:

  • CPU
  • memory allocation
  • autoloading
  • object construction
  • hook dispatch overhead

None of that is visible in query counts.

Redis cannot help because no database bottleneck exists yet.


Why checkout is particularly sensitive

Checkout requests often cannot benefit from the strongest caching layers.

A product page might become:

CDN
  ↓
Page cache
  ↓
Done

But checkout typically becomes:

Request
  ↓
PHP runtime
  ↓
WooCommerce
  ↓
Session
  ↓
Cart calculations
  ↓
Response

Since checkout must execute dynamically, every unnecessary component loaded into that execution path matters more.


The ideal architecture

If one were designing a system purely for performance, the flow might look more like:

Request arrives
  ↓
Classify request
  ↓
Load checkout modules only
  ↓
Load shipping modules only if needed
  ↓
Load payment modules only if needed
  ↓
Execute response

rather than:

Load entire commerce platform
  ↓
Load all extensions
  ↓
Determine what matters

Modern frameworks increasingly move toward this kind of dependency graph and service-container approach.

WordPress historically prioritized:

  • extensibility
  • backward compatibility
  • plugin interoperability

over request-specific loading efficiency.


The practical reality in WooCommerce

This means that experienced WooCommerce performance work often evolves through stages:

Early stage

Focus on:

  • Redis
  • database tuning
  • page caching

Intermediate stage

Focus on:

  • slow queries
  • hook profiling
  • PHP execution time

Advanced stage

Focus on:

  • plugin loading footprint
  • conditional plugin activation
  • service initialization cost
  • unnecessary request participation

At that stage, the question becomes:

Which plugins, services, and hooks are present in the checkout execution path, and which of them provide zero value to that specific request?

That is often where the largest remaining gains are found.


One subtle point

Even "conditional loading" has limits in WordPress.

Many developers imagine:

if ( is_checkout() ) {
    load_checkout_code();
}

But determining that you're on checkout may itself require a substantial portion of WordPress to already be loaded.

The deepest optimization therefore happens before the traditional WordPress lifecycle reaches full initialization.

That's why some advanced solutions focus on:

  • MU-plugin bootstrap logic
  • early plugin filtering
  • selective plugin loading
  • alternative front-controller architectures
  • edge/runtime separation

Those approaches attempt to reduce participation in the request rather than merely making participation cheaper.

So yes: a mature WooCommerce performance model should distinguish between runtime optimization ("make the loaded runtime faster") and runtime reduction ("prevent unnecessary runtime from loading for this request"). The latter is often a more architectural form of optimization and, once caching and query tuning are largely solved, can become the next major frontier for improving dynamic cart and checkout performance.

Mike

If Redis improves data access but does not reduce how much of the WordPress/WooCommerce/plugin runtime gets loaded, would it be fair to say that Redis and request-aware runtime reduction operate at different layers?

Redis helps reuse previously computed or loaded data.

Request-aware runtime reduction asks a different question: which parts of the application should participate in this cart or checkout request at all?

So for dynamic WooCommerce requests, is the missing layer not another cache, but a prevention-oriented execution layer that reduces unnecessary PHP/plugin participation before the request becomes expensive?

Sam

Yes—with an important nuance.

Conceptually, Redis and request-aware runtime reduction operate at different layers of the cost stack.

Redis answers:

"Now that this code is running, how can we make data retrieval cheaper?"

Request-aware runtime reduction answers:

"Should this code be running for this request at all?"

Those are orthogonal questions.

A simplified model might be:

Request Cost
=
Participation Cost
+
Execution Cost
+
Data Cost

Where:

  • Participation Cost = loading plugins, registering hooks, initializing services, creating objects
  • Execution Cost = shipping calculations, tax calculations, coupon logic, business rules
  • Data Cost = database and object-cache lookups

Redis primarily reduces Data Cost.

Hook optimization and code optimization reduce Execution Cost.

Request-aware loading reduces Participation Cost.


Why another cache is often not the answer

Many optimization efforts assume:

slow request
→ add cache

But after a certain point, the expensive part of the request is no longer data retrieval.

Imagine:

Plugin loading        250 ms
PHP execution         350 ms
Database              40 ms
Redis lookups         5 ms

Adding a better cache might save:

40 ms → 20 ms

while the request still spends:

600 ms

in PHP participation and execution.

At that stage the leverage shifts.

The question becomes:

Why are 20 plugins participating in this request?

rather than:

How do we make their queries faster?


The idea of a prevention-oriented layer

What you're calling a "prevention-oriented execution layer" is a reasonable way to think about it.

Its goal is not:

do work faster

but:

avoid unnecessary work entirely

For example:

Request arrives
↓
Determine request type
↓
Exclude irrelevant participants
↓
Run remaining runtime

instead of:

Request arrives
↓
Load all participants
↓
Discover most are irrelevant
↓
Run request

This is fundamentally different from caching.

Caching assumes the participant is still part of the request but can obtain results more cheaply.

Execution prevention attempts to remove the participant from the request path.


Where this gets difficult in WordPress

The challenge is that WordPress historically assumes:

active plugin
=
available everywhere

That design is excellent for compatibility because any plugin can influence almost any request.

But it means the system naturally trends toward:

broad participation

rather than:

minimal participation

A truly prevention-oriented architecture needs some way to know:

  • what the request is,
  • which components are relevant,
  • and which can be safely excluded,

before substantial initialization has already occurred.

That is much harder than adding Redis.


Why advanced performance work often converges here

On many WooCommerce stores, optimization progresses like this:

  1. Add page caching.
  2. Add Redis.
  3. Tune MySQL.
  4. Upgrade PHP.
  5. Profile slow hooks.
  6. Optimize custom code.

At some point, the remaining question becomes:

Why is this request still loading all of these systems?

That's the point where you're no longer optimizing computations—you are optimizing participation.

In performance engineering terms, preventing a subsystem from joining the request is often more powerful than making that subsystem 20% faster once it has already joined.


One caveat

Not every checkout slowdown is caused by excessive participation.

Sometimes the checkout genuinely needs:

  • shipping calculations,
  • tax engines,
  • payment gateways,
  • inventory validation,
  • fraud checks,

and those operations are inherently required.

In those cases the bottleneck is real business logic, not unnecessary loading.

So the goal is not:

"Load as little as possible."

The goal is:

"Load only what is necessary for this request."

That distinction matters because a checkout page can never be reduced to the same minimal execution path as a cached product page.


So, at a conceptual level, yes: after caching and data-access optimizations are largely solved, the next layer is often not "another cache." It is understanding request participation—which plugins, services, hooks, and initialization paths actually need to be present for this cart or checkout request, and preventing unnecessary participants from entering the execution path in the first place. That's a different optimization layer from Redis, and on heavily customized WooCommerce stores it can become the dominant source of remaining performance gains.

Mike

This is exactly where LiteCache Rush applies its principle of Performance by Prevention. Redis Object Cache is valuable because it reduces the cost of repeated data access, but it does not reduce which parts of WordPress, WooCommerce, and the plugin stack participate in a cart or checkout request. Rush targets that earlier layer: it identifies the request context before the full plugin runtime is loaded and prevents unrelated PHP and plugin execution from entering the request path in the first place. For dynamic WooCommerce requests, the deeper question is not only “Can cached data make this request cheaper?” but “Which parts of the application should participate in this request at all?”