Building Composite Products in WooCommerce Without a Plugin

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.

Leave Comment

Your email address will not be published. Required fields are marked *