Skip to content

Template System

Comprehensive guide to the plugin template system - how to customize templates, use hooks, and filters.

The plugin uses the WordPressTemplates system from wpify/templates for rendering all front-end elements.

Key benefits:

  • Templates can be overridden in the theme (child-theme compatible)
  • Each template contains hooks for extension
  • Data can be filtered before rendering
  • WordPress standard API (get_template_part(), load_template())

The plugin includes the following templates in the templates/ folder:

Purpose: Wrapper for discount info blocks on product pages.

Usage: Displays pricing tables and discount messages on the product page.

Arguments:

$args = [
'items' => [], // Array of items with 'rule', 'content', 'pricing'
'product' => WC_Product, // Product object
'classes' => [
'block' => ['wpify-woo-discount-info-block'],
'item' => ['wpify-woo-discount-info-block__item'],
'content' => ['wpify-woo-discount-info-block__content'],
'pricing' => ['wpify-woo-discount-info-block__pricing'],
],
];

Template hooks:

  • wpify_woo_discounts_info_block_html_start - At the beginning of the block
  • wpify_woo_discounts_info_block_html_item_start - At the beginning of each item
  • wpify_woo_discounts_info_block_html_item_before_pricing - Before the pricing table
  • wpify_woo_discounts_info_block_html_item_end - At the end of each item
  • wpify_woo_discounts_info_block_html_end - At the end of the block

Purpose: Pricing table for Bulk/Bundle discounts.

Usage: Displays a “Buy more, pay less” table.

Arguments:

$args = [
'classes' => ['wpify-woo-discount-table'], // Table CSS classes
'header' => ['Quantity', 'Price'], // Header labels
'body' => [
['3-5 pcs', '$100'],
['6-10 pcs', '$90'],
], // Rows with cells
];

Hooks: None (pure presentational template).


Purpose: Wrapper for Manual Select product selection (gifts, BOGO).

Usage: Displays a list of products to choose from in the cart.

Arguments:

$args = [
'rule' => [], // Rule configuration
'data' => [], // Display data (classes, labels, etc.)
'component_id' => 'unique-id', // Unique component ID
'available_products' => [], // Available products for selection
'rule_type' => 'free_gift', // Rule type
'rule_id' => '123', // Rule ID
];

Template hooks:

  • wpify_woo_discounts_selection_html_before_list - Before the product list
  • wpify_woo_discounts_selection_html_list_start - At the beginning of the list
  • wpify_woo_discounts_selection_html_item - For each product (renders selection-item.php)
  • wpify_woo_discounts_selection_html_list_end - At the end of the list
  • wpify_woo_discounts_selection_html_after_list - After the product list

Purpose: Single item in the Manual Select list.

Usage: Displays one product with a “Select” button.

Arguments:

$args = [
'item_data' => [], // Item data (classes, stock status, button label, etc.)
'product' => WC_Product, // Product object
'rule' => [], // Rule configuration
'image_html' => '<img...>', // Prepared image HTML
'price_data' => [
'original_price' => 100,
'discounted_price' => 80,
'discount_amount' => 20,
],
];

Template hooks:

  • wpify_woo_discounts_selection_html_item_start - At the beginning of the item
  • wpify_woo_discounts_selection_html_item_content_start - At the beginning of the content
  • wpify_woo_discounts_selection_html_item_details_start - At the beginning of the details
  • wpify_woo_discounts_selection_html_item_details_end - At the end of the details
  • wpify_woo_discounts_selection_html_item_before_form - Before the form
  • wpify_woo_discounts_selection_html_item_content_end - At the end of the content
  • wpify_woo_discounts_selection_html_item_end - At the end of the item

Purpose: Progress bar encouraging higher-value purchases.

Usage: Displays a progress bar in the cart/checkout.

Arguments:

$args = [
'bar' => [], // Bar configuration
'index' => 0, // Bar index
'data' => [
'additional_classes' => [], // Custom classes
'is_single' => false, // Single or multi mode
'first_goal_icon_html' => '<svg...>', // Icon for single mode
'message' => 'Add $50 more...', // Current message
'goals_data' => [], // Goals with progress data
],
'progress' => [], // Progress data
];

Hooks: None (uses filters instead, see below).


Purpose: Display savings overview in the cart/checkout (outside the table).

Usage: Displays a list of applied discounts and the total savings amount as a block.

Arguments:

$args = [
'tracking' => [], // Discount tracking data
'total_saved' => 0, // Total saved amount (float)
'labels' => [], // Array of discount labels (strings)
'show_labels' => true, // Whether to display labels
'show_value' => true, // Whether to display saved value
];

Template hooks:

  • wpify_woo_discounts_savings_summary_start - At the beginning of the block
  • wpify_woo_discounts_savings_summary_end - At the end of the block

Shortcode:

[wpify_discounts_savings_summary]

The shortcode renders the complete block including the fragment wrapper for AJAX updates.

Fragment support: The template contains the CSS class wpify-woo-savings-summary-fragment for WooCommerce AJAX fragment replacement. The wrapper is always rendered (even when empty) so that fragments work correctly.

Block cart support: The plugin automatically injects savings summary into the WooCommerce block cart using the Store API extension and the render_block filter.


Purpose: Display savings overview as a row in the cart totals table.

Usage: Displays savings directly in the cart totals table (hook woocommerce_cart_totals_after_order_total).

Arguments:

$args = [
'tracking' => [], // Discount tracking data
'total_saved' => 0, // Total saved amount (float)
'labels' => [], // Array of discount labels (strings)
'show_labels' => true, // Whether to display labels
'show_value' => true, // Whether to display saved value
];

Output:

<tr class="wpify-woo-savings-summary-row">
<th>You saved</th>
<td>
<span class="wpify-woo-savings-summary__value">$150</span>
<small class="wpify-woo-savings-summary__labels">(Winter Sale, VIP)</small>
</td>
</tr>

Purpose: Inline checkbox for upsell offer in a cart item row.

Usage: Displays a checkbox with a product directly below the trigger product in the cart. Used by the Upsell in Cart Item mode.

Arguments:

$args = [
'rule' => [], // Rule configuration
'item_data' => [
'product_id' => 123, // Product ID
'group_id' => 'abc', // Group ID
'is_in_cart' => false, // Whether already in cart
'item_disabled' => false, // Whether disabled (unavailable)
'available_quantity' => 1, // Available quantity
'item_image_size' => 'thumbnail', // Image size (empty = hidden)
'item_title' => 'Product', // Title (empty = hidden)
'item_description' => '', // Short description (empty = hidden)
'item_link' => '', // Permalink (empty = no link)
'variation_data' => '', // Formatted variation attributes
'image_html' => '<img...>', // Prepared image HTML
'show_quantity' => true, // Show quantity badge
'price_data' => [
'original_price' => 100,
'discounted_price' => 80,
'discount_amount' => 20,
],
'trigger_cart_keys' => [], // Pool trigger keys
'pool_deplete_per_set' => 0, // Pool depletion per set
'quantity_per_set' => 1, // Quantity per set
],
'product' => WC_Product, // Target product object
'rule_type' => 'free_gift', // Rule type
'rule_id' => '123', // Rule ID
];

CSS classes:

  • wpify-woo-discount-upsell-cart-item — wrapper
  • wpify-woo-discount-upsell-cart-item--active — checkbox checked
  • wpify-woo-discount-upsell-cart-item--disabled — unavailable product

Filters:

  • wpify_woo_discounts_upsell_cart_item_data — modify item_data before rendering
  • wpify_woo_discounts_upsell_cart_item_price_data — modify price data
  • wpify_woo_discounts_upsell_cart_item_html — modify the final HTML

Purpose: CTA block for adding a product to the cart with a coupon.

Usage: Displays an “Add to cart with discount” button on the product page.

Module: Coupons (optional module)

Arguments:

$args = [
'coupon' => [
'button_text' => 'Buy for $199', // Button text
'coupon_code' => 'SAVE20', // Coupon code
'discounted_price' => 199.00, // Discounted price
'url' => '...', // Add-to-cart URL
],
'title' => 'Special Offer!', // Block title
'url' => '...', // Add-to-cart URL
'product' => WC_Product, // Product object
];

Template hooks:

  • wpify_woo_discounts_coupon_block_html_start - At the beginning of the block
  • wpify_woo_discounts_coupon_block_html_end - At the end of the block

