A host email saying PHP workers are full, on a large WooCommerce store, is often about the filter and not about the category page. As long as every click is a request, that click holds a worker. After hydration an InstantFilter click holds no worker: there is no request, so no PHP, and 0 SQL.
Why do WooCommerce filters exhaust PHP workers?
The host counts processes, not page views. A category URL served from the page cache costs no worker. A click on a color does, when that click goes to admin-ajax.php or a REST route. The request boots WordPress, holds a worker until the query finishes, and then releases it. With one visitor you notice a spinner. During a sale you notice a graph in which every worker is busy and new requests sit in a queue.
If you are searching for woocommerce filters exhausting php workers, this is that email. The host names a limit, a handful of workers on a small plan, and a spike that lines up with it. The spike lines up with traffic on archives that have a filter, not with traffic on a static page. The category itself still returns 200 from cache. The 502 or 504 sits on the filter endpoint.
Buying more workers raises how many simultaneous clicks you can absorb. It does not change that each click needs one. A catalog of 10,000, 20,000, or 50,000 products keeps each worker busy for longer, because the query takes longer. Longer occupancy times more clicks fills the same pool faster than a small shop with the same visitor count.
What shows up in the slow query log when workers are full?
The slow query log and the worker graph belong together. A worker running a slow SELECT is not free for the next click. In the log you see joins on term tables, on wp_postmeta, or on wc_product_attributes_lookup. The lookup table shortens the attribute join. It does not make the worker unnecessary. The request still exists, and MySQL holds that request until the count finishes.
woocommerce filter slow query log is the phrase a developer pastes next to the host email. One slow query of two seconds is one worker gone for two seconds. Twenty of those queries at once are twenty workers, or a queue if the pool is smaller. The timeout the shopper sees is often the queue plus the query, not the query alone. The browser gives up while the request is still inside PHP.
Why does raising the timeout fail when filter clicks overlap?
A higher max_execution_time lets a slow query run long instead of cutting it off. The worker stays busy longer. With overlapping clicks the pool gets worse, not better. A proxy timeout of 60 seconds hides the 504 and fills the row of workers with requests the shopper has already abandoned.
The same applies to an object cache around the query. If the plugin stores the result of a popular combination, the second identical click is faster. The first click of every unique combination, and every combination that misses the cache, still takes a worker. A shop with many facets has more combinations than the cache keeps warm. During a sale many of those combinations are new.
How many workers does a filter click cost after the first page load?
Zero, when the click no longer hits the server. InstantFilter renders the first HTML on the server. After that the archive lives in the codebook in the browser. A click then holds no PHP worker. That figure is in the production standard: 0 workers while filtering. This page does not add a new measurement. There is no request to measure.
The first load can still use a worker, like any uncached HTML response. That single render is cacheable. WP Rocket, LiteSpeed, or Cloudflare may store the category URL. The click after that is not in that cache and does not need to be, because it does not go to PHP. The guide on filter performance is the hub for that distinction. This page is the host email.
Other plugins on the same site can still use workers: the cart, a payment webhook, a search box in the header. Those are not filter clicks. If the host panel fills when people click the sidebar, and stays quiet on pages without a filter, that points at the filter endpoint. The Network panel confirms it: an XHR per click, or no XHR per click.
What do you tell the host about a large catalog?
The host sees workers and queries. You see the architecture. As long as the filter is one request per click, the number of workers you need scales with simultaneous clicks, and the time per worker scales with the catalog. A plan with more workers is a ceiling. It is not a different architecture. At 20,000 or 50,000 products that ceiling is still tight during a promotion, because each query takes longer.
The change that moves the graph: after the first load there is no filter request, so the clicks during the sale do not enter the worker pool. The pool stays available for checkout and for the first HTML of an uncached URL. Test that on staging with the current plugin and then with InstantFilter, with the same number of overlapping clicks. The slow query log should not show the second series.
An index that speeds up the join and leaves the request in place lowers the seconds per worker. It does not remove the worker from the graph. You see that with plugins that have their own table and still call admin-ajax.php. The host email then becomes “a bit less red” instead of “the filter spike is gone”. For an agency running a shop of tens of thousands of products, the difference is whether the sale fills the pool.
How do you read the host email next to the Network panel?
Put three things side by side. The timestamp in the host email. The URL that most often returns 502 or 504 in the access log. The row in the Network panel at the moment you set a filter yourself. If the timestamp lines up with traffic on the archive, the failing URL is admin-ajax.php or a filter route, and your own click hits that same URL, then the worker pool is the sum of those clicks. A slow homepage or a heavy checkout has a different URL in the log.
Then measure how long one worker stays busy. The duration in the slow query log, plus the time WordPress needs to boot before the query, is the occupancy per click. Divide the pool size by that occupancy and you have a rough ceiling for simultaneous filterers. A shop with eight workers and a one-second click keeps about eight simultaneous filterers. The ninth waits. A newsletter or an ad crosses that line easily, even when the daily average looks low.
Repeat the count after the filter click no longer hits the server. The access log should stop growing that action while people filter. The workers then stay free for the requests that actually need PHP. That is the check you send back to the host: the same spike in visitors, a different line in the log.
Keep going
The host email belongs to a request. These pages show where that request comes from.
- Why WooCommerce filters get slow
- Every click a request to admin-ajax.php
- The lookup table does not remove the worker
- The cache does not cover the filter click
- Pricing and trial