FlowRegistry, delegates rendering to the matched AbstractFlow subclass, and that class paints the interface by recursively walking the JSON structure.
System diagram
Render pipeline
The following sequence describes what happens from the moment a user visits a product page to the moment a compiled form appears in the browser.Core components
FlowRegistry
Central static registry that maps WooCommerce products to their assigned flow. Loads product→flow assignments from
wp_utb_form_configs on first access and caches them in memory for the request lifecycle.AbstractFlow
Base class for all flows. Registers WooCommerce hooks (
woocommerce_add_cart_item_data, woocommerce_checkout_create_order_line_item, etc.), handles cart validation, dynamic pricing, and order meta persistence. Concrete flows extend this class.FormConfigManager
Resolves form configuration for a given product and flow. Checks product post meta (
_utb_form_config) first, then falls back to a linked certificate record, and finally to the flow’s built-in default config.ApiConnectionManager
Generic, connection-agnostic HTTP hub. Given a
$connection_id, it reads encrypted credentials from the database, negotiates OAuth2 tokens (cached as WordPress Transients), and injects Authorization headers into outbound requests.RulesEngine
Programmable validation pipeline configured from the WordPress dashboard. At form submit time it interpolates field values into API endpoint URLs, calls
ApiConnectionManager for auth headers, fires cURL requests, and evaluates JSON path mappings to accept or reject submissions.DataSourceManager
Abstraction layer for dynamic
<select> options. Reads data source definitions from wp_utb_data_sources and serves filtered option lists to the form renderer — no hardcoded data arrays in template code.SubmissionHandler
Universal form data capture and persistence layer. Stores form submissions and uploaded files at cart time (temporarily), moves them to permanent storage on payment, and updates status on failure or cancellation. Works with every flow automatically.
Technology stack
| Layer | Technology |
|---|---|
| Backend | PHP 8.1+ with strict typing, abstract classes, and interfaces |
| Database | Custom tables via $wpdb; independent of wp_postmeta |
| Frontend | Plain HTML5, CSS Flexbox/Grid, jQuery (WooCommerce compatibility only) |
| E-commerce | Native WooCommerce hooks: woocommerce_add_cart_item_data, woocommerce_checkout_create_order_line_item |
| REST API | Native WP REST API at /wp-json/utb/v1/ with custom Bearer Token validators |
| External comms | wp_remote_request wrapper over cURL for Banner/Iceberg integration |
| Token caching | WordPress Transients API |
| Auth types | OAuth2 Client Credentials, Bearer Token, HTTP Basic Auth |
Key design decisions
No React or Vue. The frontend uses zero JavaScript framework dependencies. This avoids bundle fatigue and keeps the plugin compatible with any WordPress theme without build tooling. Custom DB tables, notwp_postmeta. High-volume form configuration and submission data is stored in dedicated tables (wp_utb_form_configs, wp_utb_product_submissions, etc.) to avoid the performance pitfalls of the key-value wp_postmeta table.
Generic connection manager instead of per-API classes. ApiConnectionManager replaces what would have been separate CEPOAuthManager, BannerManager, and similar classes. New API integrations are added through the admin UI — no code changes required.
Declarative logic binding. Field visibility, required state, and value propagation are expressed as a logic_binding JSON object attached to each field definition. The generic frontend script (form-builder.js) reads these declarations and wires up event listeners dynamically, so no custom JavaScript is needed per form.
Flow extension point. The do_action('utb_pb_register_flows') hook, fired during Plugin::register_flows(), allows external plugins or themes to register additional flows into the registry without modifying the plugin’s own code.