Claude Skill

br-woo-routes

Expose WooCommerce 10.x orders, products, customers, and coupons with better-route 1.1 WooRouteRegistrar. Use for BetterRoute::wooRouteRegistrar, HPOS guards, actions, permissions, strict list/body validation, pagination meta, stable sorting, protected metadata, atomic idempotenc

LLM Mart · 0 points · 0 views 0 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download Lonsdale201-wp-agent-skills-better-route_br-woo-routes-8820ff3.zip · 4 KB
Part of lonsdale201/wp-agent-skills — 226 skills

Install

skills CLI npx skills add https://github.com/Lonsdale201/wp-agent-skills/tree/main/better-route/br-woo-routes
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install lonsdale201-wp-agent-skills@llmmart
Git git clone https://github.com/Lonsdale201/wp-agent-skills.git

The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole lonsdale201/wp-agent-skills collection as a plugin from our marketplace. Git is the plain clone.

Skill manifest

better-route: WooCommerce routes

Register Woo routes during rest_api_init and retain the returned Router when contracts are needed.

use BetterRoute\BetterRoute;

add_action('rest_api_init', static function (): void {
    $woo = BetterRoute::wooRouteRegistrar()->register('myapp/v1', [
        'basePath' => 'woo',
        'requireHpos' => true,
        'deleteMode' => 'trash',
        'actions' => [
            'customers' => ['list', 'get'],
            'coupons' => [],
        ],
        'permissions' => [
            'orders.list' => 'manage_woocommerce',
            'orders.create' => 'manage_woocommerce',
        ],
    ]);
});

Routes cover orders, products, customers, and coupons under /wp-json/myapp/v1/woo by default.

Actions and permissions

Each resource supports list, get, create, update, and delete; update registers both PUT and PATCH.

  • Omit actions.<resource> for full CRUD.
  • Pass [] to disable that resource.
  • Invalid action names or a non-array value throw.

Permission keys use <resource>.<action>. A value may be bool, capability string, any-of capability list, or callable receiving the request and optionally the registrar. Unrecognized/empty rules deny. Defaults are manage_woocommerce.

Customer writes also enforce native user capabilities inside the service:

  • create: create_users;
  • update: edit_user for the target;
  • delete: delete_user for the target.

Customer list/get expose users with the customer role only; a general WordPress user directory is intentionally not provided.

Lists

GET /wp-json/myapp/v1/woo/orders?status=processing&sort=-date_created&page=1&per_page=50&fields=id,total,status

Lists return pagination in the JSON envelope:

{"data": [], "meta": {"page": 1, "perPage": 50, "total": 0}}

Do not expect X-WP-Total or X-WP-TotalPages; Better Route Woo pagination is in meta.

per_page > maxPerPage returns 400 validation_failed; it is not clamped. sort=-field means DESC. Services add an ID tie-breaker so equal primary sort values paginate deterministically.

Strict parsers reject unknown parameters but accept WordPress globals _locale, _fields, _embed, _envelope, and _jsonp, including wp.apiFetch's _locale=user.

Resource filters/sorts differ:

  • orders: status, customer_id, search; stable order/date/total options supported by parser;
  • products: status, type, sku, search, stock_status; derived price sorting is not supported;
  • customers: role, email, search;
  • coupons: code, search.

Use each parser's allowlist rather than forwarding arbitrary Woo query vars.

Strict write payloads in 1.1

All services reject unknown top-level fields and enforce field types before setters/save.

Orders:

  • validate the complete payload before persistence;
  • reject unknown billing/shipping/line-item keys;
  • require product_id for line items and validate product/variation existence and relationship;
  • require positive finite line quantities supported by Woo's stock normalizer, and non-negative finite totals;
  • refuse line-item replacement after stock reduction with 409 woo_line_items_locked;
  • run create/update inside wc_transaction_query('start'/'commit'/'rollback').

Products:

  • treat price as read-only;
  • write regular_price and sale_price instead;
  • validate all fields before applying setters/save.

Customers:

  • require email on create;
  • reject username on update because WordPress usernames are immutable through this API;
  • reject unknown address keys and non-string address values;
  • omit expensive orders_count and total_spent from list defaults to avoid N+1 work; request them explicitly when needed.

Coupons:

  • require code on create;
  • strictly validate monetary, boolean, list, date, and metadata fields;
  • enforce normalized code uniqueness on create and update under a MySQL named lock;
  • exclude the current coupon ID when checking an update; conflicts return 409 coupon_exists.

Money response fields are decimal strings, not JSON floats.

