Product Builder for WooCommerce
Visual product configurator with tile selection, conditional logic, file uploads, and smart formula pricing. The modern WooCommerce product addons alternative.
Product Builder Developer Reference
Product Builder is built around two registries (layouts and field types) and a small set of hooks. Everything below is public API — safe to use from a child theme or companion plugin.
Bootstrap
Hook into carticy_pb_init after the plugin has registered its core services. Extensions register layouts and field types here.
add_action( 'carticy_pb_init', function ( $plugin ) {
$plugin->layouts()->register( new My_Wizard_Layout() );
$plugin->field_types()->register( new My_DatePicker_Field() );
} );
Actions
carticy_pb_init— Plugin initialized. Register layouts and field types here.carticy_pb_config_saved— (int $product_id, array $config) — fired after a builder configuration is saved.carticy_pb_order_item_created— (WC_Order_Item $item, array $selections) — fired after selections are written to an order line.carticy_pb_render_group_extension_fields— (int $product_id) — render custom fields inside the option group modal. Usedata-extension-field="key"on inputs for automatic binding.
Filters
carticy_pb_option_groups— (array $groups, int $product_id) — modify option groups before display.carticy_pb_calculated_price— (float $total, array $selections, array $context) — modify the calculated total.carticy_pb_cart_item_data— (array $data, array $selections) — modify cart item data before adding.carticy_pb_sanitize_group_extension_data— (array $data, array $group, string $field_type) — sanitize extension data before save.
Custom field type
Implement FieldTypeInterface to add a new field type (date picker, range slider, dropdown, etc.). The shape of get_editor_config() drives the option group modal — including which option-table columns appear.
class My_DatePicker_Field implements \Carticy\ProductBuilder\Fields\FieldTypeInterface {
public function get_type(): string { return 'date_picker'; }
public function get_name(): string { return __( 'Date', 'my-ext' ); }
public function get_description(): string { return __( 'Customer picks a date.', 'my-ext' ); }
public function supports_multiple(): bool { return false; }
public function render( $option, array $settings, array $context ): string { /* HTML */ }
public function render_container( string $inner_html, array $group, array $settings ): string { /* HTML */ }
public function validate( $value, $option, array $context ): bool { /* … */ }
public function sanitize( $value, $option, array $context ): mixed { /* … */ }
public function get_assets(): array { return [ 'css' => [], 'js' => [] ]; }
public function get_js_data( array $options, array $settings ): array { return [ 'type' => 'date_picker' ]; }
public function get_editor_config(): array {
return [
'supports_options' => false, // group-level field, no per-option rows
'supports_images' => false,
'supports_columns' => false,
'supports_default' => false,
'supports_pricing' => true,
'option_fields' => [],
'group_settings' => [
'min_date' => [ 'type' => 'text', 'label' => 'Min date' ],
'max_date' => [ 'type' => 'text', 'label' => 'Max date' ],
],
];
}
}
Custom layout
Implement LayoutInterface for a new layout style (tabs, accordion, drawer, etc.). The default layout stacks groups; the wizard turns each group into a step.
Modal extension fields
Extensions can add arbitrary settings to the option group modal without forking the modal template. Values are stored on the group’s extension_data property — separate from the field-type-specific meta bag.
// 1. Render the field inside the modal.
add_action( 'carticy_pb_render_group_extension_fields', function ( $product_id ) {
?>
<div class="cpb-field-row">
<label>
<input type="checkbox" data-extension-field="my_feature" value="1" />
<?php esc_html_e( 'Enable my feature', 'my-ext' ); ?>
</label>
</div>
<?php
} );
// 2. Sanitize before save.
add_filter( 'carticy_pb_sanitize_group_extension_data', function ( $data, $group, $field_type ) {
$data['my_feature'] = ! empty( $data['my_feature'] );
return $data;
}, 10, 3 );
The data-extension-field attribute auto-binds the input value to group.extension_data[key] in the admin JS — no extra wiring needed.
Reading selections programmatically
foreach ( $order->get_items() as $item ) {
$selections = $item->get_meta( '_carticy_pb_selections', true );
if ( ! $selections ) { continue; }
// $selections is an array keyed by group_id. Each value is either a
// string (option_id) or { option_id, qty } for Quantity fields, or an
// array of option_ids for Multi-choice fields.
}
Configuration storage
The full per-product configuration is stored in post meta _carticy_pb_config as an array with enabled, layout, option_groups[] and settings. Use the plugin’s Repository service rather than reading the raw meta — it handles versioning and sanitization.