Read-only CLI that pulls a WooCommerce catalogue into local Markdown and JSON, so a shop's product data can be read, diffed and reasoned about offline.
pks-agent-woocommerce-cli product sync [--dir PATH] [--lang CODE] [--with-variations]$ pks-agent-woocommerce-cli initConnect a store — prompts for the REST key, stores it outside the profile file
$ pks-agent-woocommerce-cli product sync --with-variationsPull the whole catalogue, variations included, into ./woo
$ pks-agent-woocommerce-cli pim reportWhat product information actually exists, per field, from the local pull
pks-agent-woocommerce-cli pulls a WooCommerce catalogue out of a shop and
leaves it on disk as Markdown and JSON — one file per product, plus an index —
so the catalogue can be read, diffed, reviewed and handed to an agent without
anyone opening the shop's admin again.
It exists because reviewing someone else's WooCommerce store through the admin UI is neither repeatable nor safe: you click through hundreds of products, you see one at a time, you cannot diff last week against this week, and every page you open is a session on a production site. This pulls the data out once, verifiably, and leaves you with files.
Not read-only by discipline — read-only because there is no code path that could
write. The HTTP client exposes exactly one verb, Get. No POST, PUT,
PATCH or DELETE exists anywhere in the binary, so no future change, flag or
mistake can modify a customer's shop without someone deliberately adding a new
HTTP verb first. Continuous integration greps for one and fails the pull request
that introduces it.
Two further deliberate limits:
--key, --secret, --consumer… and
--password are refused with an explanation rather than silently unsupported:
arguments are visible in ps and are saved to shell history. Credentials come
from the profile store, which init fills in with the input hidden — or, for
containers and scheduled jobs, from injected environment variables that are
never written to disk.| Command | What it leaves behind |
|---|---|
product sync | woo/raw/products/*.json (the API response, unedited), Markdown per product, index.json, sync-state.json |
pim report | Field-by-field coverage of the local pull — what is filled in, what is not, and for how many products |
export ontology | ontology.json for applications and ontology.md for people: object types, every field with its fill rate and owner, the links between them, and the data-quality findings |
export xlsx | catalogue.xlsx — only the columns that actually carry data, plus the field inventory and the issue list |
export all | Both of the above |
Everything after init reads the stored profile — or the PKS_WOO_* variables,
where a scheduler injects them; the commands ask, they do not demand a wall of
flags.
A translation in WPML or Polylang is a separate product post, so --lang pulls
one language into its own directory:
for lang in da en de fr; do
pks-agent-woocommerce-cli product sync --dir "./woo/$lang" --lang "$lang" --with-variations
done
Which language holds the prices is a property of the shop, not of the CLI. WooCommerce Multilingual writes per-currency prices onto the original post, so on most shops the prices for every market live in the original language's export — pull that language even when only a translation changed.
You need a WooCommerce REST API key with Read permission
(WooCommerce → Settings → Advanced → REST API → Add key). init prompts for it
with the input hidden and never echoes it back.
Creating that key is a write on a production site. Get the shop owner's authorization first, and revoke the key when the work is finished.
Two hard requirements, both of which init checks and explains rather than
failing obscurely:
| Requirement | Why | Symptom when missing |
|---|---|---|
| HTTPS | Woo accepts key/secret over HTTP Basic only on TLS; over plain HTTP it demands OAuth 1.0a signatures | every request 401s |
| Pretty permalinks | Woo's authenticator only recognises URLs containing wp-json/wc/, so ?rest_route= is never authenticated | a valid key 401s forever |