Overview

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

Component Minimum Version Recommended
PHP 8.0 8.2+
WordPress 6.0 6.5+
WooCommerce 7.0 8.5+
MySQL 5.7 8.0+
Setup

Installation

Get the plugin running in under five minutes. No external services or API keys required.

Method 1 — Upload via WordPress Admin

  1. 01
    Download the plugin ZIP

    Download wc-bundle-configurator.zip from your purchase receipt or account dashboard.

  2. 02
    Navigate to the Upload screen

    In your WordPress admin, go to Plugins → Add New → Upload Plugin.

  3. 03
    Upload and activate

    Choose the ZIP file, click Install Now, then Activate Plugin.

  4. 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

Shell
# 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.

Database tables are created automatically on first activation using 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.

Quickstart

Getting Started

Create your first bundle and see it live on a product page in about 10 minutes.

Creating Your First Bundle

  1. 01
    Open the Bundles menu

    Navigate to Bundles → Add New in your WordPress admin sidebar.

  2. 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.

  3. 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.

  4. 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.

  1. 01
    Add a step

    Click + Add Step. A new step form appears, collapsed below existing steps.

  2. 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.

  3. 03
    Choose selection type

    Set to Single (pick one option) or Multiple (pick many, with configurable min/max).

  4. 04
    Save the step

    Click 💾 Save Step. The Options section immediately unlocks below the step settings.

Adding Options to a Step

  1. 01
    Click Add Option

    The + Add Option button opens a new blank option row inline.

  2. 02
    Fill in the Label

    This is the text shown beneath the option card image (e.g. "Blossom", "Chestnut", "Clear"). Required field.

  3. 03
    Set a Value (slug)

    An internal identifier, auto-generated from the label if left blank. Used in cart metadata and order records.

  4. 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.

  5. 05
    Save the option

    Click 💾 to save. The option count badge updates. Repeat for all options in this step.

You're ready! Visit the linked WooCommerce product page. You'll see a Bundle Options panel with a "Select" button above the Add to Cart button. Clicking it opens the configurator modal.
Admin

Admin Guide

A complete reference for every field, option, and control in the bundle builder.

Bundle Settings

Field Type Description
WooCommerce Product Select (required) The product this bundle is attached to. Cannot be changed after creation. One bundle per product.
Pricing Mode Radio Fixed: uses the product's existing price. Dynamic: sums the price_delta values of all selected options.

Step Settings

Field Type Description
Step Title Text (required) Displayed as the tab label in the modal header and in the product page panel's step rows.
Selection Type Select Single: customer picks exactly one option. Auto-advances to next step. Multiple: customer picks a range of options.
Min / Max Number (Multiple only) Minimum and maximum number of options the customer must select. Validated both client-side and server-side on add-to-cart.

Option Settings

Field Type Description
Label Text (required) The human-readable name shown under the image card. Also used in cart/order meta display.
Value (slug) Text Internal identifier stored in cart/order data. Auto-generated from the label if left blank. Must be unique within the step.
Image Media picker The product swatch or image displayed on the option card. Opens the WordPress Media Library. Recommended: square images at 200×200px or larger.
Price Δ Number Price adjustment applied in Dynamic pricing mode. Can be positive (surcharge) or negative (discount). Ignored in Fixed pricing mode.

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.

Example: Conditional Step Flow
Step 1: Choose Base
Squeez Big Brush
→ If "Big Brush" selected
Step 2: Choose Brush Size
Small Medium Large

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

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:

User Flow

  1. 1
    Customer lands on product page → sees "Bundle Options" panel with "0/2 selected"
  2. 2
    Clicks Select → modal opens to Step 1
  3. 3
    Clicks an image card → for single-select steps, auto-advances to Step 2
  4. 4
    Completes all steps → Done button activates
  5. 5
    Clicks Done → modal closes, panel updates to show all selections
  6. 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.

Customization

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

Primary Color Select button, modal title, step names, and active elements. Default: #c8527a
Secondary Color Done button and softer accent elements. Default: #e8a0b4
Accent Color Active tab fills and hover backgrounds. Default: #fce4ec
Text Color Primary body text inside the modal. Default: #171717
Button Text Color Text colour on primary-coloured buttons. Default: #ffffff

◻ Shape & Radius

Card Border Radius Roundness of option cards. Range: 0–24px. Default: 10px
Modal Border Radius Roundness of the configurator modal. Range: 0–32px. Default: 20px

◈ Shadows

Card Shadows Toggle drop shadows on option cards. Default: On
Shadow Intensity Light / Medium / Heavy. Default: Medium

Aa Typography & Spacing

Base Font Size Root font size inside the modal. Range: 11–18px. Default: 14px
Spacing Mode Compact / Normal / Large — controls padding and gaps throughout the UI. Default: Normal

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:

HTML — Injected in <head>
<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>
Cascade order matters. The dynamic <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.
Commerce

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:

🧴
Squeez + Big Brush Bundle
Squeez Shade Blossom
Big Brush Shade Cozy Dream
449 EGP

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.

Meta Key (internal) Visible As Content
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.

Support

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.

! "Sorry, you are not allowed to access this page" when saving a step

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.

! Bundle Options panel not showing on the product page

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.php template without calling do_action('woocommerce_before_add_to_cart_button'). The plugin has three fallback hooks — if all three are missing, you may need to add a manual do_action call 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 defined appears, the JS payload wasn't injected. This usually means get_queried_object_id() returned 0 — check if your theme uses a non-standard product template.
Debug — Add to wp-config.php
// Enable debug logging
define( 'WP_DEBUG',         true  );
define( 'WP_DEBUG_LOG',     true  );
define( 'WP_DEBUG_DISPLAY', false );

// Then check: wp-content/debug.log
? Design settings saved but changes not appearing on the frontend

Cause: A caching plugin or CDN may be serving a cached version of the page that contains the old inline styles.

Fix:

  1. Clear all caching plugin caches (WP Rocket → Clear All, LiteSpeed Cache → Purge All, etc.).
  2. If you use a CDN (Cloudflare, BunnyCDN), purge the cache there too.
  3. Do a hard refresh in your browser (Ctrl+Shift+R on Windows, Cmd+Shift+R on Mac).
  4. Open DevTools → Elements → search for wcbc-design-vars in the <head>. Confirm it contains your saved values and that it appears after the <link> to frontend.css.
? Critical error on website after plugin activation

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.

i Selections not appearing in order emails or My Account

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

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

action 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.

PHP
add_action( 'wcbc_init', function() {
    // Plugin is fully loaded — safe to interact with it
    error_log( 'HOMS Bundles is ready!' );
} );
action 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
PHP
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:

PHP — CartIntegration static helpers
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:

Event Fires when event.detail
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 }
JavaScript — Listening to events
// 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,
    });
} );
REST API endpoints are available at /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.