You've already forked wc-composable-product
84 lines
3.3 KiB
PHP
84 lines
3.3 KiB
PHP
|
|
<?php
|
||
|
|
/**
|
||
|
|
* Custom single product template for composable products.
|
||
|
|
*
|
||
|
|
* Replaces the standard WooCommerce two-column layout (image + summary) with
|
||
|
|
* a compact header and full-width product selector.
|
||
|
|
*
|
||
|
|
* This is a thin PHP loader that captures WooCommerce hook output and passes
|
||
|
|
* it to the Twig template for rendering.
|
||
|
|
*
|
||
|
|
* @package Magdev\WcComposableProduct
|
||
|
|
*/
|
||
|
|
|
||
|
|
defined( 'ABSPATH' ) || exit;
|
||
|
|
|
||
|
|
global $product;
|
||
|
|
|
||
|
|
if ( ! $product || ! is_a( $product, 'WC_Product' ) ) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- WooCommerce hook.
|
||
|
|
do_action( 'woocommerce_before_single_product' );
|
||
|
|
|
||
|
|
if ( post_password_required() ) {
|
||
|
|
echo get_the_password_form(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- WP core function.
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Temporarily remove standard WooCommerce summary hooks — we render title,
|
||
|
|
// price, and description in the compact header instead. Our product selector
|
||
|
|
// (CartHandler::render_product_selector at priority 25) stays attached.
|
||
|
|
$hooks_to_remove = array(
|
||
|
|
array( 'woocommerce_template_single_title', 5 ),
|
||
|
|
array( 'woocommerce_template_single_rating', 10 ),
|
||
|
|
array( 'woocommerce_template_single_price', 10 ),
|
||
|
|
array( 'woocommerce_template_single_excerpt', 20 ),
|
||
|
|
array( 'woocommerce_template_single_add_to_cart', 30 ),
|
||
|
|
array( 'woocommerce_template_single_meta', 40 ),
|
||
|
|
array( 'woocommerce_template_single_sharing', 50 ),
|
||
|
|
);
|
||
|
|
|
||
|
|
foreach ( $hooks_to_remove as $hook ) {
|
||
|
|
remove_action( 'woocommerce_single_product_summary', $hook[0], $hook[1] );
|
||
|
|
}
|
||
|
|
|
||
|
|
// Capture product selector output (our hook at priority 25 + structured data at 60).
|
||
|
|
ob_start();
|
||
|
|
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- WooCommerce hook.
|
||
|
|
do_action( 'woocommerce_single_product_summary' );
|
||
|
|
$selector_html = ob_get_clean();
|
||
|
|
|
||
|
|
// Restore removed hooks.
|
||
|
|
foreach ( $hooks_to_remove as $hook ) {
|
||
|
|
add_action( 'woocommerce_single_product_summary', $hook[0], $hook[1] );
|
||
|
|
}
|
||
|
|
|
||
|
|
// Capture after-summary output (product tabs, related products, etc.).
|
||
|
|
ob_start();
|
||
|
|
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- WooCommerce hook.
|
||
|
|
do_action( 'woocommerce_after_single_product_summary' );
|
||
|
|
$after_summary_html = ob_get_clean();
|
||
|
|
|
||
|
|
// Build template context.
|
||
|
|
$image_id = $product->get_image_id();
|
||
|
|
$context = array(
|
||
|
|
'product_id' => $product->get_id(),
|
||
|
|
'product_name' => $product->get_name(),
|
||
|
|
'price_html' => $product->get_price_html(),
|
||
|
|
'short_description' => $product->get_short_description(),
|
||
|
|
'image_html' => $image_id ? wp_get_attachment_image( $image_id, array( 100, 100 ), false, array( 'class' => 'composable-header-image' ) ) : '',
|
||
|
|
'permalink' => get_permalink( $product->get_id() ),
|
||
|
|
'product_class' => implode( ' ', wc_get_product_class( 'composable-product-layout', $product ) ),
|
||
|
|
'selector_html' => $selector_html,
|
||
|
|
'after_summary_html' => $after_summary_html,
|
||
|
|
);
|
||
|
|
|
||
|
|
$plugin = \Magdev\WcComposableProduct\Plugin::instance();
|
||
|
|
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- output escaped by Twig template.
|
||
|
|
echo $plugin->render_template( 'single-product-composable.html.twig', $context );
|
||
|
|
|
||
|
|
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- WooCommerce hook.
|
||
|
|
do_action( 'woocommerce_after_single_product' );
|