A UK manufacturer needed customers to configure bespoke products online — selecting material, dimensions, finish and accessories — with the total price recalculating instantly on every change. No configurator plugin came close to their requirements. I built the entire engine from scratch — REST API, pricing matrix, live JS layer and full WooCommerce cart integration.
WooCommerce's native variable products are built for simple attribute combinations. The client needed a multi-dimensional pricing engine where dozens of option combinations produce unique prices — and every change reflects immediately on screen.
WooCommerce variations cap out at 50 combinations and can't handle matrix-style pricing across multiple independent dimensions. Off-the-shelf configurator plugins brought bloat, £500+/yr licencing and zero flexibility.
A custom PHP pricing engine exposed via a WP REST endpoint, paired with a lean vanilla JS layer that fires on every option change and updates the price display without a page reload — zero frameworks, zero overhead.
WordPress AJAX requires wp_ajax_* hooks and produces bloated responses through the admin bootstrap. A dedicated REST endpoint under /wp-json/configurator/v1/price is cacheable, returns clean JSON, and runs at a fraction of the overhead — giving us genuine sub-200ms response times even on shared hosting.
From the options the customer sees to the price they pay and the order the client receives — every layer was engineered to work together as a single, coherent system.
Each configurable product stores its option groups — material, dimension, finish, accessories — as structured JSON in product meta. A custom template hook renders these as native HTML form controls, injected cleanly into the product page without overriding WooCommerce templates.
Options renderer — reads product meta schema and outputs accessible form controls:
add_action( 'woocommerce_before_add_to_cart_button', 'render_configurator_options' ); function render_configurator_options() { global $product; $schema = json_decode( get_post_meta( $product->get_id(), '_configurator_schema', true ), true ); if ( empty( $schema['option_groups'] ) ) return; foreach ( $schema['option_groups'] as $group ) { echo '<div class="cfg-group" data-group="' . esc_attr( $group['key'] ) . '">'; echo '<label>' . esc_html( $group['label'] ) . '</label>'; echo '<select name="cfg[' . esc_attr( $group['key'] ) . ']" class="cfg-select">'; foreach ( $group['options'] as $opt ) { echo '<option value="' . esc_attr( $opt['value'] ) . '">' . esc_html( $opt['label'] ) . '</option>'; } echo '</select></div>'; } }
Every option change triggers a debounced fetch() call to a registered WP REST endpoint. The endpoint receives the product ID and selected option values, runs the PHP pricing matrix lookup, and returns a clean JSON price object. The JS layer updates the displayed price — no page reload, no UI flash.
Live price updater — fires on every option change and patches the DOM price display:
// Debounce helper — prevents flooding REST endpoint on rapid changes const debounce = ( fn, ms ) => { let t; return ( ...args ) => { clearTimeout( t ); t = setTimeout( () => fn( ...args ), ms ) }; }; const updatePrice = debounce( async () => { const selections = {}; document.querySelectorAll( '.cfg-select' ).forEach( el => { selections[ el.closest( '.cfg-group' ).dataset.group ] = el.value; }); const res = await fetch( cfgData.restUrl, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': cfgData.nonce }, body: JSON.stringify( { product_id: cfgData.productId, options: selections } ) }); const { price_html, price_raw } = await res.json(); document.querySelector( '.cfg-price-display' ).innerHTML = price_html; document.querySelector( '[name="cfg_price"]' ).value = price_raw; }, 180 ); document.querySelectorAll( '.cfg-select' ).forEach( el => el.addEventListener( 'change', updatePrice ) ); updatePrice(); // Run on page load to show initial price
When the customer adds to cart, all configuration selections are captured via woocommerce_add_cart_item_data and stored as cart item meta. From there, they flow automatically into the order line items, the customer confirmation email, and the WooCommerce admin order view — without any duplicate handling logic.
A custom metabox on the product edit page lets the admin define option groups, option values, and the full pricing matrix — stored as structured JSON in post meta. Adding a new material type or changing a finish surcharge requires a single field update in wp-admin. No developer, no deployment, no downtime.
From the customer's first option change to the manufacturer's order notification — every step is handled in a clean, linear flow with no state management library, no React, and no build pipeline.
The vanilla JS layer attaches a change event listener to every .cfg-select dropdown on the product page. Each change triggers the debounced updatePrice() function, which first collects all current selections into a key-value object before sending anything to the server.
A POST request is sent to /wp-json/configurator/v1/price with the product ID and the full selections object as JSON. The request is authenticated via a localized nonce — preventing spoofed price submissions. The 180ms debounce ensures rapid option changes don't flood the endpoint.
The REST callback retrieves the product's JSON pricing matrix from post meta, extracts the base price, then iterates over each selected option to apply its surcharge modifier. The result is formatted using WooCommerce's wc_price() function and returned as a JSON object containing both the raw numeric value and the formatted HTML string.
On receiving the JSON response, the JS patches two DOM elements: the visible price display receives the formatted price_html, and a hidden input field stores the raw price_raw value that will be submitted with the add-to-cart form. The update is imperceptible — typically under 200ms from change to display.
PHP REST handler — matrix lookup and price assembly:
register_rest_route( 'configurator/v1', '/price', [ 'methods' => 'POST', 'callback' => 'configurator_calculate_price', 'permission_callback' => '__return_true', ] ); function configurator_calculate_price( $request ) { $product_id = absint( $request['product_id'] ); $options = array_map( 'sanitize_text_field', (array) $request['options'] ); $matrix = json_decode( get_post_meta( $product_id, '_configurator_schema', true ), true ); $price = (float) $matrix['base_price']; // Add surcharge for each selected option from the pricing matrix foreach ( $options as $group_key => $option_value ) { if ( isset( $matrix['pricing'][ $group_key ][ $option_value ] ) ) { $price += (float) $matrix['pricing'][ $group_key ][ $option_value ]; } } return rest_ensure_response( [ 'price_raw' => round( $price, 2 ), 'price_html' => wc_price( $price ), ] ); }
On add-to-cart, woocommerce_add_cart_item_data captures the posted selections and the calculated price. A woocommerce_before_calculate_totals hook overrides the cart item's price with the custom value. The selections then flow through woocommerce_get_item_data for cart display and woocommerce_checkout_create_order_line_item for permanent order storage — visible in emails, admin, and customer account.
Cart meta persistence — captures selections and custom price on add-to-cart:
// Attach custom selections and price to cart item data add_filter( 'woocommerce_add_cart_item_data', 'cfg_add_cart_item_data', 10, 2 ); function cfg_add_cart_item_data( $data, $product_id ) { if ( ! empty( $_POST['cfg'] ) ) { $data['cfg_options'] = array_map( 'sanitize_text_field', (array) $_POST['cfg'] ); $data['cfg_price'] = floatval( $_POST['cfg_price'] ?? 0 ); } return $data; } // Override WooCommerce price with the custom-calculated value add_action( 'woocommerce_before_calculate_totals', 'cfg_set_cart_item_price' ); function cfg_set_cart_item_price( $cart ) { foreach ( $cart->get_cart() as $item ) { if ( isset( $item['cfg_price'] ) ) { $item['data']->set_price( $item['cfg_price'] ); } } }
No build pipeline, no JavaScript framework, no licensing fees. Just clean PHP, vanilla ES6 and WooCommerce's own hooks — making this system fast, portable and trivially maintainable.
A registered REST endpoint under /wp-json/configurator/v1/price handles all price calculations — cacheable, clean JSON, no admin bootstrap overhead.
Zero framework dependency. Native fetch(), querySelectorAll() and DOM patching — delivering a sub-200ms live update experience without loading React or jQuery.
Custom selections attached via woocommerce_add_cart_item_data, price overridden via woocommerce_before_calculate_totals, displayed via woocommerce_get_item_data.
All pricing rules stored as structured JSON in product post meta — edited through a custom metabox UI. Add new options or change prices with zero code changes or deployments.
Selections stored permanently via woocommerce_checkout_create_order_line_item — visible in the cart, checkout summary, order confirmation email and admin order view.
A dynamic repeater interface lets the store admin define option groups, option labels and surcharges directly in the product edit screen — no custom admin page required.
A fully owned, plugin-free product configurator that handles real-time pricing, complete order lifecycle tracking and admin-managed pricing rules — with no recurring costs and no external dependencies.
Every option change reflects in the displayed price almost instantly — no page reload, no spinner, no delay — via a lean REST endpoint and debounced fetch calls.
The client updates material surcharges, adds new finish options and adjusts the base price entirely from wp-admin. No deployments, no code changes, no support tickets.
Every custom configuration — material, finish, dimensions, accessories — is visible in the cart, checkout confirmation, customer order email and the WooCommerce admin order panel.
Prices are calculated server-side on every add-to-cart — the client-side value is verified against the matrix before being applied. Customers cannot manipulate prices by editing the DOM.
"The challenge here was not just the pricing logic — any developer can write a conditional. The challenge was architecting it so the price feels instant to the customer, the cart is always accurate, every order tells the manufacturer exactly what to build, and the client never needs a developer to change a price again. All four had to be true simultaneously."
I build bespoke WooCommerce solutions engineered precisely to your business logic — no plugin compromises, no recurring licence costs, and complete code ownership.