Tooling from the WooCommerce Customer Success Solutions Architect team for measuring, diagnosing, and reproducing WooCommerce stores and the environments they run on.
This started as a hosting benchmark suite and has outgrown that name. The repo is organized one concern per top-level directory: each component has its own entry point, its own docs, and can be used without the others.
This repository is public. Never commit any of the following:
- Site URLs, IPs, or hostnames (Pressable, Kinsta, or any merchant site)
- SSH usernames, passwords, or private keys
- API keys, tokens, or credentials
- Benchmark results or reports containing environment-specific detail
- Merchant names or anything else that identifies an environment
Scripts use placeholders ({SITE_URL}, {SSH_USER}) rather than real values.
Real values live in .env.d/, results live in results/, and both are
gitignored, along with *.txt, *.html, and comparison-*.md. Do not
override those rules. If in doubt, do not commit.
Target lists and scan output that name real stores belong in the team's private knowledge repo, not here.
| Directory | What it is | Runs against | Status |
|---|---|---|---|
benchmarking/ |
Hosting benchmark suite: PHP probes dropped in the web root plus shell benchmarks driven from your machine | A remote site over SSH and curl | On trunk |
demo-stores/ |
Scaffolds a local WooCommerce demo store, seeds content, installs a named plugin list | Your local machine | On trunk |
bin/ + .env.d/ |
Named credential environments shared by every tool | Your local machine | On trunk |
store-probe/ |
Outside-in stack fingerprinting: which plugins, gateways, and third-party services a storefront is running, no admin access needed (WOOCS-83) | Any public storefront | Planned |
The two measurement tools answer the same question from different distances:
store-probe/ reads what a public page load reveals, with no access at all.
benchmarking/ needs server access, holds the application constant, and makes
the hosting stack the variable.
Every tool that touches a remote site takes an environment name, not a URL.
Environments live in .env.d/:
.env.d/accounts/<platform>-<account>.envholds account-level values shared across sites (SSH user, API tokens, PSI key).env.d/sites/<platform>-<site>-<env>.envholds one site. DeclarePARENT_ACCOUNT=<account>and the account env loads first, with site values overriding.
# Copy a template and fill it in (real .env files are gitignored)
cp .env.d/sites/pressable-example-prod.env.example .env.d/sites/mysite-prod.env
# See what's available
bin/load-env --list
# Load one into your shell
source bin/load-env mysite-prod
# Check an env has everything a given tool needs
bin/check-creds run-ttfb mysite-prodcredentials.md documents every variable each tool consumes, where to get it,
and its expected format. It carries no real values.
Holds WooCommerce constant and treats the hosting stack as the variable. The question behind every probe is "how does this host solve for ___?" (object caching, database, PHP execution, disk I/O, outbound connectivity, concurrency, page caching, background processing, memory pressure, search at scale).
./benchmarking/run-all.sh mysite-prod # deploy → PHP → shell
./benchmarking/run-all.sh mysite-prod othersite-prod # several environments
./benchmarking/run-all.sh --phase deploy mysite-prod # one phase only
./benchmarking/cleanup.sh mysite-prod # remove probes when doneResults land in benchmarking/results/<timestamp>_<env-name>/, one .txt file
per probe. benchmarking/report/generate.php compiles a comparison report from
those directories.
| Area | Tool | Method |
|---|---|---|
| PHP environment, OPcache/JIT | probe-tooling/env_check.php |
PHP config inspection |
| OPcache effectiveness | probe-tooling/opcache_check.php |
Timed wp-load boot, restrict_api-aware |
| Per-plugin boot cost | probe-tooling/plugin_load_cost.php + run/plugin-load-sweep.sh |
Boot with a controlled plugin subset, difference against a no-plugins baseline |
| Object cache (Redis/Memcached) | probe-tooling/cache_check.php |
1000-key read/write/delete |
| Database | probe-tooling/db_check.php |
Connection latency, query benchmarks, MySQL config |
| WooCommerce operations | probe-tooling/woo_benchmark.php |
Serialize, JSON, WP_Query, HPOS orders, cart totals |
| Disk I/O | probe-tooling/disk_benchmark.php |
Small/medium/large files, temp vs uploads |
| Outbound HTTP | probe-tooling/outbound_http.php |
Latency to payment gateways, DNS, egress restrictions |
| Memory pressure | probe-tooling/memory_benchmark.php |
Allocation speed, real ceiling, cost per product/order |
| Action Scheduler | probe-tooling/action_scheduler_check.php |
Queue health, processing speed, cron config |
| Search and LIKE queries | probe-tooling/search_benchmark.php |
Product search, raw LIKE on posts/meta/options |
| PHP-FPM concurrency | probe-tooling/concurrency_check.php |
Worker config, self-test at 5/10/20 concurrent |
| TTFB | run/ttfb.sh |
100 requests per page, CDN and origin modes |
| Geographic TTFB | run/geo-ttfb.sh |
GlobalPing probes from multiple regions |
| Core Web Vitals | run/cwv.sh |
PageSpeed Insights API (Lighthouse) |
| CDN and cache behavior | run/cache-behavior.sh |
Warm-up, query strings, cookie bypass, Vary |
| Query-param cache fragmentation | run/query-param-cache.sh |
Which params bust the edge cache |
| REST API throughput | run/rest-api.sh |
WooCommerce REST latency per endpoint |
| Concurrency and load | run/concurrency.sh |
Escalating parallel requests (1 to 50) |
| Variable | Applies to | Default |
|---|---|---|
BENCH_PAGES |
all six page-driven scripts | / /shop/ /cart/ /my-account/ (/ /shop/ for concurrency.sh) |
BENCH_RUNS |
ttfb.sh |
100 |
BENCH_CONCURRENCY_LEVELS |
concurrency.sh |
1 2 5 10 20 50 |
BENCH_CWV_CACHE_BUST |
cwv.sh |
0 (audit the page warm, as a visitor gets it) |
Always set BENCH_PAGES from the store's own navigation rather than trusting
the defaults. Plenty of stores rename /cart/ and /my-account/, and the
failure is silent: a 404 responds fast, so a wrong slug yields a
healthy-looking measurement of a page that does not exist instead of an error.
BENCH_PAGES="/ /store/ /bag/ /account/" ./benchmarking/run/ttfb.sh https://example.com labelBENCH_CWV_CACHE_BUST=1 forces a cold render on every PageSpeed request. That is
the worst case by design, and on a slow origin it is also the case most likely to
make Lighthouse time out, so it is opt-in.
Percentiles come from benchmarking/lib/calc-percentiles.sh.
benchmarking/docs/pressable-apm.md documents the Pressable APM API (auth,
trace list, spans) for the hosts that expose one.
Security: the PHP probes expose server internals. Run
benchmarking/cleanup.sh <env> after a test run. Never leave them on a
production site. One probe (00-plugin-load-cost.php) installs into
wp-content/mu-plugins/ and therefore loads on every request, so cleanup
matters more than usual, even though it stays inert unless the caller defines
PLC_ONLY.
Builds a local WooCommerce store to reproduce a merchant's setup or to stage a demo.
./demo-stores/scaffold.sh acme-demo \
--title "Acme Demo" \
--plugins "woocommerce-subscriptions,mailchimp-for-woocommerce"Defaults target Laravel Herd. Override SITE_ROOT, DB_*, SITE_TLD, and
SITE_SCHEME to run it against Docker or another local stack. Plugin
resolution goes local zip, then fuzzy local match, then wp.org.
demo-stores/seed-content/ holds page content for the sample store.
Outside-in fingerprinting of a live storefront: REST namespaces, plugin asset paths, third-party hosts, and cart/checkout stage footprints, collected through a real browser rather than curl. Tracked as WOOCS-83.
Design constraint set by this repo's policy: code, the vendor signature catalog, and docs live here with placeholders only. Target lists and scan output live outside the repo. The tool takes its target list as input and writes results to a path outside the working tree by default.
bash,curl,gawk(orawk),python3(standard library only)- SSH access to any environment you benchmark
- WooCommerce REST API consumer key and secret, for the REST benchmarks
sshpassfor password-based SSH:brew install hudochenkov/sshpass/sshpass- Google PageSpeed Insights API key, optional, for higher CWV rate limits
- WP-CLI and a local PHP/MySQL stack for
demo-stores/
Shell scripts find their tools via ${CURL_PATH:-$(command -v curl)} and
${GAWK_PATH:-...}. Override either if you need a specific binary.
- Put it in the directory that owns its concern. A new concern gets a new top-level directory and a row in the components table above.
- PHP probes output
Content-Type: text/plain, use=== Section ===headers, andrequire_once __DIR__ . '/wp-load.php'. - Add any new credential to
credentials.mdand to the matching.env.d/**/*.env.exampletemplate sobin/check-credscan validate it. - If it deploys files to a remote, teach
benchmarking/cleanup.shto remove them. - Keep real values out. Placeholders only.