You've already forked wc-composable-product
Added complete inventory tracking system for composable products: - Stock validation during product selection and add-to-cart - Automatic stock deduction on order completion/processing - Automatic stock restoration on order cancellation/refund - Stock status indicators with visual feedback (In stock, Low stock, Out of stock) - Prevention of out-of-stock item selection - Low stock warnings when 5 or fewer items remain - Order notes documenting all stock changes New files: - includes/Stock_Manager.php: Core stock management logic Modified files: - includes/Cart_Handler.php: Integrated stock validation - includes/Product_Selector.php: Added stock info to product data - includes/Plugin.php: Added Stock_Manager to includes - templates/product-selector.twig: Stock status display - assets/css/frontend.css: Stock indicator styling - languages/*.pot/*.po: 8 new translatable strings Version bumped to 1.1.0 with updated CHANGELOG. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
76 lines
2.6 KiB
PHP
76 lines
2.6 KiB
PHP
<?php
|
|
/**
|
|
* Product Selector
|
|
*
|
|
* @package WC_Composable_Product
|
|
*/
|
|
|
|
namespace WC_Composable_Product;
|
|
|
|
defined('ABSPATH') || exit;
|
|
|
|
/**
|
|
* Product Selector Class
|
|
*
|
|
* Handles rendering the product selection interface
|
|
*/
|
|
class Product_Selector {
|
|
/**
|
|
* Render product selector
|
|
*
|
|
* @param Product_Type $product Composable product
|
|
*/
|
|
public static function render($product) {
|
|
if (!$product || $product->get_type() !== 'composable') {
|
|
return;
|
|
}
|
|
|
|
$available_products = $product->get_available_products();
|
|
$selection_limit = $product->get_selection_limit();
|
|
$pricing_mode = $product->get_pricing_mode();
|
|
|
|
$show_images = get_option('wc_composable_show_images', 'yes') === 'yes';
|
|
$show_prices = get_option('wc_composable_show_prices', 'yes') === 'yes';
|
|
$show_total = get_option('wc_composable_show_total', 'yes') === 'yes';
|
|
|
|
// Get stock manager for stock information
|
|
$stock_manager = new Stock_Manager();
|
|
|
|
// Prepare product data for template
|
|
$products_data = [];
|
|
foreach ($available_products as $available_product) {
|
|
$stock_info = $stock_manager->get_product_stock_info($available_product->get_id());
|
|
|
|
$products_data[] = [
|
|
'id' => $available_product->get_id(),
|
|
'name' => $available_product->get_name(),
|
|
'price' => $available_product->get_price(),
|
|
'price_html' => $available_product->get_price_html(),
|
|
'image_url' => wp_get_attachment_image_url($available_product->get_image_id(), 'thumbnail'),
|
|
'permalink' => $available_product->get_permalink(),
|
|
'stock_status' => $stock_info['stock_status'],
|
|
'in_stock' => $stock_info['in_stock'],
|
|
'stock_quantity' => $stock_info['stock_quantity'],
|
|
'managing_stock' => $stock_info['managing_stock'],
|
|
'backorders_allowed' => $stock_info['backorders_allowed'],
|
|
];
|
|
}
|
|
|
|
$context = [
|
|
'product_id' => $product->get_id(),
|
|
'products' => $products_data,
|
|
'selection_limit' => $selection_limit,
|
|
'pricing_mode' => $pricing_mode,
|
|
'show_images' => $show_images,
|
|
'show_prices' => $show_prices,
|
|
'show_total' => $show_total,
|
|
'fixed_price' => $product->get_price(),
|
|
'currency_symbol' => get_woocommerce_currency_symbol(),
|
|
];
|
|
|
|
// Render template
|
|
$plugin = Plugin::instance();
|
|
echo $plugin->render_template('product-selector.twig', $context);
|
|
}
|
|
}
|