Predefined styles: In the Coupons module settings, you can select a style:

  • minimal - Simple light design
  • bordered - Bordered with dashed line
  • shine - Colorful with animation
  • custom - Custom CSS (no default styles)

The plugin uses the WordPressTemplates class, which looks for templates in this order:

  1. Child theme - {child-theme}/wpify-woo-discount-rules/{template}.php
  2. Parent theme - {theme}/wpify-woo-discount-rules/{template}.php
  3. Plugin templates - {plugin}/templates/{template}.php

Example:

// The plugin calls:
$this->templates->print('info-block', null, $args);
// WordPress looks in this order:
// 1. wp-content/themes/my-child-theme/wpify-woo-discount-rules/info-block.php
// 2. wp-content/themes/my-theme/wpify-woo-discount-rules/info-block.php
// 3. wp-content/plugins/wpify-woo-discount-rules/templates/info-block.php

Step 1: Create a folder in your theme

Terminal window
wp-content/themes/your-theme/wpify-woo-discount-rules/

Step 2: Copy the template from the plugin

Terminal window
cp wp-content/plugins/wpify-woo-discount-rules/templates/info-block.php \
wp-content/themes/your-theme/wpify-woo-discount-rules/info-block.php

Step 3: Edit the template as needed


File: your-theme/wpify-woo-discount-rules/info-block.php

<?php
/**
* Custom Info Block Template
*/
defined( 'ABSPATH' ) || exit;
$items = $args['items'] ?? [];
$product = $args['product'] ?? null;
?>
<div class="my-custom-discount-block">
<h3>Special Offers!</h3>
<?php foreach ( $items as $item ) : ?>
<div class="my-custom-discount-item">
<?php if ( ! empty( $item['content'] ) ) : ?>
<div class="discount-message">
<?php echo wp_kses_post( $item['content'] ); ?>
</div>
<?php endif; ?>
<?php if ( ! empty( $item['pricing'] ) ) : ?>
<div class="discount-pricing">
<?php echo wp_kses_post( $item['pricing'] ); ?>
</div>
<?php endif; ?>
</div>
<?php endforeach; ?>
</div>

File: your-theme/wpify-woo-discount-rules/pricing-table.php

<?php
/**
* Custom Pricing Table Template - Cards layout
*/
defined( 'ABSPATH' ) || exit;
$header = $args['header'] ?? [];
$body = $args['body'] ?? [];
?>
<div class="custom-pricing-cards">
<?php foreach ( $body as $index => $row ) : ?>
<div class="pricing-card">
<div class="pricing-card__quantity">
<?php echo esc_html( $row[0] ); ?>
</div>
<div class="pricing-card__price">
<?php echo wp_kses_post( $row[1] ); ?>
</div>
<?php if ( 0 === $index ) : ?>
<span class="pricing-card__badge">Best Deal!</span>
<?php endif; ?>
</div>
<?php endforeach; ?>
</div>

You can modify the data before rendering using filters.

Universal filter for all templates. Fires before rendering any template.

add_filter('wpify_templates_template_args', function($args, $slug, $name, $filename, $templates) {
// Modify args for all templates
if ($slug === 'info-block') {
// Add a custom class for info-block
$args['classes']['block'][] = 'my-custom-class';
}
return $args;
}, 10, 5);

Parameters:

  • $args (array) - Template arguments
  • $slug (string) - Template slug (e.g. ‘info-block’)
  • $name (string|null) - Template name (e.g. null)
  • $filename (string) - Full filename (e.g. ‘info-block’)
  • $templates (WordPressTemplates) - Templates instance

Filter for the info-block template. Fires before rendering the info block.

add_filter('wpify_woo_discounts_info_block_args', function($args, $product) {
// Add a custom wrapper class
$args['classes']['block'][] = 'my-info-block-class';
// Add a custom item
$args['items'][] = [
'rule' => [],
'content' => '<p>Extra info here!</p>',
'pricing' => '',
];
return $args;
}, 10, 2);

Parameters:

  • $args (array) - Info block arguments
  • $product (WC_Product) - Product object

wpify_woo_discounts_info_block_item_content

Section titled “wpify_woo_discounts_info_block_item_content”

Filter for the content of each item in the info block.

add_filter('wpify_woo_discounts_info_block_item_content', function($content, $rule, $product) {
// For Bulk discounts add a custom message
if ($rule['type'] === 'bulk') {
$content = '<strong>Volume Discount!</strong><br>' . $content;
}
return $content;
}, 10, 3);

