The public PHP API, REST fields, Store API data, CSV columns, WP-CLI commands, hooks and template overrides of Sales Igniter Bundles & Composites.
Words you need #
- A bundle is a product of type
si_bundle, labelled “Bundle”. - A bundle has items. An item is a fixed product (
kind=product) or a choice (kind=choice). - A configuration is what a customer picked.
- The bundle line in a cart or order is the container. Its item lines are its children.
Public PHP API: Sibundles\Api #
A static class. Method names are camelCase. Signatures are stable. New methods may be added; existing ones keep their signatures.
A configuration can be given in either of two shapes:
- Rows, as the Store API and REST take them: “
[ { item, product_id, quantity, selected, variation_id, attributes } ]`attributesis{ “attribute_size”: “Large” }or[ { name, option } ].product_id` is the option picked for a choice. Items you leave out take their defaults. - The stored shape, as order lines carry it: “
{ item id: { product_id, qty, selected, variation_id, attributes } }“
Hidden items always keep their defaults. Every method checks the bundle as it is now.
Bundles and configurations #
Api::isBundle( $product ): bool
True when the product (or product id) is a bundle.
Api::configuration( $bundle, array $config = array() ): array|null
A configuration in its stored shape, with defaults filled in. Null when $bundle is not a bundle. $bundle is a product or an id.
Api::validate( $bundle, array $config = array(), $qty = 1, $stock = true ): string[]
Checks a configuration and returns the problems, in customer words. An empty array means it is fine. $stock = false skips the stock check. Filter: sibundles_configuration_errors.
Api::rules( $bundle ): array[]
A bundle’s rules (see “Rules” below). Empty when none.
Cart #
Api::addToCart( $bundle, $qty = 1, array $config = array(), array $cart_item_data = array() ): string|false
Adds a bundle with its items. Returns the bundle line’s cart key, or false with the usual error notices when refused. $cart_item_data is kept on the bundle line.
Api::isChildCartItem( array $cart_item ): bool // an item line of a bundle
Api::isContainerCartItem( array $cart_item ): bool // a bundle line
Api::containerCartItem( array $cart_item ): array|null // the bundle line of an item line
Orders #
Api::addToOrder( $order, $bundle, $qty = 1, array $config = array() ): int|WP_Error
Adds a bundle line and its item lines to an order. Stock is not checked. Items that cannot be resolved are named in an order note. Totals are recalculated. Returns the bundle line’s id.
Api::configureOrderItem( $item, array $config = array(), $qty = null ): true|WP_Error
Reconfigures the bundle line $item (a WC_Order_Item_Product at the top of its bundle). $qty null keeps the quantity. Returns WP_Error if the configuration breaks the bundle’s rules.
Api::isChildOrderItem( $item ): bool
Api::isContainerOrderItem( $item ): bool
Api::orderLineDialect( $item ): string // 'sib' | 'pb' | 'cp' | ''
Api::orderContainer( $item, $order = null ): WC_Order_Item_Product|null
Api::orderChildren( $item, $order = null ): WC_Order_Item_Product[] // line id => line
Api::orderItemInfo( $item, $order = null ): array|null
Api::orderConfiguration( $item ): array
These read an order line whatever plugin wrote it: this plugin (sib), or an order placed before an import from another bundle plugin (pb for bundles, cp for composites). Old lines are never rewritten. Always read them through these methods, not through their meta.
orderItemInfo() returns: dialect, role (container or child), nested (a child that is also a bundle line), ours, bundle_id, product_id, variation_id, item_id, group_mode (grouped, flat, items_only). For a child it adds priced_individually, discount (percent at order time), title (the staff name), hidden, price_hidden.
orderConfiguration() returns item id => [ qty, selected, variation_id, attributes, title ]. Feed it to configuration() to check it against the bundle as it is now.
Items of a line #
Api::partItem( $line ): array|null // the item behind an item line, as an array
Api::isChoice( $line ): bool // the line comes from a choice
Api::partOptions( $line, $limit = 50 ): array[] // other options of its choice: { product_id, name, type, variable }
$line is an order line or a cart line. Used by “Swap item” suggestions.
Cart and order meta #
Cart line data: sib_parent (container key), sib_children, sib_item (item id), sib_bundle (bundle id), sib_config.
Bundle (container) order line meta: _sib_key, _sib_children, _sib_config, _sib_group_mode, _sib_weight, _sib_needs_processing.
Item (child) order line meta: _sib_key, _sib_parent (the container’s key), _sib_item, _sib_bundle, _sib_hidden, _sib_price_hidden, _sib_own_price (yes or no), _sib_discount, _sib_ships_alone, _sib_title, and a visible “Part of” row for shown items.
These are for reading. Use the API to write.
REST API #
Products (v3) #
Bundles are created with "type": "si_bundle". A bundle’s product object has a bundle field, read and write:
"bundle": {
"settings": { "layout": "default", "group_mode": "default", "shipping": "separately", "min_size": "", "max_size": "", "...": "..." },
"items": [ { "id": 12, "kind": "product", "product_id": 345, "quantity_min": 1, "quantity_default": 1, "quantity_max": 1, "priced_individually": false, "discount": "", "visible_product": true, "...": "..." } ],
"rules": [],
"stock_status": "instock",
"stock_quantity": 4,
"price_range": { "min": "...", "max": "..." }
}
settings: the keys arelayout,form_location,group_mode,min_size,max_size,shipping,weight,sold_individually,edit_in_cart,catalog_price,qty_tiers,qty_tiers_base. Writing merges.items: writing replaces the list. An entry with theidof one of the bundle’s items keeps it (settings merged). An entry without an id is new. Items left out are removed. A new item may carry aref(write only) thatrulescan use before it has an id.- Fixed item:
kind=product,product_id. - Choice:
kind=choice,sources={ product, product_cat, product_tag, exclude }(lists of ids), plus choice settings:default_pick,options_style,per_page,pagination,sort,filters,filter_attributes,select_action,details_*,option_price_display,image_id. - Item settings:
quantity_min,quantity_default,quantity_max,optional,optional_checked,allowed_variations,default_attributes,priced_individually,discount,discount_base,shipped_individually,visible_product,visible_cart,visible_order,price_visible_product,price_visible_cart,price_visible_order,title,description,hide_thumbnail.
- Fixed item:
rules: writing replaces them.stock_status,stock_quantity,price_range: read only.
Errors: 400 sibundles_rest_invalid_item (an item is not valid, for example a grouped, external or bundle product), 400 sibundles_rest_not_a_bundle (bundle data on another type), 400 sibundles_rest_invalid_bundle, 400 sibundles_rest_invalid_rules.
Orders (v3) #
Each line item gets:
bundle_parent: id of the bundle line this line is an item of, or null;bundle_children: ids of a bundle line’s item lines;bundle_config: the bundle line’s configuration.
Posting a bundle line, with or without bundle_config (rows or the stored shape), builds its item lines on the server. Stock is not checked, and it is reduced when a paid order reduces stock. Posting bundle_config on an existing bundle line reconfigures it. Errors: 400 sibundles_rest_invalid_config, sibundles_rest_not_a_bundle, sibundles_rest_not_a_bundle_line.
A bundle line’s quantity change scales its totals and its item lines follow. Item lines whose quantity the same request sets keep that quantity. The internal v4 order routes are not handled yet.
Read aliases for the previous bundle plugins #
For stores that moved from another bundle plugin, read-only copies of the old field names are served so that integrations keep working.
- Products:
bundled_by; on bundlesbundle_stock_status,bundle_stock_quantity,bundle_virtual,bundle_layout,bundle_add_to_cart_form_location,bundle_editable_in_cart,bundle_sold_individually_context,bundle_item_grouping,bundle_min_size,bundle_max_size,bundle_price,bundled_items, andcomposite_virtual,composite_layout,composite_add_to_cart_form_location,composite_editable_in_cart,composite_sold_individually_context,composite_shop_price_calc,composite_components,composite_scenarios. - Order lines:
bundled_by,bundled_items,bundled_item_title,composite_parent,composite_children.
They are read only, and only keys that are missing are added. New integrations should use bundle. Setting: WooCommerce > Bundles > Settings > Previous REST field names: Automatic (on once bundles were imported), On, Off. Imported items keep their old ids in these fields.
Store API #
- Cart items carry
extensions.sibundles.- Bundle line:
{ role: "container", mode, children, editable, saveable }. - Item line:
{ role: "child", mode, parent, item, removable, price_hidden, last, choice, depth, saveable }.
- Bundle line:
- Products carry
extensions.sibundleswithitems(the shown ones only),layout,group_mode,min_size,max_size,edit_in_cart,needs_configuration,stock_quantity,rules,rule_parents. Hidden items are never listed. - Add to cart:
POST /wc/store/v1/cart/add-itemaccepts asibundlesparameter: a list of rows{ item, quantity, selected, variation_id, attributes }. An invalid one answers 400sibundles_add_to_cart. - Cart responses leave out hidden items and, in “items only” mode, the bundle line. A grouped bundle line carries the price and totals of the whole bundle. Item quantities are read-only.
Plugin routes #
GET /wp-json/sibundles/v1/options #
Public. The options of a choice, for the product page. Parameters:
| Parameter | |
|---|---|
bundle | Bundle id (required) |
item | The choice’s item id (required) |
mode | page (default), all (1,000 a page, with more when there are more) or details |
page | Page number |
search | Only options whose name or SKU holds this text |
orderby | default, popularity, rating, date, price, price-desc, title |
filters | JSON: taxonomy => slugs |
picks | JSON: the picks so far, so rules apply |
pick | With details: the option to describe |
404 sibundles_not_found for a missing bundle, a draft, a fixed or hidden item.
GET /wp-json/sibundles/v1/reports #
Needs view_woocommerce_reports. Feeds Analytics > Bundles.
| Parameter | |
|---|---|
view | bundles (default), items or stock |
after, before | Dates (YYYY-MM-DD, store time) |
compare_after, compare_before | A period to compare with. Its totals come back as previous. |
orderby, order | Sort |
page, per_page | Paging (per_page up to 100) |
Sales come from the lookup table, with refunds already taken off, for the order statuses the Analytics settings count.
Abilities API #
sibundles/query-bundles, in the category sibundles (“Bundles”). Read only. Needs edit_products. Registered where the Abilities API exists (WordPress 6.9 and later).
Input (all optional): id, contains_product_id, search, sku, status (any, publish, private, draft, pending, future), stock_status (instock, outofstock, onbackorder), page, per_page (up to 100).
Output: each bundle’s settings, items (with product name and SKU), rules, stock and price range.
Product CSV #
Three columns on products:
| Column | Key | Content |
|---|---|---|
| Bundle items | sibundles_items | JSON list of items in order |
| Bundle settings | sibundles_settings | JSON of the settings that differ from the defaults |
| Bundle rules | sibundles_rules | JSON of the rules |
Items name their product by SKU, or id:<id> when it has none. A product further down the file, or not imported yet, is filled in when its row comes. A choice is written with kind = choice and sources = { products, categories, tags, exclude }: products by SKU or id:<id>, categories and tags by slug. Every item carries a ref (i1, i2, …) that the rules use. id keeps an item when the same store imports over its own bundles. Only settings that differ from the defaults are written.
While the previous bundle plugins are switched off, their CSV columns are read on import too.
WP-CLI #
wp sibundles sync [--all] [--product=<id>]
Recompute prices, stock and guard rails. --product takes a bundle id, or an item product id (then every bundle that uses it).
wp sibundles migrate --detect
wp sibundles migrate --dry-run (--all | --product=<ids>) [--source=<pb|cp>] [--format=<table|csv|json>]
wp sibundles migrate (--all | --product=<ids>) [--source=<pb|cp>] [--reimport] [--no-backfill]
wp sibundles migrate --backfill
wp sibundles rollback (--all | --product=<ids>) [--source=<pb|cp>] [--delete-rows]
pb is bundles of the Product Bundles plugin, cp is composites of the Composite Products plugin. See the two switching guides. Run WP-CLI with a memory cap, for example ulimit -v 3000000; wp sibundles sync --all.
Hooks #
Filters #
| Hook | Arguments | Use |
|---|---|---|
sibundles_form_data | $data, $bundle | Change the data the product page form’s script receives |
sibundles_editor_price_line | $line, $bundle | The price line under the bundle settings in the editor (HTML, ” for none). The rental bridge puts a rental bundle’s rates there |
sibundles_show_prices | $show, $bundle | Return false to hide every price of a bundle’s form from this visitor: item and option prices, the total, “You save”, quantity discounts, the rental total (Request a Quote uses it for hidden prices) |
sibundles_share_link | $show, $bundle | Show or hide “Copy link to these picks” |
sibundles_configuration_errors | $errors, $bundle, $config, $bundle_qty | Add or change problems found in a configuration |
sibundles_cart_check_errors | $errors, $bundle, $config, $qty | Add problems at add to cart |
sibundles_option_types | $types | Product types that may be options of a choice (default simple, variable, subscription, variable-subscription, si_bundle) |
sibundles_choice_options | $ids, $item | Change the option ids of a choice |
sibundles_nestable_bundle | $ok, $bundle | Whether a bundle may be an option |
sibundles_item_unit_price | $unit, $item, $source, $context | Change an item’s unit price |
sibundles_price_range | $out, $bundle, $inputs | Change the computed shop price range |
sibundles_catalog_range | $range, $product | Supply the catalog range yourself (return an array to override) |
sibundles_display_range | $out, $product | Change the range shown |
sibundles_attention | $out, $bundle | Add or change guard-rail notes |
sibundles_order_item_priced_individually | $yes, $bundle_item, $bundle, $item | Whether an order item line counts as charged on its own |
sibundles_order_dialects | $list | Register another order line reader |
sibundles_pb_plugin_active | $bool | Tell this plugin if the previous bundle plugin should draw its own lines |
sibundles_cp_plugin_active | $bool | The same for composites |
sibundles_import_scan_paths | $paths | Folders the dry run scans for template overrides and code |
sibundles_admin_tabs | $tabs | Add a tab to WooCommerce > Bundles |
sibundles_new_item_defaults | $settings, $product | Settings of a product item when it is added in the editor |
sibundles_new_choice_defaults | $settings | Settings of a new choice |
sibundles_item_card_data | $data, $item, $product | Add data attributes to an item card |
sibundles_load_rental_bridge | $load | Turn the rental bridge off |
Actions #
| Hook | Arguments | When |
|---|---|---|
sibundles_loaded | The plugin finished booting | |
sibundles_before_items | $product | In the product page form, before the items |
sibundles_items_saved | $bundle_id, $items, $removed_ids | A bundle’s items were saved |
sibundles_bundle_synced | $bundle | A bundle’s price and stock were re-counted |
sibundles_order_items_followed | $order_id | Item lines followed a bundle line’s new quantity |
sibundles_items_panel_settings | $bundle | Inside the Bundle items tab, to print extra settings |
sibundles_admin_tab_{slug} | Render a tab added with sibundles_admin_tabs | |
sibundles_rental_bridge_loaded | The rental bridge booted | |
sibundles_initialize_failed | $error, $class_name | A component failed to start |
JavaScript #
The product form dispatches sibundles:update on the form element after every change of picks. event.detail is the form object. The rental calendar listens to it.
Templates #
Copy a file from wp-content/plugins/sibundles/templates/ to your-theme/sibundles/ and edit it. Keep the same path below sibundles/.
| Template | Draws |
|---|---|
single-product/add-to-cart/si-bundle.php | The whole form |
single-product/bundle/item.php | A fixed item |
single-product/bundle/choice.php | A choice |
single-product/bundle/options.php | The option list of a choice |
single-product/bundle/choice-details.php | The picked option’s details |
single-product/bundle/summary.php | The summary |
Templates are versioned by the plugin; check them after an update. The scripts and styles are sibundles-form (with readable files when SCRIPT_DEBUG is on).
Compatibility notes #
- HPOS and the Cart and Checkout blocks are supported and declared.
- PHP 7.4 to 8.4.
- The plugin sends no telemetry and never locks the editor.
