Skip to content

Instantly share code, notes, and snippets.

@yokirahmada
Last active October 5, 2025 21:29
Show Gist options
  • Select an option

  • Save yokirahmada/696d3ca0eb0a26fa64561497c22d7b2f to your computer and use it in GitHub Desktop.

Select an option

Save yokirahmada/696d3ca0eb0a26fa64561497c22d7b2f to your computer and use it in GitHub Desktop.
Debugging & get price by size with Plugin Republic Plugin
// 1. SHORTCODE FORM FILTER
function pewc_size_filter_shortcode() {
if ( is_product_category( 'curtains' ) ) {
return '';
}
if ( is_product_category( 'sheers' ) ) {
return '';
}
if ( is_product_category( 'track-accessories' ) ) {
return '';
}
ob_start();
$width = isset($_GET['width']) ? intval($_GET['width']) : '';
$height = isset($_GET['height']) ? intval($_GET['height']) : '';
?>
<div class="pewc-size-filter-form">
<form method="get" class="pewc-filter-form">
<input type="hidden" name="post_type" value="product">
<div class="filter-row">
<div class="input-wrapper width">
<label for="pewc-width" class="gfield_label">Width</label>
<input type="number" id="pewc-width" name="width" value="<?php echo esc_attr($width); ?>" min="0" required />
</div>
<div class="input-wrapper height">
<label for="pewc-height" class="gfield_label">Height</label>
<input type="number" id="pewc-height" name="height" value="<?php echo esc_attr($height); ?>" min="0" required />
</div>
<div class="button-group">
<button type="submit" class="filter-submit">Show Me Pricing</button>
</div>
<!-- <div class="button-group">
<a href="<?php echo esc_url(remove_query_arg(['width', 'height'])); ?>" class="filter-reset">Reset</a>
</div> -->
</div>
</form>
</div>
<style>
.pewc-filter-form .filter-row {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 10px;
align-items: end;
width: 1200px !important;
margin: 0 auto;
}
.pewc-filter-form input[name="width"],
.pewc-filter-form input[name="height"] {
color: #000 !important;
}
/* Color <label> */
.pewc-filter-form label {
color: #000 !important;
font-weight: bold;
}
.input-wrapper.width {
margin-right: 6px;
}
.input-wrapper.width,
.input-wrapper.height {
display: flex;
align-items: center;
background: white;
border-radius: 40px;
position: relative;
width: 300px;
height: 60px;
flex-shrink: 0;
padding-right: 64px;
}
/* Left Icon */
.input-wrapper.width::before,
.input-wrapper.height::before {
content: "↔";
background-color: #efd962;
color: black;
font-size: 24px;
width: 80px;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
border-radius: 40px 0px 0px 40px;
position: absolute;
left: -5px;
}
.input-wrapper.height::before {
content: "↕";
}
/* Label */
.input-wrapper .gfield_label {
position: absolute;
left: 90px;
top: 20px;
font-weight: bold;
font-size: 16px;
z-index: 1;
color: black;
}
/* Input */
.input-wrapper input {
font-size: 16px;
width: 130px;
padding: 5px 0px 0px 0px !important;
background: transparent;
border: none;
position: absolute;
left: 36px;
margin-left: 120px;
border-bottom: 1px solid #000000;
box-sizing: border-box;
}
.input-wrapper input:focus {
outline: none !important;
border-top: none !important;
border-right: none !important;
border-left: none !important;
border-bottom: 1px solid #000000 !important;
}
/* mm */
.input-wrapper.width::after,
.input-wrapper.height::after {
content: "mm";
position: absolute;
right: 15px;
top: 44%;
transform: translateY(-25%);
font-size: 14px;
color: #444;
color: black;
}
.button-group button,
.button-group a {
width: 100%;
height: 60px;
padding: 12px;
border: none;
border-radius: 4px;
text-align: center;
font-weight: 600;
cursor: pointer;
transition: all 0.3s;
text-decoration: none;
box-sizing: border-box;
display: inline-block;
}
.filter-submit {
background-color: #efd962!important;
color: black;
padding: 15px 25px !important;
border-radius: 30px!important;
border: none;
font-size: 15px;
font-weight: bold;
cursor: pointer;
}
.filter-submit::after {
content: "→"!important;
font-size: 18px!important;
margin-left: 20px;
}
.filter-submit:hover {
background: #1d4f83;
}
.filter-reset {
background: #e74c3c;
color: white;
padding: 15px 25px !important;
border-radius: 30px!important;
border: none;
font-size: 15px;
font-weight: bold;
cursor: pointer;
}
.filter-reset:hover {
background: #c0392b;
}
@media only screen and (max-width: 1024px){
.pewc-filter-form .filter-row {
grid-template-columns: repeat(3, 1fr);
margin: 0 auto;
padding: 0 15px;
box-sizing: border-box;
width: 100% !important;
}
.input-wrapper.width, .input-wrapper.height{
width: 100%;
}
}
@media only screen and (max-width: 768px) {
.pewc-filter-form .filter-row {
grid-template-columns: 1fr;
margin: 0 auto;
padding: 0 15px;
box-sizing: border-box;
width: 100% !important;
}
.input-wrapper.width, .input-wrapper.height{
width: 100%;
}
.button-group button,
.button-group a {
width: 100%;
padding: 14px;
font-size: 16px;
}
.input-wrapper .gfield_label {
font-size: 14px;
top: 16px;
left: 70px;
}
.input-wrapper input {
margin-left: 100px;
width: calc(100% - 140px);
left: 28px;
}
.input-wrapper.width::before,
.input-wrapper.height::before {
width: 60px;
font-size: 20px;
}
.input-wrapper.width::after,
.input-wrapper.height::after {
font-size: 12px;
right: 10px;
}
}
</style>
<?php
return ob_get_clean();
}
add_shortcode('pewc_size_filter', 'pewc_size_filter_shortcode');
// 3. FUNCTION FILTER PRODUCTS (UPDATED VERSION)
add_action('woocommerce_product_query', 'filter_products_by_pewc_size', 20);
function filter_products_by_pewc_size($q) {
if (is_admin() || !$q->is_main_query()) return;
$width = isset($_GET['width']) ? (int)$_GET['width'] : null;
$height = isset($_GET['height']) ? (int)$_GET['height'] : null;
// Only filter with parameter width/height
if (!$width && !$height) return;
$all_ids = wc_get_products([
'limit' => -1,
'return' => 'ids',
'status' => 'publish'
]);
$matched_ids = [];
foreach ($all_ids as $product_id) {
$groups = pewc_get_extra_fields($product_id);
$has_match = false;
// Skip If product DOESNT HAVE PEWC GROUPS FROM PLUGIN
if (empty($groups)) continue;
foreach ($groups as $group) {
if (empty($group['items'])) continue;
foreach ($group['items'] as $field) {
if (isset($field['field_type']) &&
$field['field_type'] === 'calculation' &&
isset($field['formula']) &&
$field['formula'] === '{look_up_table}' &&
!empty($field['look_up_table'])) {
$tables = apply_filters('pewc_calculation_look_up_tables', []);
$table = $tables[$field['look_up_table']] ?? [];
// If the table is empty, continue
if (empty($table)) continue;
// Get all available widths and heights
$available_widths = array_keys($table);
$available_heights = !empty($available_widths) ? array_keys($table[$available_widths[0]]) : [];
// Find the nearest width (rounding up)
$nearest_width = find_nearest_size($available_widths, $width);
// Find the nearest height (rounding up)
$nearest_height = find_nearest_size($available_heights, $height);
// If a price is found for the nearest size
if (isset($table[$nearest_width][$nearest_height])) {
$has_match = true;
break 2;
}
}
}
}
if ($has_match) {
$matched_ids[] = $product_id;
}
}
// If product matches
if (!empty($matched_ids)) {
$q->set('post__in', $matched_ids);
} else {
// If doesnt product matches
add_action('woocommerce_before_shop_loop', function() {
echo '<div class="woocommerce-info">No products match the selected size.</div>';
}, 30);
// empty query
$q->set('post__in', [0]);
}
}
// 4. Show active filters
add_action('woocommerce_before_shop_loop', 'display_active_size_filter', 5);
function display_active_size_filter() {
if (!is_shop() && !is_product_category()) return;
$width = isset($_GET['width']) ? (int)$_GET['width'] : null;
$height = isset($_GET['height']) ? (int)$_GET['height'] : null;
if ($width || $height) {
echo '<div class="pewc-active-filter">';
echo '<strong>Active Filter:</strong> ';
echo $width ? 'Width: ' . $width . 'mm ' : '';
echo $height ? 'Height: ' . $height . 'mm ' : '';
echo '</div>';
echo '<style>
.pewc-active-filter {
padding: 15px;
margin: 0 0 20px;
background: #f8f9fa;
border-left: 4px solid #27ae60;
color: #333;
}
</style>';
}
}
function find_nearest_size($available_sizes, $target_size) {
// Sort sizes from smallest to largest
sort($available_sizes);
// If target is smaller than the smallest size, return the smallest size
if ($target_size <= $available_sizes[0]) {
return $available_sizes[0];
}
// Find the first size that is greater than or equal to the target
foreach ($available_sizes as $size) {
if ($size >= $target_size) {
return $size;
}
}
// If no larger size is found, return the largest size
return end($available_sizes);
}
// 5. GET PRICE FROM TABLE
function get_pewc_table_price($product_id, $width, $height) {
$groups = pewc_get_extra_fields($product_id);
foreach ($groups as $group) {
if (empty($group['items'])) continue;
foreach ($group['items'] as $field) {
if (isset($field['field_type']) &&
$field['field_type'] === 'calculation' &&
isset($field['formula']) &&
$field['formula'] === '{look_up_table}' &&
!empty($field['look_up_table'])) {
$tables = apply_filters('pewc_calculation_look_up_tables', []);
$table = $tables[$field['look_up_table']] ?? [];
// If the table is empty, continue
if (empty($table)) continue;
// Get all available widths and heights
$available_widths = array_keys($table);
$available_heights = !empty($available_widths) ? array_keys($table[$available_widths[0]]) : [];
// Find the nearest width (rounding up)
$nearest_width = find_nearest_size($available_widths, $width);
// Find the nearest height (rounding up)
$nearest_height = find_nearest_size($available_heights, $height);
// Return the price if found
if (isset($table[$nearest_width][$nearest_height])) {
return $table[$nearest_width][$nearest_height];
}
}
}
}
return false;
}
// 6. UPDATE PRODUCT PRICE DISPLAY - MODIFIED VERSION
add_filter('woocommerce_get_price_html', 'update_price_based_on_size', 10, 2);
function update_price_based_on_size($price_html, $product) {
if (!is_shop() && !is_product_category()) return $price_html;
$width = isset($_GET['width']) ? (int)$_GET['width'] : null;
$height = isset($_GET['height']) ? (int)$_GET['height'] : null;
if ($width && $height) {
$table_price = get_pewc_table_price($product->get_id(), $width, $height);
if ($table_price !== false) {
$formatted_price = wc_price($table_price);
// Get the actual matched dimensions from the table
$matched_dimensions = get_matched_dimensions($product->get_id(), $width, $height);
$matched_width = $matched_dimensions['width'];
$matched_height = $matched_dimensions['height'];
return '<span class="price"><span class="woocommerce-Price-amount amount"><bdi>' .
$formatted_price . '</bdi></span>' .
'<div class="matched-dimensions" style="font-size:0.9em;color:#666;margin-top:5px;">' .
'' . $matched_width . 'mm × ' . $matched_height . 'mm' .
'</div></span>';
}
}
return $price_html;
}
// NEW FUNCTION TO GET MATCHED DIMENSIONS
function get_matched_dimensions($product_id, $width, $height) {
$groups = pewc_get_extra_fields($product_id);
foreach ($groups as $group) {
if (empty($group['items'])) continue;
foreach ($group['items'] as $field) {
if (isset($field['field_type']) &&
$field['field_type'] === 'calculation' &&
isset($field['formula']) &&
$field['formula'] === '{look_up_table}' &&
!empty($field['look_up_table'])) {
$tables = apply_filters('pewc_calculation_look_up_tables', []);
$table = $tables[$field['look_up_table']] ?? [];
if (empty($table)) continue;
$available_widths = array_keys($table);
$available_heights = !empty($available_widths) ? array_keys($table[$available_widths[0]]) : [];
$nearest_width = find_nearest_size($available_widths, $width);
$nearest_height = find_nearest_size($available_heights, $height);
return [
'width' => $nearest_width,
'height' => $nearest_height
];
}
}
}
return [
'width' => $width,
'height' => $height
];
}
// DEBUGING CODE
add_action('wp', function() {
if (!is_shop() || !current_user_can('manage_options')) return;
if (!isset($_GET['debug_size_filter'])) return;
// Get parameters
$width = isset($_GET['width']) ? (int)$_GET['width'] : 0;
$height = isset($_GET['height']) ? (int)$_GET['height'] : 0;
echo '<div style="padding: 20px; background: #fff; margin: 20px; border: 1px solid #ddd;">';
echo '<h1>PEWC Size Filter Debugger</h1>';
echo "<h2>Filter Parameters: Width={$width}mm, Height={$height}mm</h2>";
$products = wc_get_products([
'limit' => -1,
'return' => 'ids',
'status' => 'publish'
]);
foreach ($products as $product_id) {
$product = wc_get_product($product_id);
echo '<hr>';
echo "<h3>Product #{$product_id}: {$product->get_name()}</h3>";
$groups = function_exists('pewc_get_extra_fields') ? pewc_get_extra_fields($product_id) : [];
if (empty($groups)) {
echo "<p>No PEWC groups found (will be INCLUDED in results)</p>";
continue;
}
$has_lookup_table = false;
foreach ($groups as $group_id => $group) {
if (empty($group['items'])) continue;
foreach ($group['items'] as $field_id => $field) {
if (isset($field['field_type']) &&
$field['field_type'] === 'calculation' &&
isset($field['formula']) &&
$field['formula'] === '{look_up_table}' &&
!empty($field['look_up_table'])) {
$has_lookup_table = true;
$table_key = $field['look_up_table'];
echo "<h4>Lookup Table Found: {$field['field_label']} (Key: {$table_key})</h4>";
$all_tables = apply_filters('pewc_calculation_look_up_tables', []);
if (!isset($all_tables[$table_key])) {
echo "<p style='color:red'>Table with key '{$table_key}' not found!</p>";
continue;
}
$table = $all_tables[$table_key];
// Extract all unique widths and heights
$widths = array_keys($table);
$heights = [];
foreach ($table as $w => $height_prices) {
$heights = array_unique(array_merge($heights, array_keys($height_prices)));
}
sort($widths);
sort($heights);
// Display table
echo "<table border='1' cellpadding='5' style='border-collapse: collapse;'>";
// Header row (widths)
echo "<tr><th>{$table_key}</th>";
foreach ($widths as $w) {
$style = ($width == $w) ? 'background: #FFEB3B;' : '';
echo "<th style='{$style}'>" . esc_html($w) . "</th>";
}
echo "</tr>";
// Data rows
foreach ($heights as $h) {
echo "<tr>";
$style = ($height == $h) ? 'background: #FFEB3B;' : '';
echo "<td style='{$style}'>" . esc_html($h) . "</td>";
foreach ($widths as $w) {
$value = $table[$w][$h] ?? '';
$cell_style = ($width == $w && $height == $h) ? 'background: #4CAF50; color: white;' : '';
echo "<td style='{$cell_style}'>" . esc_html($value) . "</td>";
}
echo "</tr>";
}
echo "</table>";
// Check for match
if ($width > 0 && $height > 0) {
$match_found = isset($table[$width][$height]);
if ($match_found) {
echo "<p style='color:green; font-weight:bold'>MATCH FOUND for {$width}mm × {$height}mm (Price: {$table[$width][$height]})</p>";
} else {
echo "<p style='color:red'>No match for {$width}mm × {$height}mm</p>";
}
}
}
}
}
if (!$has_lookup_table) {
echo "<p>No lookup tables found (will be INCLUDED in results)</p>";
}
}
echo '</div>';
exit;
});
add_action('wp_footer', 'porto_modify_product_links_with_size_params');
function porto_modify_product_links_with_size_params() {
// Only run on shop/category/tag pages
if (!is_shop() && !is_product_category() && !is_product_tag()) {
return;
}
// Get current size parameters
$width = isset($_GET['width']) ? absint($_GET['width']) : 0;
$height = isset($_GET['height']) ? absint($_GET['height']) : 0;
// Only modify if we have valid dimensions
if ($width <= 0 || $height <= 0) {
return;
}
?>
<script>
jQuery(document).ready(function($) {
// Find all product links in Porto grid
$('.porto-tb-item.product a[href*="/product/"]').each(function() {
var $link = $(this);
var productUrl = $link.attr('href');
// Check if URL already has query parameters
if (productUrl.indexOf('?') === -1) {
// Add our parameters
$link.attr('href', productUrl + '?width=<?php echo $width; ?>&height=<?php echo $height; ?>');
}
});
});
</script>
<?php
}
@yokirahmada
Copy link
Author