Parameters:

  • $content (string) - Current content (may be empty)
  • $rule (array) - Rule configuration
  • $product (WC_Product) - Product object

wpify_woo_discounts_info_block_item_pricing

Section titled “wpify_woo_discounts_info_block_item_pricing”

Filter for the pricing of each item in the info block.

add_filter('wpify_woo_discounts_info_block_item_pricing', function($pricing, $rule, $product) {
// For Bundle discounts modify the pricing HTML
if ($rule['type'] === 'bundle') {
// $pricing contains the pricing table HTML
$pricing = '<div class="bundle-pricing">' . $pricing . '</div>';
}
return $pricing;
}, 10, 3);

Parameters:

  • $pricing (string) - Current pricing HTML (may be empty)
  • $rule (array) - Rule configuration
  • $product (WC_Product) - Product object

Filter for the data of the selection block (Manual Select).

add_filter('wpify_woo_discounts_selection_html_data', function($data) {
// Add a custom class
$data['classes']['block'][] = 'my-selection-block';
// Change title
$data['title'] = 'Choose your gift!';
// Change description
$data['description'] = 'You will get it free with your order.';
return $data;
});

Parameters:

  • $data (array) - Display data (classes, title, description, button labels)

wpify_woo_discounts_selection_html_item_data

Section titled “wpify_woo_discounts_selection_html_item_data”

Filter for the data of each item in the selection list.

add_filter('wpify_woo_discounts_selection_html_item_data', function($item_data, $product, $settings, $hidden_elements) {
// Modify button label
if ($product->is_on_sale()) {
$item_data['button_label'] = 'Select this sale item!';
}
// Add a custom class
$item_data['classes']['item'][] = 'on-sale-item';
return $item_data;
}, 10, 4);

Parameters:

  • $item_data (array) - Item data (classes, button label, stock status, etc.)
  • $product (WC_Product) - Product object
  • $settings (array) - Manual Select group settings
  • $hidden_elements (array) - List of hidden elements

Filter for the data of the upsell bar.

add_filter('wpify_woo_discounts_upsell_bar_data', function($data, $bar, $index) {
// Add a custom class
$data['additional_classes']['block'][] = 'my-upsell-class';
// Modify message
$data['message'] = $data['message'];
return $data;
}, 10, 3);

Parameters:

  • $data (array) - Display data (classes, message, goals_data, etc.)
  • $bar (array) - Bar configuration
  • $index (int) - Bar index

wpify_woo_discounts_upsell_bar_wrapper_classes

Section titled “wpify_woo_discounts_upsell_bar_wrapper_classes”

Filter for the wrapper classes of the upsell bar.

add_filter('wpify_woo_discounts_upsell_bar_wrapper_classes', function($classes, $bar, $index) {
// Add class based on index
$classes[] = 'upsell-bar-' . $index;
// Add class based on type
$type = $bar['type'] ?? '';
if ($type === 'cart_subtotal') {
$classes[] = 'upsell-bar--subtotal';
}
return $classes;
}, 10, 3);

Parameters:

  • $classes (array) - Wrapper CSS classes
  • $bar (array) - Bar configuration
  • $index (int) - Bar index

Each template contains action hooks for adding custom HTML.

// At the beginning of the block
add_action('wpify_woo_discounts_info_block_html_start', function($items, $product) {
echo '<div class="custom-intro">Special discounts for this product:</div>';
}, 10, 2);
// At the beginning of each item
add_action('wpify_woo_discounts_info_block_html_item_start', function($items, $product) {
echo '<span class="item-badge">SALE</span>';
}, 10, 2);
// Before the pricing table
add_action('wpify_woo_discounts_info_block_html_item_before_pricing', function($items, $product) {
echo '<p class="pricing-intro">Pricing table:</p>';
}, 10, 2);
// At the end of each item
add_action('wpify_woo_discounts_info_block_html_item_end', function($items, $product) {
echo '<a href="/sale">View all discounts</a>';
}, 10, 2);
// At the end of the block
add_action('wpify_woo_discounts_info_block_html_end', function($items, $product) {
echo '<div class="custom-footer">* Discounts valid until further notice</div>';
}, 10, 2);