1.1.1 order lifecycle and quantities

  • Initialize payment gateways before writes; apply items/addresses and calculate taxes/totals before staging the requested status. Status hooks see final totals.
  • Treat billing/shipping-only updates as financially significant: they recalculate totals even on paid orders.
  • Save before payment completion. On update, set_paid: true calls payment_complete() only when the order still needs payment. Repeated paid updates do not repeat the event. An already-paid status with set_paid is not a guarantee of that event or evidence of external capture.
  • Do not assume database rollback undoes emails, webhooks or external hook effects.
  • Accept finite numeric quantities (including numeric strings). Order lines must be positive; product stock accepts negative values and null. Reject booleans, non-numeric/non-finite values, and any quantity that wc_stock_amount() would change, before persistence.
  • Keep fractional Woo stock configuration active for later reads as well as writes. Woo normalizes quantities on load; Better Route does not recover old fractions by bypassing its data store.
  • Use OpenAPI number for line quantities, exclusiveMinimum: 0 on input, and number or null for stock.

The registrar is administrative CRUD, not a Store API cart/checkout adapter. It adds no storefront or refund endpoints in 1.1.1. Runtime changes were checked with WooCommerce 11.1.1 on both HPOS and legacy storage; requireHpos remains enabled by default.

Metadata

Use the actual helper APIs:

$meta = MetaDataHelper::normalizeIncoming($payload['meta_data'] ?? null);
MetaDataHelper::applyToTarget($object, $meta);
$serialized = MetaDataHelper::serialize($object->get_meta_data());

Incoming metadata may be a key/value map or a list of {key,value} entries. Underscore-prefixed protected keys are rejected on write and omitted on serialization by default. Opt in with allowProtected/includeProtected only on tightly protected internal code paths.

Atomic idempotency

'idempotency' => [
    'enabled' => true,
    'requireKey' => true,
    'ttlSeconds' => 86400,
    'resources' => [
        'orders' => true,
        'products' => true,
        'customers' => true,
        'coupons' => true,
    ],
],

Idempotency defaults to disabled and requireKey defaults to false; enable both explicitly for protected retry-safe writes. 1.1 uses AtomicIdempotencyMiddleware and requires a custom store to implement AtomicIdempotencyStoreInterface. Under WordPress, the default is a lease-aware wpdb store whose schema is installed/migrated once per version option; failure is surfaced rather than silently falling back.

The current 1.1 registrar attaches idempotency to create and update routes. DELETE routes are not wrapped by the registrar's idempotency configuration; add a custom raw route/middleware if idempotent delete replay is a requirement.

Before updating existing idempotent writers to 1.1.1, follow br-install-and-migrate: default namespace/URL keys and fingerprints change without translating legacy records.

HPOS

requireHpos defaults to true and gates order routes only. When HPOS is unavailable, order routes return 503 hpos_required; products/customers/coupons are not HPOS data stores.

The host plugin must also declare compatibility from its main file:

BetterRoute\Integration\Woo\HposGuard::declareCompatibility(__FILE__);

The runtime guard does not replace Woo's feature compatibility declaration.

OpenAPI

Use the returned Router's contracts and BetterRoute::wooOpenApiComponents(). In 1.1 input schemas match strict runtime behavior: customer create requires email, coupon create requires code, product input excludes derived price, order line input requires product ID, and nested addresses disallow additional properties.

Review checklist

  • Set deleteMode explicitly; default force is destructive.
  • Keep HPOS required for production order APIs and declare host compatibility.
  • Verify action omission versus explicit [].
  • Test customer role plus native capabilities.
  • Assert oversized per_page is 400 and read totals from JSON meta.
  • Test unknown nested keys and exact scalar types for every write entity.
  • Concurrency-test duplicate idempotent create/update and duplicate coupon codes.
  • Request expensive customer aggregate fields only when necessary.

Related skills

  • Use br-atomic-idempotency for reservation semantics.
  • Use br-openapi for document generation.
  • Use WooCommerce HPOS skills for migration/operational setup.

References

  • Verified source paths:
    • src/Integration/Woo/WooRouteRegistrar.php
    • src/Integration/Woo/WooOrderService.php
    • src/Integration/Woo/WooProductService.php
    • src/Integration/Woo/WooCustomerService.php
    • src/Integration/Woo/WooCouponService.php
    • src/Integration/Woo/WooOpenApiComponents.php
