You've already forked wc-bootstrap
Add WooCommerce-to-Twig rendering bridge
Intercept WooCommerce's PHP template loading via
woocommerce_before_template_part / woocommerce_after_template_part hooks
to render Bootstrap 5 Twig templates instead. This makes all 99 child
theme templates functional in a standard WooCommerce environment.
- Create WooCommerceExtension (Twig AbstractExtension) with ~50 functions
and 7 filters covering WC API, WordPress hooks, escaping, and forms
- Rewrite TemplateOverride to use hook-based interception with stack-based
output buffering for nested template support
- Wire bridge initialization at init priority 20 in functions.php
- Fix invalid {% do return() %} in two order templates
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -43,16 +43,42 @@ function wc_bootstrap_setup(): void {
|
||||
add_action( 'after_setup_theme', 'wc_bootstrap_setup' );
|
||||
|
||||
/**
|
||||
* Register plugin template overrides.
|
||||
* Initialize the WooCommerce-to-Twig template bridge.
|
||||
*
|
||||
* Prepends the child theme's templates/ directory to the plugin's Twig loader,
|
||||
* so child theme templates take priority over plugin templates.
|
||||
* Registers the WooCommerce Twig extension with the parent theme's TwigService
|
||||
* and sets up template interception hooks so the child theme's Twig templates
|
||||
* are rendered instead of WooCommerce's PHP templates.
|
||||
*
|
||||
* Runs at 'init' priority 20 to ensure WooCommerce is fully loaded (it
|
||||
* initializes at 'init' priority 0).
|
||||
*/
|
||||
function wc_bootstrap_register_template_override(): void {
|
||||
function wc_bootstrap_init_twig_bridge(): void {
|
||||
// Guard: require parent TwigService and WooCommerce.
|
||||
if ( ! class_exists( '\WPBootstrap\Twig\TwigService' ) || ! function_exists( 'WC' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$twig = \WPBootstrap\Twig\TwigService::getInstance();
|
||||
$env = $twig->getEnvironment();
|
||||
|
||||
// Add child theme templates directory to the Twig loader so {% include %}
|
||||
// directives in Twig templates can find other child theme templates.
|
||||
$loader = $env->getLoader();
|
||||
if ( $loader instanceof \Twig\Loader\FilesystemLoader ) {
|
||||
$template_dir = WC_BOOTSTRAP_PATH . 'templates';
|
||||
if ( is_dir( $template_dir ) ) {
|
||||
$loader->prependPath( $template_dir );
|
||||
}
|
||||
}
|
||||
|
||||
// Register WooCommerce functions and filters as Twig extensions.
|
||||
$env->addExtension( new \WcBootstrap\Twig\WooCommerceExtension() );
|
||||
|
||||
// Register template interception hooks.
|
||||
$override = new \WcBootstrap\TemplateOverride();
|
||||
$override->register();
|
||||
}
|
||||
add_action( 'after_setup_theme', 'wc_bootstrap_register_template_override' );
|
||||
add_action( 'init', 'wc_bootstrap_init_twig_bridge', 20 );
|
||||
|
||||
/**
|
||||
* Enqueue child theme styles.
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
<?php
|
||||
/**
|
||||
* Template Override
|
||||
* Template Override.
|
||||
*
|
||||
* Hooks into the plugin's Twig FilesystemLoader to prepend
|
||||
* the child theme's templates/ directory, allowing template overrides.
|
||||
* Intercepts WooCommerce's PHP template rendering and replaces it
|
||||
* with Twig template output from the child theme's templates/ directory.
|
||||
*
|
||||
* Uses woocommerce_before_template_part / woocommerce_after_template_part
|
||||
* hooks to render the Twig version and discard the PHP include output.
|
||||
*
|
||||
* @package WcBootstrap
|
||||
* @since 0.1.0
|
||||
@@ -11,9 +14,7 @@
|
||||
|
||||
namespace WcBootstrap;
|
||||
|
||||
// IMPORTANT: Update these imports to match your plugin's actual class names.
|
||||
use Magdev\Woocommerce\Frontend\Template;
|
||||
use Twig\Loader\FilesystemLoader;
|
||||
use WPBootstrap\Twig\TwigService;
|
||||
|
||||
class TemplateOverride {
|
||||
|
||||
@@ -22,55 +23,114 @@ class TemplateOverride {
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private string $template_path;
|
||||
private string $templatePath;
|
||||
|
||||
/**
|
||||
* Stack of template names with active output buffers.
|
||||
*
|
||||
* Handles nested template calls where one WC template triggers
|
||||
* another via wc_get_template() from within action hooks.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
private array $bufferStack = [];
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->template_path = WC_BOOTSTRAP_PATH . 'templates';
|
||||
$this->templatePath = WC_BOOTSTRAP_PATH . 'templates/';
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the template override with WordPress hooks.
|
||||
* Register the template override hooks.
|
||||
*
|
||||
* Must be called after the plugin's Template singleton is initialized
|
||||
* (plugin inits at 'init' priority 0).
|
||||
* Only registers if the parent theme's TwigService is available.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register(): void {
|
||||
add_action( 'init', [ $this, 'override_template_paths' ], 20 );
|
||||
if ( ! class_exists( TwigService::class ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
add_action( 'woocommerce_before_template_part', [ $this, 'beforeTemplatePart' ], 10, 4 );
|
||||
add_action( 'woocommerce_after_template_part', [ $this, 'afterTemplatePart' ], 10, 4 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepend the child theme's templates directory to the Twig loader.
|
||||
* Before WooCommerce includes a PHP template.
|
||||
*
|
||||
* This makes Twig look in the child theme's templates/ first,
|
||||
* falling back to the plugin's templates/ if not found.
|
||||
* If a matching Twig template exists, renders it and starts output
|
||||
* buffering to capture (and later discard) the PHP template output.
|
||||
*
|
||||
* @param string $templateName Template name (e.g., 'cart/cart.php').
|
||||
* @param string $templatePath Template path override.
|
||||
* @param string $located Full path to the located PHP template.
|
||||
* @param array $args Template context variables.
|
||||
* @return void
|
||||
*/
|
||||
public function override_template_paths(): void {
|
||||
if ( ! class_exists( Template::class ) ) {
|
||||
return;
|
||||
}
|
||||
public function beforeTemplatePart( string $templateName, string $templatePath, string $located, array $args ): void {
|
||||
$twigTemplate = $this->resolveTwigTemplate( $templateName );
|
||||
|
||||
if ( ! is_dir( $this->template_path ) ) {
|
||||
return;
|
||||
if ( null === $twigTemplate ) {
|
||||
return; // No Twig override — let PHP render normally.
|
||||
}
|
||||
|
||||
try {
|
||||
$twig = Template::get_instance()->get_twig();
|
||||
$loader = $twig->getLoader();
|
||||
$twig = TwigService::getInstance();
|
||||
echo $twig->render( $twigTemplate, $args );
|
||||
|
||||
if ( $loader instanceof FilesystemLoader ) {
|
||||
$loader->prependPath( $this->template_path );
|
||||
}
|
||||
} catch ( \Exception $e ) {
|
||||
// Buffer the upcoming PHP include so we can discard it.
|
||||
ob_start();
|
||||
$this->bufferStack[] = $templateName;
|
||||
} catch ( \Throwable $e ) {
|
||||
// Twig render failed — let PHP render as fallback.
|
||||
if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
|
||||
error_log( 'WooCommerce Bootstrap: Failed to register template override - ' . $e->getMessage() );
|
||||
error_log( sprintf(
|
||||
'WC Bootstrap: Twig render failed for %s — %s',
|
||||
$templateName,
|
||||
$e->getMessage()
|
||||
) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* After WooCommerce includes a PHP template.
|
||||
*
|
||||
* If we started buffering for this template, discards the PHP output.
|
||||
*
|
||||
* @param string $templateName Template name.
|
||||
* @param string $templatePath Template path override.
|
||||
* @param string $located Full path to the located PHP template.
|
||||
* @param array $args Template context variables.
|
||||
* @return void
|
||||
*/
|
||||
public function afterTemplatePart( string $templateName, string $templatePath, string $located, array $args ): void {
|
||||
if ( ! empty( $this->bufferStack ) && end( $this->bufferStack ) === $templateName ) {
|
||||
ob_end_clean(); // Discard PHP template output.
|
||||
array_pop( $this->bufferStack );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a WooCommerce template name to a Twig template path.
|
||||
*
|
||||
* Maps 'cart/cart.php' to 'cart/cart.html.twig' and checks that
|
||||
* the file exists in the child theme's templates/ directory.
|
||||
*
|
||||
* @param string $templateName WooCommerce template name.
|
||||
* @return string|null Twig template path relative to templates/, or null if not found.
|
||||
*/
|
||||
private function resolveTwigTemplate( string $templateName ): ?string {
|
||||
$twigName = preg_replace( '/\.php$/', '.html.twig', $templateName );
|
||||
$fullPath = $this->templatePath . $twigName;
|
||||
|
||||
if ( file_exists( $fullPath ) ) {
|
||||
return $twigName;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
320
inc/Twig/WooCommerceExtension.php
Normal file
320
inc/Twig/WooCommerceExtension.php
Normal file
@@ -0,0 +1,320 @@
|
||||
<?php
|
||||
/**
|
||||
* WooCommerce Twig Extension.
|
||||
*
|
||||
* Registers all WooCommerce and WordPress functions/filters needed
|
||||
* by the child theme's Twig templates.
|
||||
*
|
||||
* @package WcBootstrap
|
||||
* @since 0.1.0
|
||||
*/
|
||||
|
||||
namespace WcBootstrap\Twig;
|
||||
|
||||
use Twig\Extension\AbstractExtension;
|
||||
use Twig\TwigFunction;
|
||||
use Twig\TwigFilter;
|
||||
|
||||
class WooCommerceExtension extends AbstractExtension {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFunctions(): array {
|
||||
return array_merge(
|
||||
$this->getWordPressFunctions(),
|
||||
$this->getWooCommerceFunctions()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFilters(): array {
|
||||
return [
|
||||
// Escaping filters (parent registers as functions only, templates use as |filter).
|
||||
new TwigFilter( 'esc_html', 'esc_html', [ 'is_safe' => [ 'html' ] ] ),
|
||||
new TwigFilter( 'esc_attr', 'esc_attr', [ 'is_safe' => [ 'html' ] ] ),
|
||||
new TwigFilter( 'esc_url', 'esc_url', [ 'is_safe' => [ 'html' ] ] ),
|
||||
|
||||
// Text processing filters.
|
||||
new TwigFilter( 'wpautop', 'wpautop', [ 'is_safe' => [ 'html' ] ] ),
|
||||
new TwigFilter( 'wp_kses_post', 'wp_kses_post', [ 'is_safe' => [ 'html' ] ] ),
|
||||
new TwigFilter( 'wptexturize', 'wptexturize' ),
|
||||
new TwigFilter( 'do_shortcode', 'do_shortcode', [ 'is_safe' => [ 'html' ] ] ),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* WordPress core functions not registered by the parent theme's TwigService.
|
||||
*
|
||||
* @return TwigFunction[]
|
||||
*/
|
||||
private function getWordPressFunctions(): array {
|
||||
return [
|
||||
// Hook system.
|
||||
new TwigFunction( 'do_action', [ $this, 'doAction' ], [ 'is_safe' => [ 'html' ] ] ),
|
||||
new TwigFunction( 'apply_filters', [ $this, 'applyFilters' ] ),
|
||||
|
||||
// Security.
|
||||
new TwigFunction( 'wp_nonce_field', function ( string $action = '-1', string $name = '_wpnonce', bool $referer = true ): string {
|
||||
return wp_nonce_field( $action, $name, $referer, false );
|
||||
}, [ 'is_safe' => [ 'html' ] ] ),
|
||||
|
||||
// Options and settings.
|
||||
new TwigFunction( 'get_option', 'get_option' ),
|
||||
|
||||
// User functions.
|
||||
new TwigFunction( 'get_current_user_id', 'get_current_user_id' ),
|
||||
new TwigFunction( 'is_user_logged_in', 'is_user_logged_in' ),
|
||||
|
||||
// URL helpers.
|
||||
new TwigFunction( 'wp_lostpassword_url', 'wp_lostpassword_url' ),
|
||||
new TwigFunction( 'get_permalink', 'get_permalink' ),
|
||||
new TwigFunction( 'get_term_link', 'get_term_link' ),
|
||||
new TwigFunction( 'wp_get_attachment_url', 'wp_get_attachment_url' ),
|
||||
|
||||
// Content rendering (echo-based, wrapped in ob_start).
|
||||
new TwigFunction( 'get_avatar', 'get_avatar', [ 'is_safe' => [ 'html' ] ] ),
|
||||
new TwigFunction( 'the_title', function (): string {
|
||||
ob_start();
|
||||
the_title();
|
||||
return ob_get_clean();
|
||||
}, [ 'is_safe' => [ 'html' ] ] ),
|
||||
new TwigFunction( 'the_content', function (): string {
|
||||
ob_start();
|
||||
the_content();
|
||||
return ob_get_clean();
|
||||
}, [ 'is_safe' => [ 'html' ] ] ),
|
||||
|
||||
// Taxonomy.
|
||||
new TwigFunction( 'term_description', 'term_description', [ 'is_safe' => [ 'html' ] ] ),
|
||||
new TwigFunction( 'single_term_title', function ( string $prefix = '' ): string {
|
||||
return single_term_title( $prefix, false );
|
||||
} ),
|
||||
|
||||
// Date/time.
|
||||
new TwigFunction( 'date_i18n', 'date_i18n' ),
|
||||
|
||||
// Text processing (as functions).
|
||||
new TwigFunction( 'wpautop', 'wpautop', [ 'is_safe' => [ 'html' ] ] ),
|
||||
new TwigFunction( 'wptexturize', 'wptexturize' ),
|
||||
new TwigFunction( 'wp_parse_url', 'wp_parse_url' ),
|
||||
|
||||
// Formatting.
|
||||
new TwigFunction( 'sprintf', 'sprintf' ),
|
||||
|
||||
// Dynamic function calls.
|
||||
new TwigFunction( 'call_user_func', [ $this, 'callUserFunc' ], [ 'is_safe' => [ 'html' ] ] ),
|
||||
new TwigFunction( 'fn', [ $this, 'callFunction' ] ),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* WooCommerce-specific functions.
|
||||
*
|
||||
* @return TwigFunction[]
|
||||
*/
|
||||
private function getWooCommerceFunctions(): array {
|
||||
return [
|
||||
// URL functions.
|
||||
new TwigFunction( 'wc_get_cart_url', 'wc_get_cart_url' ),
|
||||
new TwigFunction( 'wc_get_checkout_url', 'wc_get_checkout_url' ),
|
||||
new TwigFunction( 'wc_get_page_permalink', 'wc_get_page_permalink' ),
|
||||
new TwigFunction( 'wc_get_endpoint_url', 'wc_get_endpoint_url' ),
|
||||
new TwigFunction( 'wc_get_account_endpoint_url', 'wc_get_account_endpoint_url' ),
|
||||
new TwigFunction( 'wc_logout_url', 'wc_logout_url' ),
|
||||
|
||||
// Boolean helpers.
|
||||
new TwigFunction( 'wc_coupons_enabled', 'wc_coupons_enabled' ),
|
||||
new TwigFunction( 'wc_shipping_enabled', 'wc_shipping_enabled' ),
|
||||
new TwigFunction( 'wc_ship_to_billing_address_only', 'wc_ship_to_billing_address_only' ),
|
||||
new TwigFunction( 'wc_terms_and_conditions_checkbox_enabled', 'wc_terms_and_conditions_checkbox_enabled' ),
|
||||
|
||||
// Order functions.
|
||||
new TwigFunction( 'wc_get_order', 'wc_get_order' ),
|
||||
new TwigFunction( 'wc_get_order_status_name', 'wc_get_order_status_name' ),
|
||||
new TwigFunction( 'wc_format_datetime', 'wc_format_datetime' ),
|
||||
new TwigFunction( 'wc_date_format', 'wc_date_format' ),
|
||||
|
||||
// Product functions.
|
||||
new TwigFunction( 'wc_attribute_label', 'wc_attribute_label' ),
|
||||
new TwigFunction( 'wc_placeholder_img_src', 'wc_placeholder_img_src' ),
|
||||
new TwigFunction( 'wc_get_image_size', 'wc_get_image_size' ),
|
||||
|
||||
// Account functions.
|
||||
new TwigFunction( 'wc_get_account_menu_items', 'wc_get_account_menu_items' ),
|
||||
new TwigFunction( 'wc_get_account_menu_item_classes', 'wc_get_account_menu_item_classes' ),
|
||||
new TwigFunction( 'wc_get_account_orders_columns', 'wc_get_account_orders_columns' ),
|
||||
new TwigFunction( 'wc_get_account_orders_actions', 'wc_get_account_orders_actions' ),
|
||||
new TwigFunction( 'wc_get_account_payment_methods_columns', 'wc_get_account_payment_methods_columns' ),
|
||||
new TwigFunction( 'wc_get_account_formatted_address', 'wc_get_account_formatted_address', [ 'is_safe' => [ 'html' ] ] ),
|
||||
new TwigFunction( 'wc_get_customer_saved_methods_list', 'wc_get_customer_saved_methods_list' ),
|
||||
new TwigFunction( 'wc_get_credit_card_type_label', 'wc_get_credit_card_type_label' ),
|
||||
|
||||
// Content/form functions (echo-based, need output capture).
|
||||
new TwigFunction( 'wc_print_notices', [ $this, 'wcPrintNotices' ], [ 'is_safe' => [ 'html' ] ] ),
|
||||
new TwigFunction( 'wc_display_item_meta', [ $this, 'wcDisplayItemMeta' ], [ 'is_safe' => [ 'html' ] ] ),
|
||||
new TwigFunction( 'wc_query_string_form_fields', [ $this, 'wcQueryStringFormFields' ], [ 'is_safe' => [ 'html' ] ] ),
|
||||
new TwigFunction( 'woocommerce_form_field', [ $this, 'woocommerceFormField' ], [ 'is_safe' => [ 'html' ] ] ),
|
||||
new TwigFunction( 'woocommerce_breadcrumb', function ( array $args = [] ): string {
|
||||
ob_start();
|
||||
woocommerce_breadcrumb( $args );
|
||||
return ob_get_clean();
|
||||
}, [ 'is_safe' => [ 'html' ] ] ),
|
||||
new TwigFunction( 'woocommerce_quantity_input', function ( array $args = [], $product = null ): string {
|
||||
ob_start();
|
||||
woocommerce_quantity_input( $args, $product, true );
|
||||
return ob_get_clean();
|
||||
}, [ 'is_safe' => [ 'html' ] ] ),
|
||||
new TwigFunction( 'woocommerce_product_loop_start', function (): string {
|
||||
return woocommerce_product_loop_start( false );
|
||||
}, [ 'is_safe' => [ 'html' ] ] ),
|
||||
new TwigFunction( 'woocommerce_product_loop_end', function (): string {
|
||||
return woocommerce_product_loop_end( false );
|
||||
}, [ 'is_safe' => [ 'html' ] ] ),
|
||||
|
||||
// Text/policy functions.
|
||||
new TwigFunction( 'wc_terms_and_conditions_checkbox_text', 'wc_terms_and_conditions_checkbox_text', [ 'is_safe' => [ 'html' ] ] ),
|
||||
new TwigFunction( 'wc_replace_policy_page_link_placeholders', 'wc_replace_policy_page_link_placeholders', [ 'is_safe' => [ 'html' ] ] ),
|
||||
new TwigFunction( 'wc_get_privacy_policy_text', 'wc_get_privacy_policy_text', [ 'is_safe' => [ 'html' ] ] ),
|
||||
|
||||
// Data helpers.
|
||||
new TwigFunction( 'wc_get_post_data_by_key', 'wc_get_post_data_by_key' ),
|
||||
new TwigFunction( 'wc_get_page_id', 'wc_get_page_id' ),
|
||||
|
||||
// Template recursion (renders a WC template and returns HTML).
|
||||
new TwigFunction( 'wc_get_template', [ $this, 'wcGetTemplate' ], [ 'is_safe' => [ 'html' ] ] ),
|
||||
];
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Method implementations for functions that need special handling.
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Execute a WordPress action hook and capture its output.
|
||||
*
|
||||
* Actions may echo HTML (e.g., rendering sub-templates). Output buffering
|
||||
* captures this so it can be returned as a Twig-safe string.
|
||||
*
|
||||
* @param string $tag Action hook name.
|
||||
* @param mixed ...$args Arguments to pass to the hook.
|
||||
* @return string Captured HTML output.
|
||||
*/
|
||||
public function doAction( string $tag, ...$args ): string {
|
||||
ob_start();
|
||||
do_action( $tag, ...$args );
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply WordPress filters.
|
||||
*
|
||||
* @param string $tag Filter hook name.
|
||||
* @param mixed ...$args Arguments (first is the value to filter).
|
||||
* @return mixed Filtered value.
|
||||
*/
|
||||
public function applyFilters( string $tag, ...$args ): mixed {
|
||||
return apply_filters( $tag, ...$args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Call a user function and capture its output.
|
||||
*
|
||||
* Used for tab callbacks that echo content.
|
||||
*
|
||||
* @param callable $callback Function to call.
|
||||
* @param mixed ...$args Arguments.
|
||||
* @return string Captured output.
|
||||
*/
|
||||
public function callUserFunc( callable $callback, ...$args ): string {
|
||||
ob_start();
|
||||
call_user_func( $callback, ...$args );
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Call a PHP function by name and return its result.
|
||||
*
|
||||
* Enables `fn('WC')` in templates to access the WooCommerce singleton
|
||||
* and chain method calls via Twig's property accessor.
|
||||
*
|
||||
* @param string $name Function name.
|
||||
* @param mixed ...$args Arguments.
|
||||
* @return mixed Function return value.
|
||||
*
|
||||
* @throws \RuntimeException If function does not exist.
|
||||
*/
|
||||
public function callFunction( string $name, ...$args ): mixed {
|
||||
if ( ! function_exists( $name ) ) {
|
||||
throw new \RuntimeException( "Function {$name} does not exist." );
|
||||
}
|
||||
return $name( ...$args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Capture wc_print_notices() output.
|
||||
*
|
||||
* @return string Rendered notices HTML.
|
||||
*/
|
||||
public function wcPrintNotices(): string {
|
||||
ob_start();
|
||||
wc_print_notices();
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Render item meta without echoing.
|
||||
*
|
||||
* @param mixed $item WC_Order_Item object.
|
||||
* @param array $args Display arguments.
|
||||
* @return string Rendered meta HTML.
|
||||
*/
|
||||
public function wcDisplayItemMeta( $item, array $args = [] ): string {
|
||||
$args['echo'] = false;
|
||||
return wc_display_item_meta( $item, $args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Render query string form fields and return HTML.
|
||||
*
|
||||
* @param mixed $values Values array or null.
|
||||
* @param array $exclude Keys to exclude.
|
||||
* @param string $currentKey Current key prefix.
|
||||
* @return string Hidden input fields HTML.
|
||||
*/
|
||||
public function wcQueryStringFormFields( $values = null, array $exclude = [], string $currentKey = '' ): string {
|
||||
return wc_query_string_form_fields( $values, $exclude, $currentKey, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a WooCommerce form field and return HTML.
|
||||
*
|
||||
* @param string $key Field key.
|
||||
* @param array $args Field arguments.
|
||||
* @param mixed $value Field value.
|
||||
* @return string Rendered field HTML.
|
||||
*/
|
||||
public function woocommerceFormField( string $key, array $args, $value = null ): string {
|
||||
$args['return'] = true;
|
||||
return woocommerce_form_field( $key, $args, $value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a WooCommerce template and return its HTML.
|
||||
*
|
||||
* Enables recursive template calls from within Twig templates.
|
||||
* The rendered template goes through the same interception pipeline,
|
||||
* so it will use the Twig version if one exists.
|
||||
*
|
||||
* @param string $templateName Template name (e.g., 'order/order-downloads.php').
|
||||
* @param array $args Template context variables.
|
||||
* @return string Rendered HTML.
|
||||
*/
|
||||
public function wcGetTemplate( string $templateName, array $args = [] ): string {
|
||||
ob_start();
|
||||
wc_get_template( $templateName, $args );
|
||||
return ob_get_clean();
|
||||
}
|
||||
}
|
||||
@@ -18,10 +18,7 @@
|
||||
# @since 0.1.0
|
||||
#}
|
||||
|
||||
{% if not apply_filters('woocommerce_order_item_visible', true, item) %}
|
||||
{% do return() %}
|
||||
{% endif %}
|
||||
|
||||
{% if apply_filters('woocommerce_order_item_visible', true, item) %}
|
||||
{% set is_visible = product and product.is_visible() %}
|
||||
{% set product_permalink = apply_filters('woocommerce_order_item_permalink', is_visible ? product.get_permalink(item) : '', item, order) %}
|
||||
|
||||
@@ -61,3 +58,4 @@
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
@@ -16,10 +16,7 @@
|
||||
|
||||
{% set order = wc_get_order(order_id) %}
|
||||
|
||||
{% if not order %}
|
||||
{% do return() %}
|
||||
{% endif %}
|
||||
|
||||
{% if order %}
|
||||
{% set order_items = order.get_items(apply_filters('woocommerce_purchase_order_item_types', 'line_item')) %}
|
||||
{% set show_purchase_note = order.has_status(apply_filters('woocommerce_purchase_note_order_statuses', ['completed', 'processing'])) %}
|
||||
{% set show_customer_details = order.get_user_id() == get_current_user_id() %}
|
||||
@@ -89,3 +86,4 @@
|
||||
{% if show_customer_details %}
|
||||
{% include 'order/order-details-customer.html.twig' with { order: order } %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
Reference in New Issue
Block a user