Changeset 3422890
- Timestamp:
- 12/18/2025 01:24:57 PM (3 months ago)
- Location:
- 410-link-unlinker
- Files:
-
- 2 edited
- 3 copied
-
tags/1.0.6 (copied) (copied from 410-link-unlinker/trunk)
-
tags/1.0.6/410-link-unlinker.php (copied) (copied from 410-link-unlinker/trunk/410-link-unlinker.php) (16 diffs)
-
tags/1.0.6/readme.txt (copied) (copied from 410-link-unlinker/trunk/readme.txt) (2 diffs)
-
trunk/410-link-unlinker.php (modified) (16 diffs)
-
trunk/readme.txt (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
410-link-unlinker/tags/1.0.6/410-link-unlinker.php
r3421603 r3422890 3 3 * Plugin Name: 410 Link Unlinker 4 4 * Description: Removes anchor wrappers (<a href="…">…</a>) in posts/pages (and optionally postmeta) when links match a provided list (e.g., 410 Gone). Keeps the visible text. 5 * Version: 1.0. 55 * Version: 1.0.6 6 6 * Author: Arnjen 7 7 * License: GPL-2.0-or-later … … 17 17 const OPT_KEY = 'link410_urls'; 18 18 const NONCE = 'link410_nonce'; 19 const VER = '1.0. 5';19 const VER = '1.0.6'; 20 20 21 21 public function __construct() { … … 42 42 if ($u === '') { continue; } 43 43 if ($loose) { 44 // Add scheme if missing so wp_parse_url can identify the host 45 if (strpos($u, '://') === false) { 46 $u = 'https://' . $u; 47 } 44 48 $p = wp_parse_url($u); 45 49 if (!$p || empty($p['host'])) { continue; } … … 90 94 </p> 91 95 <p><label><input type="checkbox" name="link410_dry" value="1" checked> <?php esc_html_e('Dry-run (preview only; no saving)', '410-link-unlinker'); ?></label></p> 96 <p><label><input type="checkbox" name="link410_show_all" value="1"> <?php esc_html_e('Show all changes (not just first 10)', '410-link-unlinker'); ?></label></p> 92 97 <p> 93 98 <button class="button button-primary" name="link410_action" value="run"><?php esc_html_e('Scan / Unlink Now', '410-link-unlinker'); ?></button> … … 134 139 $dry = !empty($_POST['link410_dry']); 135 140 $include_meta = !empty($_POST['link410_include_meta']); 141 $show_all = !empty($_POST['link410_show_all']); 136 142 137 143 $urls = $this->get_saved_urls(); … … 141 147 } 142 148 143 $result = $this->process($urls, $limit, $offset, $dry, $include_meta );149 $result = $this->process($urls, $limit, $offset, $dry, $include_meta, $show_all); 144 150 add_action('admin_notices', function() use ($result, $dry){ 145 151 $mode = $dry ? __('Dry-run', '410-link-unlinker') : __('Updated', '410-link-unlinker'); … … 159 165 } 160 166 161 private function process(array $urls, int $limit, int $offset, bool $dry, bool $include_meta ) {167 private function process(array $urls, int $limit, int $offset, bool $dry, bool $include_meta, bool $show_all = false) { 162 168 global $wpdb; 163 169 … … 167 173 $posts = $wpdb->get_results( 168 174 $wpdb->prepare( 169 "SELECT ID, post_ content FROM {$wpdb->posts} WHERE post_type IN ('post','page') AND post_status = 'publish' ORDER BY ID ASC LIMIT %d OFFSET %d",175 "SELECT ID, post_name, post_content FROM {$wpdb->posts} WHERE post_type IN ('post','page') AND post_status = 'publish' ORDER BY ID ASC LIMIT %d OFFSET %d", 170 176 $limit, $offset 171 177 ), … … 184 190 $posts_changed++; 185 191 $anchors_removed += $removed; 186 if ($example && count($examples) < 5) { $examples[] = 'Post '.$row['ID'].': '.$example; } 192 // Fallback: extract matched URL from original if example wasn't captured 193 if (!$example) { 194 foreach ($patterns['href_regexes'] as $rx) { 195 if (preg_match('/href=["\']('.$rx.')["\']/', $orig, $href_match)) { 196 $example = 'Removed: '.(strlen($href_match[1]) > 80 ? substr($href_match[1], 0, 80).'...' : $href_match[1]); 197 break; 198 } 199 } 200 } 201 if ($show_all || count($examples) < 10) { $examples[] = '/'.$row['post_name'].'/: '.($example ?: 'Unknown match in content'); } 187 202 if (!$dry) { 188 203 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- Direct update required for bulk processing … … 199 214 $meta = $wpdb->get_results( 200 215 $wpdb->prepare( 201 "SELECT m eta_id, post_id, meta_key, meta_value FROM {$wpdb->postmeta} ORDER BYmeta_id ASC LIMIT %d OFFSET %d",216 "SELECT m.meta_id, m.post_id, m.meta_key, m.meta_value, p.post_name FROM {$wpdb->postmeta} m LEFT JOIN {$wpdb->posts} p ON m.post_id = p.ID ORDER BY m.meta_id ASC LIMIT %d OFFSET %d", 202 217 $limit, $offset 203 218 ), … … 208 223 $orig = (string) $m['meta_value']; 209 224 if ($orig === '' || strlen($orig) < 4) { continue; } 210 [$new, $removed, $example] = $this->unlink_in_html($orig, $patterns); 211 // Shortcode attribute neutralization 225 // Only process values that look like HTML (contain tags) 226 if (strpos($orig, '<') === false || strpos($orig, '>') === false) { continue; } 227 // Use full-URL-only patterns for postmeta (no relative path matching) 228 $meta_patterns = [ 229 'href_regexes' => $patterns['href_regexes_full'], 230 'href_regexes_raw' => $patterns['href_regexes_full'], 231 ]; 232 [$new, $removed, $example] = $this->unlink_in_html($orig, $meta_patterns); 233 // Shortcode attribute neutralization (if no anchors were removed) 212 234 if ($removed === 0) { 213 foreach ($patterns['href_regexes_ raw'] as $rx) {235 foreach ($patterns['href_regexes_full'] as $rx) { 214 236 $before = $new; 237 $matched_url = null; 238 $matched_attr = null; 215 239 $new = preg_replace_callback( 216 '/(\[?[a-z0-9_-]+\b[^]\n\r]*\b(url|link|href)=)\"('.$rx.')\"/i', 217 function($matches) use (&$example) { 218 if (!$example) { 219 $example = 'Neutralized shortcode attr: '.$matches[2].'="'.$matches[3].'"'; 220 } 240 '/(\[?[a-z0-9_-]+\b[^]\n\r]*\b(url|link|href)=)["\']('.$rx.')["\']/', 241 function($matches) use (&$matched_url, &$matched_attr) { 242 $matched_attr = $matches[2]; 243 $matched_url = $matches[3]; 221 244 return $matches[1].'"#"'; 222 245 }, 223 246 $new 224 247 ); 225 if ($new !== $before) { $removed++; } 248 if ($new !== null && $new !== $before) { 249 $removed++; 250 if (!$example && $matched_url) { 251 $example = 'Neutralized: '.$matched_attr.'="'.(strlen($matched_url) > 60 ? substr($matched_url, 0, 60).'...' : $matched_url).'"'; 252 } 253 } 226 254 } 227 255 } 228 256 if ($removed > 0) { 229 257 $meta_changed++; 230 if ($example && count($examples) < 5) { $examples[] = 'Meta '.$m['meta_id'].' (post '.$m['post_id'].'): '.$example; } 258 // Fallback: extract matched URL from original if example wasn't captured 259 if (!$example) { 260 // Try to find a URL from our patterns in the original content 261 foreach ($patterns['href_regexes_full'] as $rx) { 262 if (preg_match('/href=["\']('.$rx.')["\']/', $orig, $href_match)) { 263 $example = 'Removed: '.(strlen($href_match[1]) > 80 ? substr($href_match[1], 0, 80).'...' : $href_match[1]); 264 break; 265 } 266 if (preg_match('/(url|link)=["\']('.$rx.')["\']/', $orig, $url_match)) { 267 $example = 'Neutralized: '.$url_match[1].'="'.(strlen($url_match[2]) > 60 ? substr($url_match[2], 0, 60).'...' : $url_match[2]).'"'; 268 break; 269 } 270 } 271 } 272 if ($show_all || count($examples) < 10) { 273 $examples[] = '/'.($m['post_name'] ?: 'post-'.$m['post_id']).'/ ['.$m['meta_key'].']: '.($example ?: 'Modified'); 274 } 231 275 if (!$dry) { 232 276 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- Direct update required for bulk processing … … 251 295 $full_url_patterns = []; 252 296 $path_only_patterns = []; 253 $hosts_only = [];254 297 255 298 foreach ($urls as $u) { … … 266 309 } 267 310 268 // Build pattern for this specific host+path combination311 // Build individual pattern for this specific host+path combination 269 312 if ($path) { 270 313 // Match: https://host/path (with optional trailing slash and query string) … … 274 317 } else { 275 318 // Only host provided (no path) - match host with optional trailing slash 276 $hosts_only[] = $host; 277 } 278 } 279 280 $list = []; 281 282 // Add patterns for full URLs (host+path pairs) 283 if ($full_url_patterns) { 284 $list[] = '(?:' . implode('|', $full_url_patterns) . ')'; 285 } 286 287 // Add patterns for hosts without paths 288 if ($hosts_only) { 289 $host_rx = '(?:' . implode('|', array_map($esc, $hosts_only)) . ')'; 290 $list[] = 'https?:\/\/(?:www\.)?' . $host_rx . '(?:\/)?(?:\?[^"\']*)?'; 291 } 292 293 // Add relative path patterns 294 if ($path_only_patterns) { 295 $list[] = '(?:' . implode('|', $path_only_patterns) . ')'; 296 } 297 319 $full_url_patterns[] = 'https?:\/\/(?:www\.)?' . $esc($host) . '(?:\/)?(?:\?[^"\']*)?'; 320 } 321 } 322 323 // Return individual patterns (not combined) to avoid PCRE limits with large URL lists 298 324 return [ 299 'href_regexes' => $list, 300 'href_regexes_raw' => $list, 325 'href_regexes' => array_merge($full_url_patterns, $path_only_patterns), // For post_content 326 'href_regexes_raw' => array_merge($full_url_patterns, $path_only_patterns), 327 'href_regexes_full' => $full_url_patterns, // For postmeta (full URLs only) 301 328 ]; 302 329 } … … 332 359 $a->parentNode->replaceChild($frag, $a); 333 360 $removed++; 334 if (!$example) { $example = 'Removed link href="'.$href.'"'; }361 if (!$example) { $example = 'Removed: '.(strlen($href) > 80 ? substr($href, 0, 80).'...' : $href); } 335 362 } 336 363 } … … 341 368 foreach ($patterns['href_regexes'] as $rx) { 342 369 $before = $new; 343 $new = preg_replace('/<a\b[^>]*href="(?:'.$rx.')"[^>]*>(.*?)<\/a>/i', '$1', $new); 344 $new = preg_replace("/<a\\b[^>]*href='(?:".$rx.")'[^>]*>(.*?)<\/a>/i", '$1', $new); 345 if ($new !== $before) { $removed++; if (!$example) { $example = 'Removed link by regex'; } } 370 $matched_url = null; 371 $new = preg_replace_callback( 372 '/<a\b[^>]*href="('.$rx.')"[^>]*>(.*?)<\/a>/i', 373 function($matches) use (&$matched_url) { 374 if (!$matched_url) { $matched_url = $matches[1]; } 375 return $matches[2]; 376 }, 377 $new 378 ); 379 $new = preg_replace_callback( 380 "/<a\\b[^>]*href='(".$rx.")'[^>]*>(.*?)<\\/a>/i", 381 function($matches) use (&$matched_url) { 382 if (!$matched_url) { $matched_url = $matches[1]; } 383 return $matches[2]; 384 }, 385 $new 386 ); 387 if ($new !== $before) { 388 $removed++; 389 if (!$example && $matched_url) { 390 $example = 'Removed: '.(strlen($matched_url) > 80 ? substr($matched_url, 0, 80).'...' : $matched_url); 391 } 392 } 346 393 } 347 394 return [$new, $removed, $example]; -
410-link-unlinker/tags/1.0.6/readme.txt
r3421603 r3422890 3 3 Tags: links, 410, unlink, cleanup 4 4 Requires at least: 5.8 5 Tested up to: 6. 85 Tested up to: 6.9 6 6 Requires PHP: 7.4 7 Stable tag: 1.0. 57 Stable tag: 1.0.6 8 8 License: GPLv2 or later 9 9 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 24 24 25 25 == Changelog == 26 = 1.0.6 = 27 * Fix URL parsing to accept URLs without https:// prefix. 28 * Improved examples: show post/page URL slugs and meta_key names. 29 * Add "Show all changes" checkbox to list every modification instead of first 10. 30 * Fix shortcode matching to support both single and double quotes. 31 * Only process postmeta values that contain HTML tags (skip internal WP meta). 32 * Relative path matching now only applies to post_content, not postmeta (prevents false positives across domains). 33 * Fix PCRE regex limit error when processing large URL lists (600+ URLs now supported). 34 26 35 = 1.0.5 = 27 36 * Only scan published posts/pages (skip drafts for faster processing). -
410-link-unlinker/trunk/410-link-unlinker.php
r3421603 r3422890 3 3 * Plugin Name: 410 Link Unlinker 4 4 * Description: Removes anchor wrappers (<a href="…">…</a>) in posts/pages (and optionally postmeta) when links match a provided list (e.g., 410 Gone). Keeps the visible text. 5 * Version: 1.0. 55 * Version: 1.0.6 6 6 * Author: Arnjen 7 7 * License: GPL-2.0-or-later … … 17 17 const OPT_KEY = 'link410_urls'; 18 18 const NONCE = 'link410_nonce'; 19 const VER = '1.0. 5';19 const VER = '1.0.6'; 20 20 21 21 public function __construct() { … … 42 42 if ($u === '') { continue; } 43 43 if ($loose) { 44 // Add scheme if missing so wp_parse_url can identify the host 45 if (strpos($u, '://') === false) { 46 $u = 'https://' . $u; 47 } 44 48 $p = wp_parse_url($u); 45 49 if (!$p || empty($p['host'])) { continue; } … … 90 94 </p> 91 95 <p><label><input type="checkbox" name="link410_dry" value="1" checked> <?php esc_html_e('Dry-run (preview only; no saving)', '410-link-unlinker'); ?></label></p> 96 <p><label><input type="checkbox" name="link410_show_all" value="1"> <?php esc_html_e('Show all changes (not just first 10)', '410-link-unlinker'); ?></label></p> 92 97 <p> 93 98 <button class="button button-primary" name="link410_action" value="run"><?php esc_html_e('Scan / Unlink Now', '410-link-unlinker'); ?></button> … … 134 139 $dry = !empty($_POST['link410_dry']); 135 140 $include_meta = !empty($_POST['link410_include_meta']); 141 $show_all = !empty($_POST['link410_show_all']); 136 142 137 143 $urls = $this->get_saved_urls(); … … 141 147 } 142 148 143 $result = $this->process($urls, $limit, $offset, $dry, $include_meta );149 $result = $this->process($urls, $limit, $offset, $dry, $include_meta, $show_all); 144 150 add_action('admin_notices', function() use ($result, $dry){ 145 151 $mode = $dry ? __('Dry-run', '410-link-unlinker') : __('Updated', '410-link-unlinker'); … … 159 165 } 160 166 161 private function process(array $urls, int $limit, int $offset, bool $dry, bool $include_meta ) {167 private function process(array $urls, int $limit, int $offset, bool $dry, bool $include_meta, bool $show_all = false) { 162 168 global $wpdb; 163 169 … … 167 173 $posts = $wpdb->get_results( 168 174 $wpdb->prepare( 169 "SELECT ID, post_ content FROM {$wpdb->posts} WHERE post_type IN ('post','page') AND post_status = 'publish' ORDER BY ID ASC LIMIT %d OFFSET %d",175 "SELECT ID, post_name, post_content FROM {$wpdb->posts} WHERE post_type IN ('post','page') AND post_status = 'publish' ORDER BY ID ASC LIMIT %d OFFSET %d", 170 176 $limit, $offset 171 177 ), … … 184 190 $posts_changed++; 185 191 $anchors_removed += $removed; 186 if ($example && count($examples) < 5) { $examples[] = 'Post '.$row['ID'].': '.$example; } 192 // Fallback: extract matched URL from original if example wasn't captured 193 if (!$example) { 194 foreach ($patterns['href_regexes'] as $rx) { 195 if (preg_match('/href=["\']('.$rx.')["\']/', $orig, $href_match)) { 196 $example = 'Removed: '.(strlen($href_match[1]) > 80 ? substr($href_match[1], 0, 80).'...' : $href_match[1]); 197 break; 198 } 199 } 200 } 201 if ($show_all || count($examples) < 10) { $examples[] = '/'.$row['post_name'].'/: '.($example ?: 'Unknown match in content'); } 187 202 if (!$dry) { 188 203 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- Direct update required for bulk processing … … 199 214 $meta = $wpdb->get_results( 200 215 $wpdb->prepare( 201 "SELECT m eta_id, post_id, meta_key, meta_value FROM {$wpdb->postmeta} ORDER BYmeta_id ASC LIMIT %d OFFSET %d",216 "SELECT m.meta_id, m.post_id, m.meta_key, m.meta_value, p.post_name FROM {$wpdb->postmeta} m LEFT JOIN {$wpdb->posts} p ON m.post_id = p.ID ORDER BY m.meta_id ASC LIMIT %d OFFSET %d", 202 217 $limit, $offset 203 218 ), … … 208 223 $orig = (string) $m['meta_value']; 209 224 if ($orig === '' || strlen($orig) < 4) { continue; } 210 [$new, $removed, $example] = $this->unlink_in_html($orig, $patterns); 211 // Shortcode attribute neutralization 225 // Only process values that look like HTML (contain tags) 226 if (strpos($orig, '<') === false || strpos($orig, '>') === false) { continue; } 227 // Use full-URL-only patterns for postmeta (no relative path matching) 228 $meta_patterns = [ 229 'href_regexes' => $patterns['href_regexes_full'], 230 'href_regexes_raw' => $patterns['href_regexes_full'], 231 ]; 232 [$new, $removed, $example] = $this->unlink_in_html($orig, $meta_patterns); 233 // Shortcode attribute neutralization (if no anchors were removed) 212 234 if ($removed === 0) { 213 foreach ($patterns['href_regexes_ raw'] as $rx) {235 foreach ($patterns['href_regexes_full'] as $rx) { 214 236 $before = $new; 237 $matched_url = null; 238 $matched_attr = null; 215 239 $new = preg_replace_callback( 216 '/(\[?[a-z0-9_-]+\b[^]\n\r]*\b(url|link|href)=)\"('.$rx.')\"/i', 217 function($matches) use (&$example) { 218 if (!$example) { 219 $example = 'Neutralized shortcode attr: '.$matches[2].'="'.$matches[3].'"'; 220 } 240 '/(\[?[a-z0-9_-]+\b[^]\n\r]*\b(url|link|href)=)["\']('.$rx.')["\']/', 241 function($matches) use (&$matched_url, &$matched_attr) { 242 $matched_attr = $matches[2]; 243 $matched_url = $matches[3]; 221 244 return $matches[1].'"#"'; 222 245 }, 223 246 $new 224 247 ); 225 if ($new !== $before) { $removed++; } 248 if ($new !== null && $new !== $before) { 249 $removed++; 250 if (!$example && $matched_url) { 251 $example = 'Neutralized: '.$matched_attr.'="'.(strlen($matched_url) > 60 ? substr($matched_url, 0, 60).'...' : $matched_url).'"'; 252 } 253 } 226 254 } 227 255 } 228 256 if ($removed > 0) { 229 257 $meta_changed++; 230 if ($example && count($examples) < 5) { $examples[] = 'Meta '.$m['meta_id'].' (post '.$m['post_id'].'): '.$example; } 258 // Fallback: extract matched URL from original if example wasn't captured 259 if (!$example) { 260 // Try to find a URL from our patterns in the original content 261 foreach ($patterns['href_regexes_full'] as $rx) { 262 if (preg_match('/href=["\']('.$rx.')["\']/', $orig, $href_match)) { 263 $example = 'Removed: '.(strlen($href_match[1]) > 80 ? substr($href_match[1], 0, 80).'...' : $href_match[1]); 264 break; 265 } 266 if (preg_match('/(url|link)=["\']('.$rx.')["\']/', $orig, $url_match)) { 267 $example = 'Neutralized: '.$url_match[1].'="'.(strlen($url_match[2]) > 60 ? substr($url_match[2], 0, 60).'...' : $url_match[2]).'"'; 268 break; 269 } 270 } 271 } 272 if ($show_all || count($examples) < 10) { 273 $examples[] = '/'.($m['post_name'] ?: 'post-'.$m['post_id']).'/ ['.$m['meta_key'].']: '.($example ?: 'Modified'); 274 } 231 275 if (!$dry) { 232 276 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- Direct update required for bulk processing … … 251 295 $full_url_patterns = []; 252 296 $path_only_patterns = []; 253 $hosts_only = [];254 297 255 298 foreach ($urls as $u) { … … 266 309 } 267 310 268 // Build pattern for this specific host+path combination311 // Build individual pattern for this specific host+path combination 269 312 if ($path) { 270 313 // Match: https://host/path (with optional trailing slash and query string) … … 274 317 } else { 275 318 // Only host provided (no path) - match host with optional trailing slash 276 $hosts_only[] = $host; 277 } 278 } 279 280 $list = []; 281 282 // Add patterns for full URLs (host+path pairs) 283 if ($full_url_patterns) { 284 $list[] = '(?:' . implode('|', $full_url_patterns) . ')'; 285 } 286 287 // Add patterns for hosts without paths 288 if ($hosts_only) { 289 $host_rx = '(?:' . implode('|', array_map($esc, $hosts_only)) . ')'; 290 $list[] = 'https?:\/\/(?:www\.)?' . $host_rx . '(?:\/)?(?:\?[^"\']*)?'; 291 } 292 293 // Add relative path patterns 294 if ($path_only_patterns) { 295 $list[] = '(?:' . implode('|', $path_only_patterns) . ')'; 296 } 297 319 $full_url_patterns[] = 'https?:\/\/(?:www\.)?' . $esc($host) . '(?:\/)?(?:\?[^"\']*)?'; 320 } 321 } 322 323 // Return individual patterns (not combined) to avoid PCRE limits with large URL lists 298 324 return [ 299 'href_regexes' => $list, 300 'href_regexes_raw' => $list, 325 'href_regexes' => array_merge($full_url_patterns, $path_only_patterns), // For post_content 326 'href_regexes_raw' => array_merge($full_url_patterns, $path_only_patterns), 327 'href_regexes_full' => $full_url_patterns, // For postmeta (full URLs only) 301 328 ]; 302 329 } … … 332 359 $a->parentNode->replaceChild($frag, $a); 333 360 $removed++; 334 if (!$example) { $example = 'Removed link href="'.$href.'"'; }361 if (!$example) { $example = 'Removed: '.(strlen($href) > 80 ? substr($href, 0, 80).'...' : $href); } 335 362 } 336 363 } … … 341 368 foreach ($patterns['href_regexes'] as $rx) { 342 369 $before = $new; 343 $new = preg_replace('/<a\b[^>]*href="(?:'.$rx.')"[^>]*>(.*?)<\/a>/i', '$1', $new); 344 $new = preg_replace("/<a\\b[^>]*href='(?:".$rx.")'[^>]*>(.*?)<\/a>/i", '$1', $new); 345 if ($new !== $before) { $removed++; if (!$example) { $example = 'Removed link by regex'; } } 370 $matched_url = null; 371 $new = preg_replace_callback( 372 '/<a\b[^>]*href="('.$rx.')"[^>]*>(.*?)<\/a>/i', 373 function($matches) use (&$matched_url) { 374 if (!$matched_url) { $matched_url = $matches[1]; } 375 return $matches[2]; 376 }, 377 $new 378 ); 379 $new = preg_replace_callback( 380 "/<a\\b[^>]*href='(".$rx.")'[^>]*>(.*?)<\\/a>/i", 381 function($matches) use (&$matched_url) { 382 if (!$matched_url) { $matched_url = $matches[1]; } 383 return $matches[2]; 384 }, 385 $new 386 ); 387 if ($new !== $before) { 388 $removed++; 389 if (!$example && $matched_url) { 390 $example = 'Removed: '.(strlen($matched_url) > 80 ? substr($matched_url, 0, 80).'...' : $matched_url); 391 } 392 } 346 393 } 347 394 return [$new, $removed, $example]; -
410-link-unlinker/trunk/readme.txt
r3421603 r3422890 3 3 Tags: links, 410, unlink, cleanup 4 4 Requires at least: 5.8 5 Tested up to: 6. 85 Tested up to: 6.9 6 6 Requires PHP: 7.4 7 Stable tag: 1.0. 57 Stable tag: 1.0.6 8 8 License: GPLv2 or later 9 9 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 24 24 25 25 == Changelog == 26 = 1.0.6 = 27 * Fix URL parsing to accept URLs without https:// prefix. 28 * Improved examples: show post/page URL slugs and meta_key names. 29 * Add "Show all changes" checkbox to list every modification instead of first 10. 30 * Fix shortcode matching to support both single and double quotes. 31 * Only process postmeta values that contain HTML tags (skip internal WP meta). 32 * Relative path matching now only applies to post_content, not postmeta (prevents false positives across domains). 33 * Fix PCRE regex limit error when processing large URL lists (600+ URLs now supported). 34 26 35 = 1.0.5 = 27 36 * Only scan published posts/pages (skip drafts for faster processing).
Note: See TracChangeset
for help on using the changeset viewer.