A “composite product” bundles multiple component products that the customer can choose individually — for example, a PC builder where the customer picks CPU, RAM, and storage from defined option lists. Without the commercial plugin, you can build this with a variable product parent, custom meta, and a custom cart item handler.
Problem: WooCommerce does not natively support selling a product as a bundle of individually selectable components — each with its own quantity and optional add-on — without a paid extension.
Solution: Build composite products using a custom product type that extends WC_Product — register component meta fields on the product edit screen, add component selection to the single-product template, validate component selections on add-to-cart, and carry component data through the cart into the order line item meta.
The examples below create a composite product using standard WooCommerce hooks: a parent product holds component definitions in meta, a custom template renders the component selectors, and a validation hook ensures all components are chosen before adding to cart.
'Choose CPU', 'product_ids' => [101, 102, 103], 'required' => true ]
function myplugin_save_composite_components( int $post_id ): void {
if ( 'product' !== get_post_type( $post_id ) ) return;
$raw = wp_unslash( $_POST['composite_components'] ?? '' );
$components = json_decode( $raw, true );
if ( is_array( $components ) ) {
update_post_meta( $post_id, '_composite_components', $components );
}
}
add_action( 'save_post', 'myplugin_save_composite_components' );
// 2. Render component selectors on the product page
add_action( 'woocommerce_before_add_to_cart_button', function() {
global $product;
$components = get_post_meta( $product->get_id(), '_composite_components', true );
if ( ! is_array( $components ) ) return;
foreach ( $components as $index => $component ) {
$required = ! empty( $component['required'] ) ? 'required' : '';
echo '';
echo '';
echo '';
}
} );
Validate and add component child items to the cart:
$component ) {
if ( ! empty( $component['required'] ) && empty( $selected[ $index ] ) ) {
wc_add_notice( sprintf( __( 'Please select %s.', 'myplugin' ), $component['label'] ), 'error' );
return false;
}
}
return $valid;
}, 10, 2 );
// 4. Add parent + all selected child products to the cart together
add_action( 'woocommerce_add_to_cart', function( string $cart_key, int $product_id ) {
$components = get_post_meta( $product_id, '_composite_components', true );
if ( ! is_array( $components ) ) return;
$selected = array_map( 'absint', (array) ( $_POST['composite_component'] ?? [] ) );
foreach ( $selected as $child_id ) {
if ( $child_id ) {
WC()->cart->add_to_cart( $child_id, 1, 0, [], [ 'composite_parent' => $cart_key ] );
}
}
}, 10, 2 );
NOTE: This implementation covers the core flow. For production use, also handle cart item removal (remove children when parent is removed via woocommerce_remove_cart_item), price summation display, and order item grouping in the woocommerce_order_item_name filter.