CBX on WordPress — Platform Guide
- Version
- 3.x
- Updated
Audience: integrators and developers running CBX on WordPress · Scope: how the WordPress edition is wired — the adapter plugin, routing/URLs, the
/cbx-api/endpoint, identity bridging, host CSS, WP-CLI, and migrations · Last reviewed: 2026-07-25Store admins: the task-oriented manual is the Admin Guide — its CBX on WordPress article covers logging in, the menu, and the shortcode in plain language. This document is the technical counterpart.
TL;DR — Unlike on Magento 2, CBX on WordPress is the full application: it brings
its own product lists, cart, checkout, orders and customer area. WordPress contributes hosting,
identity and the admin shell; a thin adapter plugin (configbox.php and friends, in the
plugin root) bridges WP's hooks to the shared, platform-agnostic app in
wp-content/plugins/configbox/app/ (the component submodule). Storefront URLs are backed by
hidden custom post types that CBX maintains itself; XHR calls use the pretty
/cbx-api/<controller>/<task> endpoint; wp configbox … mirrors the Joomla console
commands.
1. The two layers
| Layer | Files | Lives in |
|---|---|---|
| WordPress adapter | configbox.php (hooks, routing, CPTs, shortcode, admin menu), cli.php (WP-CLI wrapper), templates/general.php (loader template), uninstall.php | The plugin root — host-repo code, packaged with every WordPress release |
| CBX app | app/… — the shared component (identical code on Joomla/Magento 2) | The component submodule |
The app's own WordPress-specific bindings sit inside the component, behind the platform
abstraction: app/external/kenedo/platforms/wordpress/ (the KenedoPlatformWordpress class),
app/helpers/wordpress.php (ConfigboxWordpressHelper — the WP-post sync), and
app/observers/Wordpress.php. Platform-specific behavior belongs there, not inline in shared
code.
2. Boot
configbox_init_kenedo()(adapter) runs on WordPress'sinithook and callsinitKenedo('com_configbox'). Kenedo auto-detects thewordpressplatform.- Everything is gated by
shouldInitCb(), which skips CBX entirely for requests that never need it (WP cron, heartbeat, Elementor AJAX, background queues). Respect the gate when adding hooks. - A request "is a CBX request" when it carries
option=com_configbox— the whole adapter pipeline keys off that request param, exactly like Joomla's component routing.
3. Storefront routing and URLs
WordPress has no component/frontname router, so the adapter builds one out of stock WP parts:
- Hidden custom post types back the SEF URLs:
cb_product_list,cb_product,cb_page(configurator pages) andcb_internal(cart, account). CBX maintains these rows itself:app/observers/Wordpress.phpreacts to admin saves/copies and callsConfigboxWordpressHelper::makePageFor…()to insert/update the matching post per language. Never edit these posts by hand — they are regenerated from CBX data. getRoute()(platforms/wordpress/general.php) turns internalindex.php?option=com_configbox&view=…URLs into the post permalinks, and translates the Kenedo params to WP conventions for everything else:view/controller→page,controller.task→action. In the admin area it targetsadmin.php, oradmin-ajax.phpfor view-only/raw output.- The CPT slug (
/cb_product/…) is stripped from permalinks (cb_remove_slug), andcb_parse_requestwidens the main query's post-type search so the slugless URLs resolve. - On CBX requests the adapter suppresses WP's 404 handling (
pre_handle_404), clears the 404 query-var thatparse_requestsets for unresolvable paths, and vetoes canonical redirects — the request must reach CBX untouched. - Rendering goes through a loader template:
template_includeswaps intemplates/general.php, which runsconfigbox_execute_controller_task()— the WP equivalent of Joomla's component dispatch (controller/task resolution, output buffering, observer-filtered output).
The /cbx-api/ endpoint
The
cb-api→cbx-apirename is complete on WordPress (adapter side landed 2026-08-27)./cb-api/…is gone with no alias and no redirect — it 404s, exactly as on Joomla.
configbox_cb_api_inject_params()keeps its old name on purpose. Its existence is the feature detection:getEndpointUrl()inplatforms/wordpress/general.phptestsfunction_exists('configbox_cb_api_inject_params')before emitting a pretty URL. The rename moved the URL segment and deliberately left that literal alone, so the adapter matches it. Renaming the function without changing thefunction_exists()call would fail detection and silently drop every frontend XHR back to the query-string URL — which is the designed fallback, not a failure, and is why a mismatched adapter/component pair degrades instead of breaking.
Frontend XHR/API calls use /cbx-api/<controller>/<task> — the same shape as Joomla's
/cbx-api frontname route (see the Joomla SEF doc).
There is no rewrite rule: configbox_cb_api_inject_params() (top of configbox.php) runs
before anything else, recognizes the path, and injects the classic request params
(option, controller, task, page, action, output_mode=view_only) into the
superglobals — from there on the request is indistinguishable from a query-string URL. The
app side (getEndpointUrl()) only emits /cbx-api/ URLs when that adapter function exists
(feature detection), so an older adapter falls back to query-string endpoints. Admin XHRs
always keep going through admin-ajax.php for the admin context.
The four surfaces the adapter routes
The surfaces are siblings, each versioned on its own terms — the adapter mirrors the Joomla system plugin branch for branch, and each needs its own pattern because they do not share a shape:
| path | routes to | why it needs its own branch |
|---|---|---|
/cbx-api/v1[/<path…>] | apiv1 / dispatch, remainder in cb_api_path | a resource path of any depth that may carry dots (openapi.json, schemas/read/product.json) — its segments name an entity and a record, not a controller and a task |
/cbx-api/mcp | apiv1 / mcp | a single segment, so the generic two-segment form below cannot match it |
/cbx-api/oauth/<task> | oauth / <task> | already fits the generic <controller>/<task> form — no special branch |
/cbx-api/<controller>/<task> | that controller and task | the original XHR endpoint |
cb_api_path keeps its name for the same reason the function does: it is a request parameter,
owned app-side by ConfigboxApiv1Controller::PATH_VAR, not a URL segment. Send a name the
controller does not read and getPath() returns empty, so every v1 call quietly answers the store
index with a 200 — a wrong answer rather than a failure.
MCP is a sibling of the entity API rather than a child of it: /cbx-api/v1/mcp answers 404
(Unknown entity "mcp"), because MCP has its own task on the shared controller. It carries no URL
version because this exact URL is the OAuth protected-resource identifier every issued token records
as its audience.
The OAuth discovery documents need a web-server exemption
RFC 8414 and RFC 9728 pin the metadata to fixed paths at the site root, not under /cbx-api/:
| path | routes to |
|---|---|
/.well-known/oauth-authorization-server | oauth / asMetadata |
/.well-known/oauth-protected-resource/cbx-api/mcp | oauth / prMetadata |
An OAuth client fetches these before it holds any token, so they are pre-auth by design. The
catch on WordPress is not the adapter but the web server: the stock nginx recipe denies everything
matching /\., which 403s these paths before PHP is reached. The dev site's nginx therefore carries
an explicit location ^~ /.well-known/ exemption (^~ outranks a regex location whatever the
order), and any production WordPress host serving the storefront OAuth flow needs the same —
otherwise discovery 403s and no agent can authorize, while everything else looks healthy.
The token commands (wp configbox token-*) and the api-export artifacts refer to endpoints that
actually answer on WordPress.
4. Embedding via shortcode
[configbox view=… id=…] renders a CBX view inside any ordinary WP page:
productlist (legacy alias productlisting), product, configuratorpage, cart,
checkout, user. The shortcode boots Kenedo and returns the view HTML in place.
5. Identity bridging
- WP is the identity provider. The
wp_loginhook maps the WP user to the CBX user (ConfigboxUserHelper) and moves a guest cart onto the logged-in user;wp_logoutlogs the CB user out and resets the cart. Don't bypass these hooks. - CBX user rows are created lazily (on first need), not at WP login.
- The CB "username" is the billing e-mail, which may differ from the WP login name —
KenedoPlatformWordpress::authenticate()andlogin()therefore resolve the WP user by e-mail first, then by login name.
6. The admin area
The CBX backend runs inside wp-admin: add_menu_page() registers the CBX menu
(capability edit_pages), and every CB admin screen is dispatched through
configbox_execute_controller_task(). Admin XHRs are registered as wp_ajax_<page>.<task>
actions; for output_mode=view_only responses the adapter ends the request itself so
admin-ajax's trailing 0 never reaches the client.
7. Host CSS adaptation
WordPress themes — block themes especially — bleed into ConfigBox's markup, so the app ships
per-host correction stylesheets and serves them itself:
KenedoPlatformWordpress::getHostStyleSheetUrls() returns hosts/wordpress-admin.css in
wp-admin and hosts/wordpress-site.css on the site, and KenedoView emits them with every
ConfigBox view. The adapter plugin enqueues nothing — its old assets/css/adapter.css was
folded into hosts/wordpress-site.css so all host adaptation lives in one platform-driven
mechanism. Put new WordPress-only CSS corrections there, not in the plugin.
Full reference: technical/com_configbox_host_stylesheets.md.
8. WP-CLI
wp configbox … mirrors the Joomla console commands one-for-one (thin wrapper cli.php →
shared ConfigboxCliHelper): cache-clear, charset (--status), migrate (--status,
--clear-failed-flag), migrate-unblock, run-task, config-get/set/list,
sysvar-get/set/list — plus custom, the dispatcher for site-specific commands from the
customization layer (wp-content/plugins/configbox-customization/cli/commands.php — the layer's
WordPress location; run wp configbox custom bare to list them — see
customization/com_configbox_custom_cli_commands.md).
Host gotchas:
- The acting-user selector is
--cb-user(WP-CLI reserves the global--userflag). - The
migrate*andcharsetcommands defineCB_SUPPRESS_AUTO_UPDATESat plugin load so booting Kenedo does not auto-apply the very migrations they are meant to report on/control — and so that a read-only--statuscall stays read-only. wp cache flushalso purges the CBX caches (cache-generation stamp bump), matchingbin/magento cache:flushbehavior on Magento 2.
Full reference: technical/com_configbox_cli_commands.md.
9. Migrations on WordPress
Update scripts (app/helpers/updates/) auto-apply on every request that boots Kenedo —
including every wp CLI invocation (except the suppressed migrate*/charset/cache flush commands
above). Logs land under the uploads dir:
wp-content/uploads/cb-logs/configbox/configbox_upgrade_errors.log (not docroot/logs/ as on
Joomla). WP-post-backed data changes are different: renaming/creating the hidden CPT rows
is done in the adapter as an init-hook function guarded by a get_option() flag (see
configbox_migrate_product_list_posts() for the pattern), not as an update script. Full
reference: technical/com_configbox_migrations.md.
10. Multilingual
The post-sync helper maintains one post per language, and CBX's own content strings live in its
EAV configbox_strings store — WP .po/.mo files are not involved. There is no WPML
integration: CBX handles its multilingual content itself.
11. Requirements & lifecycle
Activation checks (and deactivates on failure): PHP 7.1–8.4 (8.0 excluded), WordPress 5.0–6.99
(the ceiling is enforced, so a WordPress 7.0 host refuses activation until it is raised),
the ionCube loader (15+ on PHP 8.4, 14+ on 8.3, 13+ below), and the usual PHP extensions
(gd, mbstring, mysqli, xml, zip, openssl, …). Uninstall (delete via the Plugins screen) runs
uninstall.php, which drops all configbox_*/cbcheckout_* tables (removing referencing
foreign-key constraints first); the hidden CPT rows are not cleaned up.