Advanced WooCommerce Checkout Builder
An advanced checkout customize builder for WordPress compatible to WooCommerce
by Manoj Kumar P C · github.com/manoj-intellect/advanced-checkout-builder
Install
No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:
wp plugin install https://github.com/manoj-intellect/advanced-checkout-builder/archive/refs/heads/main.zipA configuration-driven builder for the WooCommerce Checkout block. WooCommerce stays responsible for checkout business logic; this plugin is a data-driven extension layer around it.
- Design: docs/architecture.md
- What is (and is not) possible with the official Block Checkout APIs: docs/feasibility-matrix.md
- Example configuration: docs/examples/business-gst.json
Status
Phase 7 (Styling + preview) — complete. Phases 1–6 (Foundation, Checkout integration, Layout, Rules, Dynamic data, WooCommerce runtime) are complete as well.
Phase 7 added styling and previews:
- Design (toolbar): accent, text, help-text, heading, section and error colors; font and label weight; section title size, corner radius, padding and spacing, and field spacing. Apply them to your own sections only, or to the whole checkout. The whole-checkout option also restyles WooCommerce's Place order button, links, focus rings and labels, on a best-effort basis. Values follow strict formats, so nothing but these tokens reaches the page's CSS. A checkout without styles gets no extra CSS at all.
- Preview (Edit / Preview switch): the builder renders the real checkout components from your unsaved changes, against a simulated shopper. You set the cart total, items, coupons, products, categories, addresses, payment and shipping method, and login and role, and conditions, data sources and payment method rules respond. "Check the form" shows every validation message.
- Live preview: opens the real checkout with your saved draft, visible to you only (a signed cookie, valid for an hour). Shoppers keep seeing the published checkout. Place order is blocked on the page, and the server refuses any order request carrying the preview cookie. "Exit preview" returns to the published checkout.
Phase 6 added payment and shipping method rules:
- Hide a payment method (or offer it only when…) based on the billing or shipping address, the cart (total, subtotal, items, coupons, products, categories, currency, whether shipping is needed), the chosen shipping method, or the customer. Set it from the "Payment method rules" button on the builder's Payment options step.
- Hide a shipping method's rates in every zone, the same way ("Shipping method rules" on the Shipping options step). Rate rules use the cart subtotal: the total is still being computed when rates are chosen.
- One evaluator, on the server. WooCommerce passes the filtered list of payment methods to the Checkout block with every cart update, so a rule hides a method live in the browser, and WooCommerce refuses it at checkout. Rates are recalculated the same way. WooCommerce's rate cache follows every value a rule reads.
- Live data sources: "Available payment methods" and "Available shipping rates" can fill a select or radio field straight from WooCommerce's current cart. The server checks the submitted value against the same list.
Phase 5 added data sources (WooCommerce → Checkout Data):
- Providers: typed-in lists, imported lists (CSV, up to 250,000 rows, up to three filter columns), posts/pages, categories/tags, product categories, products, and WooCommerce's countries and states. Users are an admin-only provider (never served at checkout). Developers add providers on
acb_register_dataset_provider. - Dependent options: select, multi-select and radio fields take options from a data source whose filters are bound to other answers (
{{field.country}}), the address ({{billing.state}}), the cart or the customer. In the browser a list waits for its parents ("Select State first"), empties when they change, debounces and cancels requests, caches pages, and becomes an accessible searchable combobox for long lists. - Public options route
GET /acb/v1/options/{field}, addressed by published field (not dataset), rate limited, cacheable unless the filters read the session. Small lists that depend on nothing are inlined into the page instead. - Server enforcement: every submitted option must exist in its data source for the submitted parent answers; publish checks unknown/private data sources, unknown filters, invalid variables and filter loops.
- Admin: CSV import in chunks (staged, so the checkout never sees half a file), export, row search, "Try it", and "Options come from" in the builder inspector.
- Performance (exit criterion): 50,000 cities over 92 states, 400 mixed requests without a persistent object cache — plugin handler p95 8 ms with opcache (13.7 ms without); the whole request p95 225 ms, of which the WordPress + WooCommerce bootstrap alone is 221 ms p95 on the local dev server (
tests/e2e/options-bench.js).
Phase 4 added conditions: show or hide any component, and make fields required, disabled or read-only, based on other answers, the billing/shipping address, the cart (total, subtotal, item count, coupons, product and category IDs, currency, whether shipping is needed), the payment or shipping method, or whether the customer is logged in and their role.
- One rule language, evaluated twice. The browser evaluates conditions live (
src/shared/rules/). The server evaluates them again from the Store API request and WooCommerce's own state (includes/Rules/), never trusting what the browser showed. Hidden fields are not validated, submitted or saved. - WooCommerce's own fields (placed inside WooCommerce's steps) get their visibility and "required" conditions compiled to WooCommerce's JSON Schema rules, so WooCommerce enforces them itself. Conditions it cannot check are flagged in the editor and block publishing.
- Condition editor in the builder: nested all/any/none groups, operators that fit each value type, pick-lists for fields' options, countries, payment methods, shipping methods and roles, and a plain-language summary. Components with conditions carry a Conditional badge.
- Publish checks: unknown sources, conditions WooCommerce cannot run for its own fields, and fields whose visibility depends on itself in a loop.
- Parity: 126 shared condition cases and 13 resolution cases run in Jest and PHPUnit. For the 84 cases WooCommerce can run natively, the compiled schemas are validated with the same JSON Schema library WooCommerce uses, and must give the same answers as both evaluators.
Phase 3 added:
- Row layouts: column presets (50/50, 33/67, 25/50/25, 4 × 25 and more) and a "Stack columns" choice (on mobile, on tablet and mobile, never). Presets never delete a column that holds components.
- Responsive widths: quick presets (full, ¾, ⅔, ½, ⅓, ¼) per device, a width badge on the canvas, and storefront breakpoints that match the builder preview (tablet ≤ 1024 px, mobile ≤ 600 px viewport, plus mobile widths for very narrow sections).
- Keyboard reordering: an Outline tab (a WAI-ARIA tree: arrow keys, Home/End, Enter to select). In the outline and on the canvas, Alt+Shift+↑/↓ moves among siblings, Alt+Shift+← moves out of a container and Alt+Shift+→ moves into the container above. Focus stays on the moved component, and every move (or refused move) is announced.
What works on the storefront (Checkout block):
- Builder sections render between WooCommerce's checkout steps, through an
acb/checkout-sectioninner block. It is added to the checkout page with one click from the builder, which saves a page revision. - Native fields placed inside WooCommerce's own steps are registered through the Additional Checkout Fields API. WooCommerce then renders, stores and displays them.
- Validation runs instantly in the browser and again on the server when the order is placed. Both sides run the same rules, checked by 69 shared test cases. Errors block "Place order" through WooCommerce's validation store and are announced to screen readers.
- Persistence stores builder values as order meta (
_acb_{name}), using HPOS or legacy storage. They can optionally be remembered for logged-in customers. They are shown in order admin, emails, the order confirmation page and My Account, and included in personal-data export and erasure. - Builder additions: a validation editor with a regex tester, and a warning when a section's position is missing from the checkout page.
Phase 1 delivered the builder itself: config storage with draft/publish, revisions and optimistic locking, the REST API, and the manage_checkout_builder capability.
Requirements
WordPress 6.7+, WooCommerce 9.9+ (11.2+ for the full native-field feature set), PHP 8.1+.
Development
composer install
npm install
npm run build # production build + bundle guard
npm start # watch mode
| Check | Command |
|---|---|
| PHP unit tests | composer test |
| PHP static analysis (level 8) | composer analyse |
| PHP coding standards | composer lint |
| JS/TS unit tests | npm run test:js |
| Type check | npm run typecheck |
| Lint | npm run lint:js · npm run lint:css |
| Browser tests | see tests/e2e/README.md |
npm run env:start needs Docker (wp-env).
Layout
advanced-checkout-builder.php bootstrap (PHP-version safe)
includes/ PHP (PSR-4, namespace ACB\)
Admin/ API/ Checkout/ Config/ Fields/ Rules/ Security/ Storage/ Support/ Validation/ WooCommerce/
blocks/checkout-section/ block.json of the checkout inner block
src/
admin/ React builder (store, components, dnd, hooks)
checkout/ storefront bundle (inner block, fields, layout, WooCommerce store adapter)
shared/ config types, component registry, tree operations, validation
tests/
php/Unit/ PHPUnit + Brain Monkey
js/ Jest
fixtures/ validation cases shared by PHPUnit and Jest
e2e/ browser tests (builder, checkout, block editor)