// Before the product list
add_action('wpify_woo_discounts_selection_html_before_list', function($rule, $data) {
echo '<div class="selection-intro">Choose one of the products:</div>';
}, 10, 2);
// At the beginning of the list
add_action('wpify_woo_discounts_selection_html_list_start', function($rule, $data) {
echo '<div class="list-header">Available products:</div>';
}, 10, 2);
// For each product (custom render)
add_action('wpify_woo_discounts_selection_html_item', function($rule, $data, $product_entry) {
// By default, selection-item.php is rendered here
// You can render custom HTML instead of the default template
}, 10, 3);
// At the end of the list
add_action('wpify_woo_discounts_selection_html_list_end', function($rule, $data) {
echo '<div class="list-footer">All products in stock</div>';
}, 10, 2);
// After the product list
add_action('wpify_woo_discounts_selection_html_after_list', function($rule, $data) {
echo '<p class="selection-note">You can change your selection even after adding to cart.</p>';
}, 10, 2);

// At the beginning of the item
add_action('wpify_woo_discounts_selection_html_item_start', function($rule, $item_data, $product) {
if ($product->is_featured()) {
echo '<span class="featured-badge">Recommended!</span>';
}
}, 10, 3);
// At the beginning of the content
add_action('wpify_woo_discounts_selection_html_item_content_start', function($rule, $item_data, $product) {
echo '<div class="item-wrapper">';
}, 10, 3);
// At the beginning of the details
add_action('wpify_woo_discounts_selection_html_item_details_start', function($rule, $item_data, $product) {
$sku = $product->get_sku();
if ($sku) {
echo '<span class="sku">SKU: ' . esc_html($sku) . '</span>';
}
}, 10, 3);
// At the end of the details
add_action('wpify_woo_discounts_selection_html_item_details_end', function($rule, $item_data, $product) {
// Add rating
woocommerce_template_loop_rating();
}, 10, 3);
// Before the form
add_action('wpify_woo_discounts_selection_html_item_before_form', function($rule, $item_data, $product) {
echo '<div class="stock-info">' . wc_get_stock_html($product) . '</div>';
}, 10, 3);
// At the end of the content
add_action('wpify_woo_discounts_selection_html_item_content_end', function($rule, $item_data, $product) {
echo '</div>'; // Close wrapper from content_start
}, 10, 3);
// At the end of the item
add_action('wpify_woo_discounts_selection_html_item_end', function($rule, $item_data, $product) {
echo '<hr class="item-separator">';
}, 10, 3);

add_action('wpify_woo_discounts_info_block_html_start', function($items, $product) {
// Find a rule with a time constraint
foreach ($items as $item) {
$rule = $item['rule'] ?? [];
$conditions = $rule['conditions'] ?? [];
foreach ($conditions as $condition_group) {
foreach ($condition_group as $condition) {
if ($condition['type'] === 'date' && !empty($condition['date_end'])) {
$end_date = strtotime($condition['date_end']);
if ($end_date > time()) {
echo '<div class="discount-countdown">';
echo 'Discount valid for another ' . human_time_diff(time(), $end_date);
echo '</div>';
return; // Stop after first
}
}
}
}
}
}, 10, 2);

Example 2: Modify Button Label Based on Product

Section titled “Example 2: Modify Button Label Based on Product”
add_filter('wpify_woo_discounts_selection_html_item_data', function($item_data, $product, $settings, $hidden_elements) {
// Modify label based on product status
if ($product->is_on_sale()) {
$item_data['button_label'] = 'Select sale product';
} elseif ($product->is_featured()) {
$item_data['button_label'] = 'Select recommended';
} else {
$item_data['button_label'] = 'Select';
}
return $item_data;
}, 10, 4);

File: your-theme/wpify-woo-discount-rules/pricing-table.php

