Changeset 3469558
- Timestamp:
- 02/25/2026 02:54:12 PM (4 weeks ago)
- Location:
- transfer-brands-for-woocommerce
- Files:
-
- 8 edited
- 1 copied
-
tags/3.0.9 (copied) (copied from transfer-brands-for-woocommerce/trunk)
-
tags/3.0.9/CHANGELOG.md (modified) (1 diff)
-
tags/3.0.9/includes/class-transfer.php (modified) (6 diffs)
-
tags/3.0.9/readme.txt (modified) (3 diffs)
-
tags/3.0.9/transfer-brands-for-woocommerce.php (modified) (2 diffs)
-
trunk/CHANGELOG.md (modified) (1 diff)
-
trunk/includes/class-transfer.php (modified) (6 diffs)
-
trunk/readme.txt (modified) (3 diffs)
-
trunk/transfer-brands-for-woocommerce.php (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
transfer-brands-for-woocommerce/tags/3.0.9/CHANGELOG.md
r3456547 r3469558 5 5 The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 6 and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 8 ## [3.0.9] - 2026-02-25 9 10 ### Fixed 11 - **CRITICAL**: Brand transfer now works correctly on sites with Redis/Memcached persistent object cache 12 - Replaced `get_terms()` and `wp_count_terms()` with direct `$wpdb` queries in `process_terms_batch()` to bypass the `WP_Term_Query` cache layer (`term-queries` group) that `clean_taxonomy_cache()` does not invalidate 13 - Added `wp_cache_delete('last_changed', 'terms')` before `term_exists()` and `wp_insert_term()` to prevent stale destination taxonomy lookups 14 - Potential division by zero in progress percentage calculation when source term count is zero 15 16 ### Improved 17 - Consistent use of local `$destination_taxonomy` variable instead of repeated `$this->core->get_option()` calls in term creation 7 18 8 19 ## [3.0.8] - 2026-02-08 -
transfer-brands-for-woocommerce/tags/3.0.9/includes/class-transfer.php
r3456547 r3469558 32 32 */ 33 33 public function process_terms_batch($offset = 0) { 34 global $wpdb; 35 34 36 $source_taxonomy = $this->core->get_option('source_taxonomy'); 35 37 $destination_taxonomy = $this->core->get_option('destination_taxonomy'); … … 56 58 } 57 59 58 // Get total count first (cached after first call) 59 $total = wp_count_terms([ 60 'taxonomy' => $source_taxonomy, 61 'hide_empty' => false 62 ]); 63 64 if (is_wp_error($total)) { 65 $this->core->add_debug("Error counting terms", [ 66 'error' => $total->get_error_message() 67 ]); 68 return [ 69 'success' => false, 70 'message' => 'Error counting terms: ' . $total->get_error_message() 71 ]; 72 } 73 74 $total = (int) $total; 75 76 // Clear term cache to prevent stale results between AJAX batch calls 77 // This is critical for sites using persistent object cache (Redis, Memcached) 78 clean_taxonomy_cache($source_taxonomy); 79 80 // Get only ONE term at the current offset (memory efficient) 81 $terms = get_terms([ 82 'taxonomy' => $source_taxonomy, 83 'hide_empty' => false, 84 'number' => 1, 85 'offset' => $offset, 86 'orderby' => 'term_id', 87 'order' => 'ASC' 88 ]); 89 90 if (is_wp_error($terms)) { 91 $this->core->add_debug("Error getting terms", [ 92 'error' => $terms->get_error_message() 93 ]); 94 return [ 95 'success' => false, 96 'message' => 'Error getting terms: ' . $terms->get_error_message() 97 ]; 98 } 99 100 if (!empty($terms)) { 101 $term = $terms[0]; 60 // Direct DB query for total count — bypasses persistent object cache (Redis, Memcached) 61 // This prevents stale counts that could affect progress tracking 62 $total = (int) $wpdb->get_var($wpdb->prepare( 63 "SELECT COUNT(*) FROM {$wpdb->term_taxonomy} WHERE taxonomy = %s", 64 $source_taxonomy 65 )); 66 67 // Direct DB query for term fetch — bypasses persistent object cache entirely 68 // This is the critical fix: get_terms() uses WP_Term_Query which caches results 69 // in the 'term-queries' group. clean_taxonomy_cache() does NOT invalidate this 70 // cache group, causing stale/empty results on Redis/Memcached sites after the 71 // first batch processes and wp_insert_term() modifies cache timestamps. 72 $term = $wpdb->get_row($wpdb->prepare( 73 "SELECT t.term_id, t.name, t.slug, tt.description 74 FROM {$wpdb->terms} AS t 75 INNER JOIN {$wpdb->term_taxonomy} AS tt ON t.term_id = tt.term_id 76 WHERE tt.taxonomy = %s 77 ORDER BY t.term_id ASC 78 LIMIT 1 OFFSET %d", 79 $source_taxonomy, 80 $offset 81 )); 82 83 if ($term) { 102 84 $log_message = ''; 103 85 … … 112 94 113 95 $offset++; 114 $percent = min(45, round(($offset / $total) * 40) + 5);96 $percent = ($total > 0) ? min(45, round(($offset / $total) * 40) + 5) : 45; 115 97 116 98 return [ … … 125 107 } 126 108 109 // Invalidate term query cache before destination taxonomy operations 110 // This ensures term_exists() and wp_insert_term() get fresh results 111 // and prevents stale lookups on persistent object cache sites 112 wp_cache_delete('last_changed', 'terms'); 113 clean_taxonomy_cache($destination_taxonomy); 114 127 115 // Create or get new term - PRESERVE ORIGINAL SLUG for SEO 128 $new = term_exists($term->name, $ this->core->get_option('destination_taxonomy'));116 $new = term_exists($term->name, $destination_taxonomy); 129 117 if (!$new) { 130 $new = wp_insert_term($term->name, $ this->core->get_option('destination_taxonomy'), [118 $new = wp_insert_term($term->name, $destination_taxonomy, [ 131 119 'slug' => $term->slug, // Preserve original slug for SEO/URL preservation 132 120 'description' => $term->description … … 147 135 148 136 $offset++; 149 $percent = min(45, round(($offset / $total) * 40) + 5);137 $percent = ($total > 0) ? min(45, round(($offset / $total) * 40) + 5) : 45; 150 138 151 139 return [ … … 182 170 183 171 $offset++; 184 $percent = min(45, round(($offset / $total) * 40) + 5);172 $percent = ($total > 0) ? min(45, round(($offset / $total) * 40) + 5) : 45; 185 173 186 174 return [ -
transfer-brands-for-woocommerce/tags/3.0.9/readme.txt
r3456547 r3469558 4 4 Requires at least: 6.0 5 5 Tested up to: 6.9 6 Stable tag: 3.0. 86 Stable tag: 3.0.9 7 7 Requires PHP: 7.4 8 8 License: GPLv2 or later … … 130 130 131 131 == Changelog == 132 133 = 3.0.9 = 134 * **Fixed**: Critical - Brand transfer now works correctly on sites with Redis/Memcached persistent object cache 135 * **Fixed**: Replaced `get_terms()` and `wp_count_terms()` with direct database queries in term batch processing to bypass `WP_Term_Query` cache layer that `clean_taxonomy_cache()` does not invalidate 136 * **Fixed**: Added `wp_cache_delete('last_changed', 'terms')` before destination taxonomy operations to prevent stale `term_exists()` lookups 137 * **Fixed**: Potential division by zero in progress percentage when term count is zero 138 * **Improved**: Consistent use of `$destination_taxonomy` variable in `wp_insert_term()` call 132 139 133 140 = 3.0.8 = … … 350 357 == Upgrade Notice == 351 358 359 = 3.0.9 = 360 **Critical fix for Redis/Memcached sites**: Resolves the persistent issue where only the first brand transfers on sites using persistent object cache. The v3.0.8 fix (`clean_taxonomy_cache()`) was insufficient — it does not invalidate the `WP_Term_Query` cache group. This update bypasses the WordPress cache layer entirely with direct database queries. No need to disable Redis. Strongly recommended for all users. 361 352 362 = 3.0.8 = 353 363 **Critical bugfix**: Fixes issue where only the first brand transfers from PWB (Perfect WooCommerce Brands). Term creation errors no longer halt the entire transfer. Added cache clearing for persistent object cache compatibility. Strongly recommended for all users migrating from PWB. -
transfer-brands-for-woocommerce/tags/3.0.9/transfer-brands-for-woocommerce.php
r3456547 r3469558 4 4 * Plugin URI: https://pluginatlas.com/transfer-brands-for-woocommerce 5 5 * Description: Official WooCommerce 9.6 brand migration tool. Transfer from Perfect Brands, YITH, or custom attributes with backup and image support. 6 * Version: 3.0. 86 * Version: 3.0.9 7 7 * Requires at least: 6.0 8 8 * Requires PHP: 7.4 … … 36 36 37 37 // Define plugin constants 38 define('TBFW_VERSION', '3.0. 8');38 define('TBFW_VERSION', '3.0.9'); 39 39 define('TBFW_PLUGIN_DIR', plugin_dir_path(__FILE__)); 40 40 define('TBFW_PLUGIN_URL', plugin_dir_url(__FILE__)); -
transfer-brands-for-woocommerce/trunk/CHANGELOG.md
r3456547 r3469558 5 5 The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 6 and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 8 ## [3.0.9] - 2026-02-25 9 10 ### Fixed 11 - **CRITICAL**: Brand transfer now works correctly on sites with Redis/Memcached persistent object cache 12 - Replaced `get_terms()` and `wp_count_terms()` with direct `$wpdb` queries in `process_terms_batch()` to bypass the `WP_Term_Query` cache layer (`term-queries` group) that `clean_taxonomy_cache()` does not invalidate 13 - Added `wp_cache_delete('last_changed', 'terms')` before `term_exists()` and `wp_insert_term()` to prevent stale destination taxonomy lookups 14 - Potential division by zero in progress percentage calculation when source term count is zero 15 16 ### Improved 17 - Consistent use of local `$destination_taxonomy` variable instead of repeated `$this->core->get_option()` calls in term creation 7 18 8 19 ## [3.0.8] - 2026-02-08 -
transfer-brands-for-woocommerce/trunk/includes/class-transfer.php
r3456547 r3469558 32 32 */ 33 33 public function process_terms_batch($offset = 0) { 34 global $wpdb; 35 34 36 $source_taxonomy = $this->core->get_option('source_taxonomy'); 35 37 $destination_taxonomy = $this->core->get_option('destination_taxonomy'); … … 56 58 } 57 59 58 // Get total count first (cached after first call) 59 $total = wp_count_terms([ 60 'taxonomy' => $source_taxonomy, 61 'hide_empty' => false 62 ]); 63 64 if (is_wp_error($total)) { 65 $this->core->add_debug("Error counting terms", [ 66 'error' => $total->get_error_message() 67 ]); 68 return [ 69 'success' => false, 70 'message' => 'Error counting terms: ' . $total->get_error_message() 71 ]; 72 } 73 74 $total = (int) $total; 75 76 // Clear term cache to prevent stale results between AJAX batch calls 77 // This is critical for sites using persistent object cache (Redis, Memcached) 78 clean_taxonomy_cache($source_taxonomy); 79 80 // Get only ONE term at the current offset (memory efficient) 81 $terms = get_terms([ 82 'taxonomy' => $source_taxonomy, 83 'hide_empty' => false, 84 'number' => 1, 85 'offset' => $offset, 86 'orderby' => 'term_id', 87 'order' => 'ASC' 88 ]); 89 90 if (is_wp_error($terms)) { 91 $this->core->add_debug("Error getting terms", [ 92 'error' => $terms->get_error_message() 93 ]); 94 return [ 95 'success' => false, 96 'message' => 'Error getting terms: ' . $terms->get_error_message() 97 ]; 98 } 99 100 if (!empty($terms)) { 101 $term = $terms[0]; 60 // Direct DB query for total count — bypasses persistent object cache (Redis, Memcached) 61 // This prevents stale counts that could affect progress tracking 62 $total = (int) $wpdb->get_var($wpdb->prepare( 63 "SELECT COUNT(*) FROM {$wpdb->term_taxonomy} WHERE taxonomy = %s", 64 $source_taxonomy 65 )); 66 67 // Direct DB query for term fetch — bypasses persistent object cache entirely 68 // This is the critical fix: get_terms() uses WP_Term_Query which caches results 69 // in the 'term-queries' group. clean_taxonomy_cache() does NOT invalidate this 70 // cache group, causing stale/empty results on Redis/Memcached sites after the 71 // first batch processes and wp_insert_term() modifies cache timestamps. 72 $term = $wpdb->get_row($wpdb->prepare( 73 "SELECT t.term_id, t.name, t.slug, tt.description 74 FROM {$wpdb->terms} AS t 75 INNER JOIN {$wpdb->term_taxonomy} AS tt ON t.term_id = tt.term_id 76 WHERE tt.taxonomy = %s 77 ORDER BY t.term_id ASC 78 LIMIT 1 OFFSET %d", 79 $source_taxonomy, 80 $offset 81 )); 82 83 if ($term) { 102 84 $log_message = ''; 103 85 … … 112 94 113 95 $offset++; 114 $percent = min(45, round(($offset / $total) * 40) + 5);96 $percent = ($total > 0) ? min(45, round(($offset / $total) * 40) + 5) : 45; 115 97 116 98 return [ … … 125 107 } 126 108 109 // Invalidate term query cache before destination taxonomy operations 110 // This ensures term_exists() and wp_insert_term() get fresh results 111 // and prevents stale lookups on persistent object cache sites 112 wp_cache_delete('last_changed', 'terms'); 113 clean_taxonomy_cache($destination_taxonomy); 114 127 115 // Create or get new term - PRESERVE ORIGINAL SLUG for SEO 128 $new = term_exists($term->name, $ this->core->get_option('destination_taxonomy'));116 $new = term_exists($term->name, $destination_taxonomy); 129 117 if (!$new) { 130 $new = wp_insert_term($term->name, $ this->core->get_option('destination_taxonomy'), [118 $new = wp_insert_term($term->name, $destination_taxonomy, [ 131 119 'slug' => $term->slug, // Preserve original slug for SEO/URL preservation 132 120 'description' => $term->description … … 147 135 148 136 $offset++; 149 $percent = min(45, round(($offset / $total) * 40) + 5);137 $percent = ($total > 0) ? min(45, round(($offset / $total) * 40) + 5) : 45; 150 138 151 139 return [ … … 182 170 183 171 $offset++; 184 $percent = min(45, round(($offset / $total) * 40) + 5);172 $percent = ($total > 0) ? min(45, round(($offset / $total) * 40) + 5) : 45; 185 173 186 174 return [ -
transfer-brands-for-woocommerce/trunk/readme.txt
r3456547 r3469558 4 4 Requires at least: 6.0 5 5 Tested up to: 6.9 6 Stable tag: 3.0. 86 Stable tag: 3.0.9 7 7 Requires PHP: 7.4 8 8 License: GPLv2 or later … … 130 130 131 131 == Changelog == 132 133 = 3.0.9 = 134 * **Fixed**: Critical - Brand transfer now works correctly on sites with Redis/Memcached persistent object cache 135 * **Fixed**: Replaced `get_terms()` and `wp_count_terms()` with direct database queries in term batch processing to bypass `WP_Term_Query` cache layer that `clean_taxonomy_cache()` does not invalidate 136 * **Fixed**: Added `wp_cache_delete('last_changed', 'terms')` before destination taxonomy operations to prevent stale `term_exists()` lookups 137 * **Fixed**: Potential division by zero in progress percentage when term count is zero 138 * **Improved**: Consistent use of `$destination_taxonomy` variable in `wp_insert_term()` call 132 139 133 140 = 3.0.8 = … … 350 357 == Upgrade Notice == 351 358 359 = 3.0.9 = 360 **Critical fix for Redis/Memcached sites**: Resolves the persistent issue where only the first brand transfers on sites using persistent object cache. The v3.0.8 fix (`clean_taxonomy_cache()`) was insufficient — it does not invalidate the `WP_Term_Query` cache group. This update bypasses the WordPress cache layer entirely with direct database queries. No need to disable Redis. Strongly recommended for all users. 361 352 362 = 3.0.8 = 353 363 **Critical bugfix**: Fixes issue where only the first brand transfers from PWB (Perfect WooCommerce Brands). Term creation errors no longer halt the entire transfer. Added cache clearing for persistent object cache compatibility. Strongly recommended for all users migrating from PWB. -
transfer-brands-for-woocommerce/trunk/transfer-brands-for-woocommerce.php
r3456547 r3469558 4 4 * Plugin URI: https://pluginatlas.com/transfer-brands-for-woocommerce 5 5 * Description: Official WooCommerce 9.6 brand migration tool. Transfer from Perfect Brands, YITH, or custom attributes with backup and image support. 6 * Version: 3.0. 86 * Version: 3.0.9 7 7 * Requires at least: 6.0 8 8 * Requires PHP: 7.4 … … 36 36 37 37 // Define plugin constants 38 define('TBFW_VERSION', '3.0. 8');38 define('TBFW_VERSION', '3.0.9'); 39 39 define('TBFW_PLUGIN_DIR', plugin_dir_path(__FILE__)); 40 40 define('TBFW_PLUGIN_URL', plugin_dir_url(__FILE__));
Note: See TracChangeset
for help on using the changeset viewer.