Last active
January 13, 2026 03:13
-
-
Save TanvirHasan19/de538ab369b1b21c95dc8ca27f80bea2 to your computer and use it in GitHub Desktop.
Alternative code for functions.php
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| /** | |
| * Add this code to your theme's functions.php file | |
| * | |
| * FINAL SOLUTION - Table Rate Shipping Cheapest Rate Fix | |
| * | |
| * This improved solution fixes the issue where Table Rate Shipping returns multiple rates | |
| * for products without shipping labels, and the feed incorrectly shows the most expensive rate. | |
| * | |
| * To enable debugging, add this line to wp-config.php (temporarily): | |
| * define( 'ADT_SHIPPING_FILTER_DEBUG', true ); | |
| * | |
| * IMPORTANT: After adding this code, clear all caches and regenerate the feed. | |
| */ | |
| /** | |
| * Filter shipping data to only include the cheapest shipping rate per country/region/postal_code | |
| * | |
| * @param array $shipping_data The shipping data array. | |
| * @param object $product The product object. | |
| * @param object $feed The feed object. | |
| * @return array Filtered shipping data with only cheapest rates. | |
| */ | |
| function adt_filter_cheapest_shipping_rate_final( $shipping_data, $product, $feed ) { | |
| // Early return if shipping data is empty or not an array | |
| if ( empty( $shipping_data ) || ! is_array( $shipping_data ) ) { | |
| return $shipping_data; | |
| } | |
| // If there's only one shipping rate, no need to filter | |
| if ( count( $shipping_data ) <= 1 ) { | |
| return $shipping_data; | |
| } | |
| // Enable debugging by setting this constant: define( 'ADT_SHIPPING_FILTER_DEBUG', true ); | |
| $debug = defined( 'ADT_SHIPPING_FILTER_DEBUG' ) && ADT_SHIPPING_FILTER_DEBUG; | |
| if ( $debug ) { | |
| $product_id = is_object( $product ) && method_exists( $product, 'get_id' ) ? $product->get_id() : 'unknown'; | |
| error_log( sprintf( | |
| '[ADT Shipping Filter] Processing %d shipping rates for product ID: %s', | |
| count( $shipping_data ), | |
| $product_id | |
| ) ); | |
| } | |
| // Group shipping rates by country, region, and postal_code combination | |
| $grouped_rates = array(); | |
| foreach ( $shipping_data as $index => $shipping ) { | |
| // Skip if not an array | |
| if ( ! is_array( $shipping ) ) { | |
| if ( $debug ) { | |
| error_log( sprintf( '[ADT Shipping Filter] Skipping non-array shipping data at index %d', $index ) ); | |
| } | |
| continue; | |
| } | |
| // Get country, region, and postal_code - handle various key formats | |
| $country = ''; | |
| $region = ''; | |
| $postal_code = ''; | |
| // Try different possible key names for country | |
| if ( isset( $shipping['country'] ) ) { | |
| $country = trim( (string) $shipping['country'] ); | |
| } | |
| // Try different possible key names for region/state | |
| if ( isset( $shipping['region'] ) ) { | |
| $region = trim( (string) $shipping['region'] ); | |
| } elseif ( isset( $shipping['state'] ) ) { | |
| $region = trim( (string) $shipping['state'] ); | |
| } | |
| // Try different possible key names for postal code | |
| if ( isset( $shipping['postal_code'] ) ) { | |
| $postal_code = trim( (string) $shipping['postal_code'] ); | |
| } elseif ( isset( $shipping['postcode'] ) ) { | |
| $postal_code = trim( (string) $shipping['postcode'] ); | |
| } | |
| // Create a unique key for country/region/postal_code combination | |
| // Use empty string for missing values to ensure proper grouping | |
| $key = $country . '|' . $region . '|' . $postal_code; | |
| // Extract numeric price from the price string | |
| $price_str = isset( $shipping['price'] ) ? $shipping['price'] : ''; | |
| $price = adt_extract_numeric_price_final( $price_str ); | |
| if ( $debug ) { | |
| error_log( sprintf( | |
| '[ADT Shipping Filter] Rate #%d - Country: "%s", Region: "%s", Postal: "%s", Price String: "%s", Price Numeric: %s', | |
| $index, | |
| $country, | |
| $region, | |
| $postal_code, | |
| $price_str, | |
| $price | |
| ) ); | |
| } | |
| // Validate price extraction | |
| if ( $price === PHP_FLOAT_MAX ) { | |
| if ( $debug ) { | |
| error_log( sprintf( | |
| '[ADT Shipping Filter] WARNING: Could not extract valid price from "%s" for rate #%d. Skipping.', | |
| $price_str, | |
| $index | |
| ) ); | |
| } | |
| continue; // Skip rates with invalid prices | |
| } | |
| // If we haven't seen this country/region/postal_code combo, or this rate is cheaper | |
| // Free shipping (price = 0) is always considered cheapest | |
| if ( ! isset( $grouped_rates[ $key ] ) ) { | |
| // First rate for this combination | |
| $grouped_rates[ $key ] = array( | |
| 'shipping' => $shipping, | |
| 'price_numeric' => $price, | |
| 'index' => $index, | |
| ); | |
| if ( $debug ) { | |
| error_log( sprintf( | |
| '[ADT Shipping Filter] First rate for key "%s" - Price: %s', | |
| $key, | |
| $price | |
| ) ); | |
| } | |
| } elseif ( $price < $grouped_rates[ $key ]['price_numeric'] ) { | |
| // This rate is cheaper, replace the existing one | |
| if ( $debug ) { | |
| error_log( sprintf( | |
| '[ADT Shipping Filter] Replacing rate for key "%s" - Old price: %s, New price: %s', | |
| $key, | |
| $grouped_rates[ $key ]['price_numeric'], | |
| $price | |
| ) ); | |
| } | |
| $grouped_rates[ $key ] = array( | |
| 'shipping' => $shipping, | |
| 'price_numeric' => $price, | |
| 'index' => $index, | |
| ); | |
| } elseif ( $debug ) { | |
| error_log( sprintf( | |
| '[ADT Shipping Filter] Keeping existing rate for key "%s" - Existing price: %s, New price: %s', | |
| $key, | |
| $grouped_rates[ $key ]['price_numeric'], | |
| $price | |
| ) ); | |
| } | |
| } | |
| // Rebuild the shipping data array with only the cheapest rates | |
| $filtered_shipping_data = array(); | |
| foreach ( $grouped_rates as $key => $grouped_rate ) { | |
| $filtered_shipping_data[] = $grouped_rate['shipping']; | |
| if ( $debug ) { | |
| error_log( sprintf( | |
| '[ADT Shipping Filter] Added cheapest rate for key "%s" - Price: %s', | |
| $key, | |
| $grouped_rate['price_numeric'] | |
| ) ); | |
| } | |
| } | |
| if ( $debug ) { | |
| $product_id = is_object( $product ) && method_exists( $product, 'get_id' ) ? $product->get_id() : 'unknown'; | |
| error_log( sprintf( | |
| '[ADT Shipping Filter] Filtered from %d rates to %d rates for product ID: %s', | |
| count( $shipping_data ), | |
| count( $filtered_shipping_data ), | |
| $product_id | |
| ) ); | |
| } | |
| return $filtered_shipping_data; | |
| } | |
| /** | |
| * Extract numeric price from price string - FINAL VERSION | |
| * Handles various formats like: | |
| * - "GBP 5.99" or "5.99 GBP" | |
| * - "5.99" (numeric only) | |
| * - "EUR 10,50" or "10,50 EUR" (European format) | |
| * - "1.000,50 EUR" (European with thousand separator) | |
| * - "1,000.50 USD" (US format with thousand separator) | |
| * - Empty strings or invalid formats | |
| * | |
| * @param string|float|int $price_str The price string or numeric value. | |
| * @return float The numeric price value, or PHP_FLOAT_MAX if extraction fails. | |
| */ | |
| function adt_extract_numeric_price_final( $price_str ) { | |
| // Handle numeric values directly | |
| if ( is_numeric( $price_str ) ) { | |
| $price = (float) $price_str; | |
| return $price >= 0 ? $price : PHP_FLOAT_MAX; | |
| } | |
| // Handle empty or non-string values | |
| if ( empty( $price_str ) || ! is_string( $price_str ) ) { | |
| return PHP_FLOAT_MAX; // Return max float if no price found | |
| } | |
| // Trim whitespace | |
| $price_str = trim( $price_str ); | |
| if ( empty( $price_str ) ) { | |
| return PHP_FLOAT_MAX; | |
| } | |
| // Remove currency symbols and text, keep only numbers and decimal separators (.,) | |
| // This handles formats like "GBP 5.99", "5.99 GBP", "EUR 10,50", etc. | |
| $cleaned = preg_replace( '/[^0-9.,\-+]/', '', $price_str ); | |
| if ( empty( $cleaned ) ) { | |
| return PHP_FLOAT_MAX; | |
| } | |
| // Handle negative prices (though unlikely for shipping) | |
| $is_negative = false; | |
| if ( strpos( $cleaned, '-' ) !== false ) { | |
| $is_negative = true; | |
| $cleaned = str_replace( '-', '', $cleaned ); | |
| } | |
| // Handle comma as decimal separator (European format) | |
| // Check if comma is used as decimal separator (e.g., "10,50" vs "1,000.50") | |
| if ( strpos( $cleaned, ',' ) !== false && strpos( $cleaned, '.' ) !== false ) { | |
| // Both comma and dot present - determine which is decimal separator | |
| $comma_pos = strrpos( $cleaned, ',' ); | |
| $dot_pos = strrpos( $cleaned, '.' ); | |
| if ( $comma_pos > $dot_pos ) { | |
| // Comma is decimal separator (e.g., "1.000,50") | |
| $cleaned = str_replace( '.', '', $cleaned ); | |
| $cleaned = str_replace( ',', '.', $cleaned ); | |
| } else { | |
| // Dot is decimal separator (e.g., "1,000.50") | |
| $cleaned = str_replace( ',', '', $cleaned ); | |
| } | |
| } elseif ( strpos( $cleaned, ',' ) !== false ) { | |
| // Only comma present - could be decimal separator or thousand separator | |
| // If there are 3+ digits after comma, it's likely a thousand separator | |
| $parts = explode( ',', $cleaned ); | |
| if ( count( $parts ) === 2 && strlen( $parts[1] ) <= 2 ) { | |
| // Comma is decimal separator (e.g., "10,50") | |
| $cleaned = str_replace( ',', '.', $cleaned ); | |
| } else { | |
| // Comma is thousand separator, remove it | |
| $cleaned = str_replace( ',', '', $cleaned ); | |
| } | |
| } | |
| // Extract the numeric value | |
| if ( ! is_numeric( $cleaned ) ) { | |
| return PHP_FLOAT_MAX; | |
| } | |
| $price = (float) $cleaned; | |
| // Apply negative sign if needed | |
| if ( $is_negative ) { | |
| $price = -$price; | |
| } | |
| // Return the price (including 0 for free shipping) | |
| // Only return max float if the price is negative (invalid for shipping) | |
| if ( $price < 0 ) { | |
| return PHP_FLOAT_MAX; | |
| } | |
| return $price; | |
| } | |
| // Hook into the shipping data filter | |
| // Priority 20 to run after other filters, but before final output | |
| // Use late priority to ensure it runs after all other modifications | |
| add_filter( 'adt_product_feed_shipping_data', 'adt_filter_cheapest_shipping_rate_final', 20, 3 ); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment