一键导入
product-bundles-kits
Sell grouped products as bundles or kits with automatic inventory deduction, bundle pricing, and display logic using platform apps
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Sell grouped products as bundles or kits with automatic inventory deduction, bundle pricing, and display logic using platform apps
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Manage supplier invoices and vendor payments with automated receipt matching, payment scheduling, early discount optimization, and reconciliation workflows
Enable wholesale and B2B sales with company accounts, custom catalogs, quote workflows, purchase orders, and net payment terms
Predict future inventory needs using historical sales data, seasonal trends, and reorder points to prevent stockouts and overstock
Launch a multi-vendor marketplace with seller onboarding, commission rules, automated payouts via Stripe Connect, and vendor dashboards
Control which products appear first in collections using automated ranking rules, manual overrides, and performance-based sorting algorithms
Sync your catalog and inventory across your own site, Amazon, eBay, and wholesale channels to sell everywhere from one system
| name | product-bundles-kits |
| description | Sell grouped products as bundles or kits with automatic inventory deduction, bundle pricing, and display logic using platform apps |
| category | catalog-inventory |
| risk | safe |
| source | curated |
| date_added | 2026-03-12 |
| tags | ["bundles","kits","product-sets","dynamic-pricing","upsell","inventory","cross-sell"] |
| triggers | ["product bundle","product kit","bundle pricing","buy together","kit builder","bundle discount","frequently bought together"] |
| tools | ["claude-code","cursor","gemini-cli","copilot","codex-cli","kiro","opencode"] |
| platforms | ["shopify","woocommerce","bigcommerce","custom"] |
| difficulty | intermediate |
Product bundles let you sell multiple products together — optionally at a discount — as a single purchasable unit. This increases average order value and is one of the most effective upsell mechanisms in e-commerce. Dedicated bundle apps handle the inventory tracking, pricing, and display logic that platforms don't support natively. Only build a custom bundle system if your kit configuration requirements (dynamic assembly, real-time pricing, component substitution) exceed what apps offer.
| Platform | Recommended Tool | Why |
|---|---|---|
| Shopify | Bundler — Product Bundles or Bundle Builder | Bundler is the most popular; handles fixed bundles, mix-and-match, and inventory deduction per component |
| WooCommerce | WooCommerce Product Bundles (WooCommerce extension) | Official WooCommerce extension; supports fixed and configurable bundles, per-component pricing, and inventory |
| BigCommerce | Product Bundler app or native "Frequently Bought Together" | BigCommerce App Marketplace has several bundle apps; native "Frequently Bought Together" for simple cross-sells |
| Custom / Headless | Build bundle data model with component inventory deduction | Required when bundle logic (real-time pricing, dynamic component substitution) exceeds app capabilities |
Option A: Bundler — Product Bundles (recommended)
For "Frequently Bought Together":
Important for Shopify Plus:
WooCommerce Product Bundles (official extension):
For "Frequently Bought Together":
Bundle apps from the App Marketplace:
Native cross-sell / "Frequently Bought Together":
For headless storefronts, build a bundle model where components are stored as separate cart line items (simplifies inventory, tax, and fulfillment):
// lib/bundles.ts
interface BundleComponent { variantId: string; quantity: number; unitPrice: number; }
interface BundlePricing { componentSum: number; bundlePrice: number; savings: number; savingsPct: number; }
// Calculate bundle price dynamically from current component prices
export async function calculateBundlePrice(bundle: Bundle, selectedVariants: BundleComponent[]): Promise<BundlePricing> {
const componentSum = selectedVariants.reduce((total, c) => total + c.unitPrice * c.quantity, 0);
let bundlePrice: number;
switch (bundle.pricingType) {
case 'fixed': bundlePrice = bundle.pricingValue; break;
case 'discount_pct': bundlePrice = +(componentSum * (1 - bundle.pricingValue / 100)).toFixed(2); break;
case 'discount_abs': bundlePrice = Math.max(0, +(componentSum - bundle.pricingValue).toFixed(2)); break;
default: bundlePrice = componentSum;
}
const savings = +(componentSum - bundlePrice).toFixed(2);
return { componentSum, bundlePrice, savings, savingsPct: componentSum > 0 ? Math.round((savings / componentSum) * 100) : 0 };
}
// Check availability for all bundle components atomically
export async function checkBundleAvailability(selectedVariants: BundleComponent[]) {
const unavailable = [];
for (const { variantId, quantity } of selectedVariants) {
const level = await db.inventoryLevels.findFirst({ where: { variantId } });
const available = (level?.onHand ?? 0) - (level?.reserved ?? 0);
if (available < quantity) {
unavailable.push({ variantId, requested: quantity, available: Math.max(0, available) });
}
}
return { available: unavailable.length === 0, unavailable };
}
// Add bundle to cart as separate line items (grouped by bundle ID for UI display)
export async function addBundleToCart(cartId: string, bundleId: string, selectedVariants: BundleComponent[]) {
const bundle = await db.productBundles.findUnique({ where: { id: bundleId } });
const pricing = await calculateBundlePrice(bundle, selectedVariants);
const { available, unavailable } = await checkBundleAvailability(selectedVariants);
if (!available) throw new Error(`Bundle not available: ${unavailable.map(u => u.variantId).join(', ')}`);
// Create a bundle group record to keep line items visually associated
const bundleGroup = await db.cartBundleGroups.create({
data: { cartId, bundleId, bundlePrice: pricing.bundlePrice, bundleSavings: pricing.savings },
});
// Pro-rate the discount across components proportionally to their share of the total
const lineItems = selectedVariants.map(({ variantId, quantity, unitPrice }) => {
const itemSubtotal = unitPrice * quantity;
const discountShare = pricing.savings * (itemSubtotal / pricing.componentSum);
const discountedUnitPrice = +(unitPrice - discountShare / quantity).toFixed(4);
return { cartId, variantId, quantity, bundleGroupId: bundleGroup.id, unitPrice: discountedUnitPrice };
});
await db.cartItems.createMany({ data: lineItems });
return bundleGroup;
}
Bundle display checklist:
For Shopify/Bundler: The app generates a bundle product page automatically — customize the template in Bundler → Customize
For WooCommerce Product Bundles: The plugin renders a bundle-specific product page layout; style it using the built-in CSS settings or child theme overrides
After setting up bundles, test that inventory deducts correctly for each component:
| Problem | Solution |
|---|---|
| Bundle discount applied incorrectly at checkout | Use the app's built-in discount logic; don't layer additional discount codes on top of bundle discounts without testing the interaction |
| One bundle component goes out of stock mid-cart | Re-check availability at checkout; display which specific component is unavailable so the customer can adjust |
| Bundle pricing stale when component prices change | Recalculate bundle price on each cart refresh and at checkout, not just at add-to-cart time |
| Fulfillment system confused by bundle line items | For headless builds, ensure each line item has a standard variant_id and quantity; use bundle_group_id only for UI grouping |
| Inventory not decremented for all bundle components | After setup, always test with a real order and verify each component SKU decremented by the correct quantity |