HOMS WooCommerce Bundles
A premium WooCommerce plugin that transforms how customers configure product bundles — replacing clunky dropdowns with a modern, step-by-step visual configurator modal complete with image-based option cards, dynamic validation, and seamless cart integration.
Step-by-Step Configuration
Guide customers through multi-step bundle selections with tabbed navigation and progress tracking.
Image-Based Option Cards
Beautiful image cards replace plain dropdowns. Customers see exactly what they're selecting.
Conditional Steps
Lock or unlock steps based on prior selections — create intelligent, context-aware bundle flows.
Session Persistence
Selections survive page refreshes. Customers can leave and return without losing their choices.
Design Settings
Full visual customization — colors, radii, shadows, typography — from a live-preview settings page.
WC HPOS Compatible
Built for WooCommerce High-Performance Order Storage with full order lifecycle integration.
Requirements
Installation
Get the plugin running in under five minutes. No external services or API keys required.
Method 1 — Upload via WordPress Admin
-
01
Download the plugin ZIP
Download
wc-bundle-configurator.zipfrom your purchase receipt or account dashboard. -
02
Navigate to the Upload screen
In your WordPress admin, go to Plugins → Add New → Upload Plugin.
-
03
Upload and activate
Choose the ZIP file, click Install Now, then Activate Plugin.
-
04
Verify the menu appears
A new Bundles menu item should appear in your WP admin sidebar, just below WooCommerce.
Method 2 — Manual FTP Upload
# Unzip the plugin package
unzip wc-bundle-configurator.zip
# Upload to WordPress plugins directory
cp -r wc-bundle-configurator/ /var/www/html/wp-content/plugins/
# Set correct permissions
chown -R www-data:www-data wp-content/plugins/wc-bundle-configurator/
Then activate via Plugins → Installed Plugins in your WordPress admin.
dbDelta(). Three new tables
are added: wcbc_bundles,
wcbc_bundle_steps, and
wcbc_step_options. No manual SQL setup is needed.
Uninstalling
Deactivate and delete the plugin from Plugins → Installed Plugins. The uninstall hook automatically removes all database tables and options. This action is irreversible — export your bundle data before uninstalling if you may need it later.
Getting Started
Create your first bundle and see it live on a product page in about 10 minutes.
Creating Your First Bundle
-
01
Open the Bundles menu
Navigate to Bundles → Add New in your WordPress admin sidebar.
-
02
Select the WooCommerce product
Use the product dropdown to link this bundle to a specific WooCommerce product. Each product can have one bundle. Once set, the product cannot be changed.
-
03
Choose a pricing mode
Select Fixed Price to use the product's existing price, or Dynamic Price to calculate the total from individual option prices.
-
04
Save the bundle
Click Save Bundle. You'll be redirected to the bundle edit page where you can add steps.
Adding Steps
After saving the bundle, the Steps section becomes active.
-
01
Add a step
Click + Add Step. A new step form appears, collapsed below existing steps.
-
02
Fill in the step title
Use a descriptive name like "Select Squeez Shade" or "Choose Brush Type". This appears as the tab label in the modal.
-
03
Choose selection type
Set to Single (pick one option) or Multiple (pick many, with configurable min/max).
-
04
Save the step
Click 💾 Save Step. The Options section immediately unlocks below the step settings.
Adding Options to a Step
-
01
Click Add Option
The + Add Option button opens a new blank option row inline.
-
02
Fill in the Label
This is the text shown beneath the option card image (e.g. "Blossom", "Chestnut", "Clear"). Required field.
-
03
Set a Value (slug)
An internal identifier, auto-generated from the label if left blank. Used in cart metadata and order records.
-
04
Add an image
Click the Image button to open the WordPress Media Library. Select a product swatch, shade sample, or illustration. Shown as a card image in the frontend modal.
-
05
Save the option
Click 💾 to save. The option count badge updates. Repeat for all options in this step.
Admin Guide
A complete reference for every field, option, and control in the bundle builder.
Bundle Settings
price_delta values of all selected options.
Step Settings
Option Settings
Conditional Logic
Steps can be locked until a specific prior selection is made. This is useful for bundles where certain options only make sense after another choice.
Reordering Steps and Options
Drag the ⠿ handle on any step row to reorder. The modal will display steps in the new order. Options within a step can also be reordered by drag-and-drop. Changes are saved automatically via AJAX.
Frontend Experience
Understanding how the customer interacts with the bundle configurator on the product page.
The Bundle Panel
On any product page linked to a bundle, a Bundle Options panel appears between the product form and the Add to Cart button. It shows:
- A progress counter (e.g. "0/2 selected")
- One row per step, showing the step name and current selection ("Not selected" initially)
- A pink Select button to open the modal
The Configurator Modal
Clicking Select opens the full-screen configurator modal. The modal consists of:
Shows the current step title (e.g. "Select Squeez Shade"), a progress counter, and a Close button.
One tab per bundle step. The active tab is highlighted. Completed tabs show the selected value. Locked tabs (conditional) show a lock icon.
3-column grid of image cards. Each card shows the option's image and label. Selected cards have a coloured border.
The Done button — enabled only when all required steps are complete.
User Flow
-
1
Customer lands on product page → sees "Bundle Options" panel with "0/2 selected"
-
2
Clicks Select → modal opens to Step 1
-
3
Clicks an image card → for single-select steps, auto-advances to Step 2
-
4
Completes all steps → Done button activates
-
5
Clicks Done → modal closes, panel updates to show all selections
-
6
Clicks Add to Cart → selections validated server-side and stored in the cart item
Validation Behaviour
If a customer clicks Add to Cart before completing all selections:
- The Add to Cart button is visually disabled (opacity 0.46, pointer-events none) until all selections are made
- Clicking a blocked Add to Cart shakes the panel and highlights incomplete step rows in red
- Server-side validation runs as a second layer — even if JS is bypassed, the server blocks invalid submissions
Mobile Experience
On screens ≤520px the modal transforms into a bottom sheet that slides up from the bottom edge. A drag handle indicator appears at the top. The option grid switches to a 2-column layout. All touch targets meet the 44px minimum.
Design Settings
Control every visual aspect of the frontend configurator from a single admin page with a live preview.
Accessing Design Settings
Navigate to Bundles → Design Settings in your WordPress admin. Changes are previewed instantly in the right-hand panel. Click Save Settings to apply globally, or Reset to Defaults to restore the original appearance.
Available Settings
🎨 Colors
#c8527a
#e8a0b4
#fce4ec
#171717
#ffffff
◻ Shape & Radius
◈ Shadows
Aa Typography & Spacing
How CSS Variables Work
Settings are stored in the
wcbc_design_settings WordPress option. On every
frontend page load, they are converted to CSS custom properties
injected into <head> after the plugin
stylesheet, ensuring they always win the cascade:
<style id="wcbc-design-vars">
:root {
--wcbc-pink: #c8527a;
--wcbc-pink-done: #e8a0b4;
--wcbc-card-r: 10px;
--wcbc-modal-r: 20px;
--wcbc-font-size: 14px;
--wcbc-spacing-panel: 16px;
--wcbc-shadow-card: 0 1px 3px rgba(0,0,0,.06);
/* ...18 more tokens */
}
</style>
<style> block is output at
wp_head priority 100, which places it
after the plugin's stylesheet link (output at priority
8). This ensures saved settings always override the CSS
fallbacks.
Cart & Checkout
Bundle selections persist through the entire WooCommerce order lifecycle — cart, checkout, emails, and order management.
Cart Display
In the WooCommerce cart and mini-cart, bundle selections appear as meta rows beneath the product name:
Preventing Accidental Merging
Two cart items with the same product but different bundle configurations are never merged. The plugin computes a hash of each configuration — identical hashes increment the quantity, different hashes create separate cart rows.
Order Admin Screen
In the WooCommerce admin order view, each bundle step appears as a
human-readable meta row. The raw internal meta keys
(_wcbc_selections, _wcbc_bundle_id) are
hidden from the admin display to keep the UI clean.
wcbc_step_7
Squeez Shade
Blossom
wcbc_step_8
Big Brush Shade
Cozy Dream
_wcbc_selections
Hidden
Raw PHP array (not displayed in admin)
Order Confirmation Emails
Bundle selections automatically appear in all WooCommerce transactional emails — customer order confirmation, admin new order notification, and order completed emails. No additional configuration required.
Server-Side Validation
Before any item is added to the cart, the plugin performs a full server-side validation pass:
- Nonce verification (tamper-proof form submission)
- Min/max selection count per step
- Each submitted value must exist as an active option in the database (prevents injection of arbitrary values)
- Conditional prerequisite check (if Step 2 requires a specific Step 1 value)
Any failure produces a WooCommerce notice and blocks the add-to-cart — the item is never added with incomplete or invalid data.
Troubleshooting
Solutions to the most common issues. If your issue is not listed here, enable WP_DEBUG and check the debug log for the exact error.
Cause: The edit bundle page slug
(wcbc-bundle-edit) was not registered with
add_submenu_page(), so WordPress blocked the
request before any plugin code could run — meaning no scripts
were loaded and no nonce was issued.
Fix: Ensure you are running plugin version
1.1.0+. The fix registers wcbc-bundle-edit as a
hidden submenu page with a null parent, so
WordPress accepts the request while keeping the item invisible
in the sidebar navigation.
Most common cause: The product does not have a bundle assigned, or the bundle has no saved steps yet.
Other causes:
-
Theme compatibility: Some themes override
WooCommerce's
single-product/add-to-cart/simple.phptemplate without callingdo_action('woocommerce_before_add_to_cart_button'). The plugin has three fallback hooks — if all three are missing, you may need to add a manualdo_actioncall in your theme's product template. - Caching: If you recently assigned a bundle, clear your caching plugin (WP Rocket, LiteSpeed Cache, etc.) and reload.
-
Asset not enqueued: Open browser DevTools →
Console. If
wcbcBundle is not definedappears, the JS payload wasn't injected. This usually meansget_queried_object_id()returned 0 — check if your theme uses a non-standard product template.
// Enable debug logging
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', false );
// Then check: wp-content/debug.log
Cause: A caching plugin or CDN may be serving a cached version of the page that contains the old inline styles.
Fix:
- Clear all caching plugin caches (WP Rocket → Clear All, LiteSpeed Cache → Purge All, etc.).
- If you use a CDN (Cloudflare, BunnyCDN), purge the cache there too.
- Do a hard refresh in your browser (Ctrl+Shift+R on Windows, Cmd+Shift+R on Mac).
-
Open DevTools → Elements → search for
wcbc-design-varsin the<head>. Confirm it contains your saved values and that it appears after the<link>tofrontend.css.
Cause: Most commonly, the server is running PHP 7.x but the plugin requires PHP 8.0+.
Fix: Check your PHP version in Tools → Site Health. If it's below 8.0, contact your host to upgrade. Alternatively, the critical error may be a double-instantiation of a controller — this was fixed in v1.1.0.
To recover access, add
?action=deactivate&plugin=wc-bundle-configurator/wc-bundle-configurator.php
to the plugins page URL, or use FTP to rename the plugin
folder.
Cause: The
OrderDisplay controller was being instantiated
twice in earlier versions, causing a hook registration
conflict.
Fix: Update to v1.1.0+. The fix ensures
OrderDisplay is instantiated exactly once,
outside the is_admin() block, so it correctly
fires on both admin order screens and WooCommerce email hooks.
Developer Hooks
HOMS WooCommerce Bundles is built for extensibility. Use these WordPress actions and filters to customize or extend behaviour without modifying plugin files.
Actions
wcbc_init
Fires after the plugin is fully initialised — all services are loaded and all hooks are registered. Use this to safely extend the plugin or add your own controllers.
add_action( 'wcbc_init', function() {
// Plugin is fully loaded — safe to interact with it
error_log( 'HOMS Bundles is ready!' );
} );
wcbc_cart_item_restored
Fires when a bundle cart item is restored after the customer clicked "Remove" and then used the "Undo" link.
string $cart_item_key — the cart item hash
array $cart_item — the restored cart item
data
add_action( 'wcbc_cart_item_restored',
function( $key, $item ) {
// $item contains _wcbc_selections, _wcbc_bundle_id, etc.
error_log( 'Bundle item restored: ' . $key );
}, 10, 2
);
Utility Methods
The CartIntegration class exposes static helpers for
reading bundle data from cart and order items:
use WCBundleConfigurator\Frontend\Controllers\CartIntegration;
// Get structured selections from a WC cart item
$selections = CartIntegration::get_selections_from_cart_item( $cart_item );
// Returns: [ step_id => [ 'step_title', 'values', 'labels' ] ] or null
// Get structured selections from a WC order line item
$selections = CartIntegration::get_selections_from_order_item( $order_item );
// Get the bundle ID attached to a cart item
$bundle_id = CartIntegration::get_bundle_id_from_cart_item( $cart_item );
// Build a deterministic hash for a configuration (for duplicate detection)
$hash = CartIntegration::build_selection_hash( $bundle_id, $selections );
JavaScript Events
The frontend JS state machine dispatches custom DOM events you can listen to:
wcbc:done
Customer clicks Done with all steps complete
{ selections, labels }
wcbc:stepChange
Customer switches to a different step tab
{ stepId, stepIndex }
wcbc:selectionChange
A card is selected or deselected
{ stepId, values, labels }
// Fire when the customer completes all selections
document.addEventListener( 'wcbc:done', function( e ) {
const { selections, labels } = e.detail;
console.log( 'Bundle complete:', selections );
// selections = { [stepId]: string[] }
// labels = { [stepId]: string[] }
} );
// Track individual card selections for analytics
document.addEventListener( 'wcbc:selectionChange', function( e ) {
const { stepId, values, labels } = e.detail;
// Push to dataLayer, analytics, etc.
window.dataLayer?.push({
event: 'bundle_selection',
step_id: stepId,
selected_values: values,
});
} );
/wp-json/wcbc/v1/bundle/{post_id} (GET) for reading
bundle data and
/wp-json/wcbc/v1/bundle/{bundle_id}/validate (POST)
for validating selections. Authentication uses the standard
WordPress REST nonce via the X-WP-Nonce header.