Files (wp-agent-skills)
  • SKILL.md 9.5 KB
    ---
    name: br-woo-routes
    description: Expose WooCommerce orders, products, customers, and coupons with better-route 1.1 WooRouteRegistrar. Use for BetterRoute::wooRouteRegistrar, HPOS guards, actions, permissions, strict list/body validation, pagination meta, stable sorting, protected metadata, atomic idempotency, transactional order writes, product price rules, customer role/capability rules, coupon uniqueness, or Woo OpenAPI components.
    metadata:
      wp-skills-author: "Soczó Kristóf"
      wp-skills-contact: "mailto:lonsdale201@hotmail.com"
      wp-skills-plugin: "better-route"
      wp-skills-plugin-version-tested: "1.1.1"
      wp-skills-php-min: "8.1"
      wp-skills-last-updated: "2026-09-21"
    ---
    
    # better-route: WooCommerce routes
    
    Register Woo routes during `rest_api_init` and retain the returned Router when contracts are needed.
    
    ```php
    use BetterRoute\BetterRoute;
    
    add_action('rest_api_init', static function (): void {
        $woo = BetterRoute::wooRouteRegistrar()->register('myapp/v1', [
            'basePath' => 'woo',
            'requireHpos' => true,
            'deleteMode' => 'trash',
            'actions' => [
                'customers' => ['list', 'get'],
                'coupons' => [],
            ],
            'permissions' => [
                'orders.list' => 'manage_woocommerce',
                'orders.create' => 'manage_woocommerce',
            ],
        ]);
    });
    ```
    
    Routes cover orders, products, customers, and coupons under `/wp-json/myapp/v1/woo` by default.
    
    ## Actions and permissions
    
    Each resource supports `list`, `get`, `create`, `update`, and `delete`; update registers both PUT and PATCH.
    
    - Omit `actions.<resource>` for full CRUD.
    - Pass `[]` to disable that resource.
    - Invalid action names or a non-array value throw.
    
    Permission keys use `<resource>.<action>`. A value may be bool, capability string, any-of capability list, or callable receiving the request and optionally the registrar. Unrecognized/empty rules deny. Defaults are `manage_woocommerce`.
    
    Customer writes also enforce native user capabilities inside the service:
    
    - create: `create_users`;
    - update: `edit_user` for the target;
    - delete: `delete_user` for the target.
    
    Customer list/get expose users with the `customer` role only; a general WordPress user directory is intentionally not provided.
    
    ## Lists
    
    ```http
    GET /wp-json/myapp/v1/woo/orders?status=processing&sort=-date_created&page=1&per_page=50&fields=id,total,status
    ```
    
    Lists return pagination in the JSON envelope:
    
    ```json
    {"data": [], "meta": {"page": 1, "perPage": 50, "total": 0}}
    ```
    
    Do not expect `X-WP-Total` or `X-WP-TotalPages`; Better Route Woo pagination is in `meta`.
    
    `per_page > maxPerPage` returns `400 validation_failed`; it is not clamped. `sort=-field` means DESC. Services add an ID tie-breaker so equal primary sort values paginate deterministically.
    
    Strict parsers reject unknown parameters but accept WordPress globals `_locale`, `_fields`, `_embed`, `_envelope`, and `_jsonp`, including `wp.apiFetch`'s `_locale=user`.
    
    Resource filters/sorts differ:
    
    - orders: status, customer_id, search; stable order/date/total options supported by parser;
    - products: status, type, sku, search, stock_status; derived price sorting is not supported;
    - customers: role, email, search;
    - coupons: code, search.
    
    Use each parser's allowlist rather than forwarding arbitrary Woo query vars.
    
    ## Strict write payloads in 1.1
    
    All services reject unknown top-level fields and enforce field types before setters/save.
    
    Orders:
    
    - validate the complete payload before persistence;
    - reject unknown billing/shipping/line-item keys;
    - require `product_id` for line items and validate product/variation existence and relationship;
    - require positive finite line quantities supported by Woo's stock normalizer, and non-negative finite totals;
    - refuse line-item replacement after stock reduction with `409 woo_line_items_locked`;
    - run create/update inside `wc_transaction_query('start'/'commit'/'rollback')`.
    
    Products:
    
    - treat `price` as read-only;
    - write `regular_price` and `sale_price` instead;
    - validate all fields before applying setters/save.
    
    Customers:
    
    - require `email` on create;
    - reject `username` on update because WordPress usernames are immutable through this API;
    - reject unknown address keys and non-string address values;
    - omit expensive `orders_count` and `total_spent` from list defaults to avoid N+1 work; request them explicitly when needed.
    
    Coupons:
    
    - require `code` on create;
    - strictly validate monetary, boolean, list, date, and metadata fields;
    - enforce normalized code uniqueness on create and update under a MySQL named lock;
    - exclude the current coupon ID when checking an update; conflicts return `409 coupon_exists`.
    
    Money response fields are decimal strings, not JSON floats.
    
    ## 1.1.1 order lifecycle and quantities
    
    - Initialize payment gateways before writes; apply items/addresses and calculate taxes/totals before staging the requested status. Status hooks see final totals.
    - Treat billing/shipping-only updates as financially significant: they recalculate totals even on paid orders.
    - Save before payment completion. On update, `set_paid: true` calls `payment_complete()` only when the order still needs payment. Repeated paid updates do not repeat the event. An already-paid status with `set_paid` is not a guarantee of that event or evidence of external capture.
    - Do not assume database rollback undoes emails, webhooks or external hook effects.
    - Accept finite numeric quantities (including numeric strings). Order lines must be positive; product stock accepts negative values and null. Reject booleans, non-numeric/non-finite values, and any quantity that `wc_stock_amount()` would change, before persistence.
    - Keep fractional Woo stock configuration active for later reads as well as writes. Woo normalizes quantities on load; Better Route does not recover old fractions by bypassing its data store.
    - Use OpenAPI `number` for line quantities, `exclusiveMinimum: 0` on input, and `number` or `null` for stock.
    
    The registrar is administrative CRUD, not a Store API cart/checkout adapter. It adds no storefront or refund endpoints in 1.1.1. Runtime changes were checked with WooCommerce 11.1.1 on both HPOS and legacy storage; `requireHpos` remains enabled by default.
    
    ## Metadata
    
    Use the actual helper APIs:
    
    ```php
    $meta = MetaDataHelper::normalizeIncoming($payload['meta_data'] ?? null);
    MetaDataHelper::applyToTarget($object, $meta);
    $serialized = MetaDataHelper::serialize($object->get_meta_data());
    ```
    
    Incoming metadata may be a key/value map or a list of `{key,value}` entries. Underscore-prefixed protected keys are rejected on write and omitted on serialization by default. Opt in with `allowProtected/includeProtected` only on tightly protected internal code paths.
    
    ## Atomic idempotency
    
    ```php
    'idempotency' => [
        'enabled' => true,
        'requireKey' => true,
        'ttlSeconds' => 86400,
        'resources' => [
            'orders' => true,
            'products' => true,
            'customers' => true,
            'coupons' => true,
        ],
    ],
    ```
    
    Idempotency defaults to disabled and `requireKey` defaults to false; enable both explicitly for protected retry-safe writes. 1.1 uses `AtomicIdempotencyMiddleware` and requires a custom store to implement `AtomicIdempotencyStoreInterface`. Under WordPress, the default is a lease-aware wpdb store whose schema is installed/migrated once per version option; failure is surfaced rather than silently falling back.
    
    The current 1.1 registrar attaches idempotency to create and update routes. DELETE routes are not wrapped by the registrar's idempotency configuration; add a custom raw route/middleware if idempotent delete replay is a requirement.
    
    Before updating existing idempotent writers to 1.1.1, follow `br-install-and-migrate`: default namespace/URL keys and fingerprints change without translating legacy records.
    
    ## HPOS
    
    `requireHpos` defaults to true and gates order routes only. When HPOS is unavailable, order routes return `503 hpos_required`; products/customers/coupons are not HPOS data stores.
    
    The host plugin must also declare compatibility from its main file:
    
    ```php
    BetterRoute\Integration\Woo\HposGuard::declareCompatibility(__FILE__);
    ```
    
    The runtime guard does not replace Woo's feature compatibility declaration.
    
    ## OpenAPI
    
    Use the returned Router's contracts and `BetterRoute::wooOpenApiComponents()`. In 1.1 input schemas match strict runtime behavior: customer create requires email, coupon create requires code, product input excludes derived price, order line input requires product ID, and nested addresses disallow additional properties.
    
    ## Review checklist
    
    - Set `deleteMode` explicitly; default `force` is destructive.
    - Keep HPOS required for production order APIs and declare host compatibility.
    - Verify action omission versus explicit `[]`.
    - Test customer role plus native capabilities.
    - Assert oversized `per_page` is 400 and read totals from JSON `meta`.
    - Test unknown nested keys and exact scalar types for every write entity.
    - Concurrency-test duplicate idempotent create/update and duplicate coupon codes.
    - Request expensive customer aggregate fields only when necessary.
    
    ## Related skills
    
    - Use `br-atomic-idempotency` for reservation semantics.
    - Use `br-openapi` for document generation.
    - Use WooCommerce HPOS skills for migration/operational setup.
    
    ## References
    
    - Verified source paths:
      - `src/Integration/Woo/WooRouteRegistrar.php`
      - `src/Integration/Woo/WooOrderService.php`
      - `src/Integration/Woo/WooProductService.php`
      - `src/Integration/Woo/WooCustomerService.php`
      - `src/Integration/Woo/WooCouponService.php`
      - `src/Integration/Woo/WooOpenApiComponents.php`
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related