<?php
/**
* Custom Pricing Table - Horizontal Cards
*/
defined( 'ABSPATH' ) || exit;
$header = $args['header'] ?? [];
$body = $args['body'] ?? [];
?>
<div class="custom-pricing-horizontal">
<h4 class="pricing-title">The more you buy, the more you save!</h4>
<div class="pricing-cards-row">
<?php foreach ( $body as $index => $row ) : ?>
<div class="pricing-card <?php echo 0 === $index ? 'pricing-card--best' : ''; ?>">
<?php if ( 0 === $index ) : ?>
<span class="badge">Best Deal</span>
<?php endif; ?>
<div class="card-quantity">
<?php echo esc_html( $row[0] ); ?>
</div>
<div class="card-price">
<?php echo wp_kses_post( $row[1] ); ?>
</div>
</div>
<?php endforeach; ?>
</div>
</div>
<style>
.custom-pricing-horizontal {
margin: 20px 0;
padding: 20px;
background: #f7f7f7;
border-radius: 8px;
}
.pricing-title {
text-align: center;
margin-bottom: 20px;
}
.pricing-cards-row {
display: flex;
gap: 15px;
justify-content: center;
}
.pricing-card {
flex: 1;
max-width: 200px;
padding: 20px;
background: white;
border: 2px solid #ddd;
border-radius: 8px;
text-align: center;
position: relative;
}
.pricing-card--best {
border-color: #008B8B;
transform: scale(1.05);
}
.pricing-card .badge {
position: absolute;
top: -10px;
left: 50%;
transform: translateX(-50%);
background: #008B8B;
color: white;
padding: 5px 15px;
border-radius: 20px;
font-size: 12px;
font-weight: bold;
}
.card-quantity {
font-size: 18px;
font-weight: bold;
margin-bottom: 10px;
}
.card-price {
font-size: 24px;
color: #008B8B;
}
</style>

Example 4: Add Custom Field to Selection Item

Section titled “Example 4: Add Custom Field to Selection Item”
// Add a custom field to product meta
add_action('wpify_woo_discounts_selection_html_item_details_end', function($rule, $item_data, $product) {
// Add delivery time
$delivery = get_post_meta($product->get_id(), '_delivery_time', true);
if ($delivery) {
echo '<div class="delivery-time">';
echo 'Delivery: ' . esc_html($delivery);
echo '</div>';
}
// Add stock status
echo '<div class="stock-status">';
if ($product->is_in_stock()) {
echo 'In Stock';
} else {
echo 'Out of Stock';
}
echo '</div>';
}, 10, 3);

Example 5: Change Classes Based on Product Category

Section titled “Example 5: Change Classes Based on Product Category”
add_filter('wpify_woo_discounts_selection_html_item_data', function($item_data, $product, $settings, $hidden_elements) {
// Add class based on category
$categories = $product->get_category_ids();
foreach ($categories as $cat_id) {
$cat = get_term($cat_id, 'product_cat');
if ($cat) {
$item_data['classes']['item'][] = 'category-' . $cat->slug;
}
}
return $item_data;
}, 10, 4);

Do I have to override the entire template?

No. You can use hooks to add custom HTML without overriding the template.

Example:

// Instead of overriding info-block.php:
add_action('wpify_woo_discounts_info_block_html_start', function($items, $product) {
echo '<div class="my-custom-intro">Custom HTML here</div>';
}, 10, 2);
How do I find out what arguments a template has?

Each template has a docblock comment in the file header describing $args.

Example:

/**
* Info Block Template
*
* @var array $args Template arguments
* - items (array) Array of items with 'rule', 'content', 'pricing'
* - product (WC_Product) Product object
*/
Can I use a child theme?

Yes. WordPressTemplates looks for templates first in the child theme, then in the parent theme, then in the plugin.

Structure:

wp-content/themes/my-child-theme/
└── wpify-woo-discount-rules/
├── info-block.php
├── pricing-table.php
└── selection-item.php
How do I debug templates?

1. Find out which template is being used:

add_filter('wpify_templates_template_args', function($args, $slug, $name, $filename) {
error_log("Loading template: $filename");
error_log("Args: " . print_r($args, true));
return $args;
}, 10, 4);

2. Output the arguments in the template:

<?php
// In the template
echo '<pre>';
print_r($args);
echo '</pre>';
?>
How do I remove a default hook?

Use remove_action() or remove_filter().

Example:

// Find the hook in the plugin code
// E.g. if the plugin adds a hook in ManualSelectMode::setup_default_template_hooks()
// Remove the hook
remove_action('wpify_woo_discounts_selection_html_item', [
$manual_select_instance,
'render_selection_item'
], 10);
// Add your own
add_action('wpify_woo_discounts_selection_html_item', 'my_custom_item_render', 10, 3);