yokirahmada commented Oct 5, 2025

  1. Main Purpose

This code creates a custom filtering system for a WooCommerce store, specifically for products with variable pricing based on size (e.g., curtains, blinds). It allows customers to enter their desired width and height on the shop page. The system then filters the product list to show only items available in those dimensions and dynamically updates the displayed price based on a pricing lookup table created with the WooCommerce Product Add-Ons Ultimate plugin and its Advanced Calculations add-on.

  1. Key Features & Workflow
  • Input Form (pewc_size_filter_shortcode): A shortcode [pewc_size_filter] generates an HTML form where users can input their desired width and height. This form submits the data via the GET method to the current page.
  • Product Filtering Logic (pewc_filter_products_by_size): This is the core logic, hooking into the main woocommerce_product_query. When width and height parameters are present in the URL, it iterates through all products. For each product, it checks its associated lookup table (created by the Add-Ons plugin) to see if it can accommodate the requested size.
  • "Nearest Size" Calculation (pewc_find_nearest_size): A key feature of this system is that if the user's exact size is not available, the logic intelligently finds the next largest available size from the product's pricing table. This ensures the customer always sees a valid and relevant product option.
  • Dynamic Price Display (pewc_update_price_based_on_size): On the shop page, this function intercepts the product price display. It dynamically calculates and shows the price for the user's selected dimensions, giving immediate and accurate pricing feedback. It also displays the actual matched dimensions below the price for transparency.
  • Seamless User Experience (pewc_modify_product_links_with_size_params): A small JavaScript snippet is added to the footer to automatically append the width and height parameters to all product links on the page, ensuring a consistent user experience.
  • Developer Debugging Tool: The code includes a built-in debugging function, activated by a URL parameter (?debug_size_filter). I created this tool to get a real-time view of how the filtering logic works, showing how each product's lookup table is analyzed and why certain products are matched. It proved essential for troubleshooting and verifying the complex logic.
  1. Technical Decisions & Best Practices
  • Hooks: I used standard WordPress and WooCommerce action and filter hooks (add_action, add_filter) to ensure the code is modular, upgrade-safe, and follows best practices.
  • Efficiency: The woocommerce_product_query action was chosen as it is the correct and most efficient way to modify the main product loop without breaking essential features like pagination.
  • Maintainability: The logic is separated into multiple, single-responsibility functions (e.g., pewc_get_table_price, pewc_find_nearest_size) for clarity, reusability, and easier maintenance.
  • Security: All user inputs from $_GET are sanitized using intval() and absint(), and outputs are escaped using esc_attr() and esc_html() to prevent security vulnerabilities like XSS.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment