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 StockManager(); // Prepare product data for template $products_data = array(); foreach ( $available_products as $available_product ) { $stock_info = $stock_manager->get_product_stock_info( $available_product->get_id() ); $products_data[] = array( '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 = array( '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(), 'fixed_price_html' => wc_price( $product->get_price() ), 'zero_price_html' => wc_price( 0 ), 'currency_symbol' => get_woocommerce_currency_symbol(), ); // Render template — Twig handles escaping via registered esc_html/esc_attr/esc_url functions. $plugin = Plugin::instance(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- output escaped by Twig template. echo $plugin->render_template( 'product-selector.twig', $context ); } }