PluginProbe
Tag, Category, and Taxonomy Manager – Autotagger Automatically Add Terms / 3.51.0
Tag, Category, and Taxonomy Manager – Autotagger Automatically Add Terms v3.51.0
3.54.0 3.53.0 3.52.0 3.51.0 3.50.0 3.45.0 3.38.0 3.4.0 3.4.1 3.4.2 3.4.3 3.4.4 3.4.5 3.40.0 3.40.1 3.41.0 3.42.0 3.43.0 3.44.0 3.5.0 3.5.1 3.5.2 3.5.3 3.6.0 3.6.1 All 178 releases
simple-tags / inc / class.admin.manage.php

class.admin.manage.php in Tag, Category, and Taxonomy Manager – Autotagger Automatically Add Terms 3.51.0, at inc/class.admin.manage.php

1,708 lines 78.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 class SimpleTags_Admin_Manage
4 {
5 public const MENU_SLUG = 'st_options';
6
7 // class instance
8 public static $instance;
9
10 /**
11 * Constructor
12 *
13 * @return void
14 * @author WebFactory Ltd
15 */
16 public function __construct()
17 {
18 add_filter('set-screen-option', [ __CLASS__, 'set_screen' ], 10, 3);
19 // Admin menu
20 add_action('admin_menu', array( $this, 'admin_menu' ));
21
22 // Register taxo, parent method...
23 SimpleTags_Admin::register_taxonomy();
24
25 // Javascript
26 add_action('admin_enqueue_scripts', array( __CLASS__, 'admin_enqueue_scripts' ), 11);
27
28 //load ajax
29 add_action('wp_ajax_taxopress_check_delete_terms', array( $this, 'handle_taxopress_check_delete_terms_ajax'));
30 add_action('wp_ajax_taxopress_autocomplete_terms', [ $this, 'handle_taxopress_autocomplete_terms']);
31 add_action('wp_ajax_taxopress_merge_terms_preflight', [$this, 'taxopress_merge_terms_preflight']);
32 add_action('wp_ajax_taxopress_merge_terms_batch', [$this, 'taxopress_merge_terms_batch']);
33 add_action('wp_ajax_taxopress_merge_suggestions', [$this, 'handle_taxopress_merge_suggestions']);
34
35 }
36
37 /**
38 * Init somes JS and CSS need for this feature
39 *
40 * @return void
41 * @author WebFactory Ltd
42 */
43 public static function admin_enqueue_scripts()
44 {
45 wp_register_script('st-helper-manage', STAGS_URL . '/assets/js/helper-manage.js', array( 'jquery' ), STAGS_VERSION);
46
47 // add JS for manage click tags
48 if (isset($_GET['page']) && $_GET['page'] == 'st_manage') {
49 wp_enqueue_script('st-helper-manage');
50 }
51 }
52
53 public static function set_screen($status, $option, $value)
54 {
55 return $value;
56 }
57
58 /**
59 * Add WP admin menu for Tags
60 *
61 * @return void
62 * @author WebFactory Ltd
63 */
64 public function admin_menu()
65 {
66 $hook = add_submenu_page(
67 self::MENU_SLUG,
68 __('TaxoPress: Manage Terms', 'simple-tags'),
69 __('Manage Terms', 'simple-tags'),
70 'simple_tags',
71 'st_manage',
72 array(
73 $this,
74 'page_manage_tags',
75 )
76 );
77 }
78
79 /**
80 * Method for build the page HTML manage tags
81 *
82 * @return void
83 * @author WebFactory Ltd
84 */
85 public function page_manage_tags()
86 {
87 $default_tab = '';
88 // Control Post data
89 if (isset($_POST['term_action'])) {
90 if (!current_user_can('simple_tags')) {
91 add_settings_error(__CLASS__, __CLASS__, esc_html__('Permission denied!', 'simple-tags'), 'error taxopress-notice');
92 } elseif (! wp_verify_nonce(sanitize_text_field($_POST['term_nonce']), 'simpletags_admin')) { // Origination and intention
93
94 add_settings_error(__CLASS__, __CLASS__, esc_html__('Security problem. Try again.', 'simple-tags'), 'error taxopress-notice');
95 } elseif (! isset(SimpleTags_Admin::$taxonomy) || ! taxonomy_exists(SimpleTags_Admin::$taxonomy)) { // Valid taxo ?
96
97 add_settings_error(__CLASS__, __CLASS__, esc_html__('Missing valid taxonomy for work. Try again.', 'simple-tags'), 'error taxopress-notice');
98 } elseif ($_POST['term_action'] == 'renameterm') {
99 $taxonomy = isset($_POST['current_taxo']) ? sanitize_text_field($_POST['current_taxo']) : 'post_tag';
100 $post_type = isset($_POST['current_cpt']) ? sanitize_text_field($_POST['current_cpt']) : 'post';
101
102 SimpleTags_Admin::$taxonomy = $taxonomy;
103 SimpleTags_Admin::$post_type = $post_type;
104
105 $oldtag = isset($_POST['renameterm_old']) ? sanitize_text_field($_POST['renameterm_old']) : '';
106 $newtag = isset($_POST['renameterm_new']) ? sanitize_text_field($_POST['renameterm_new']) : '';
107 self::renameTerms($taxonomy, $oldtag, $newtag);
108 $default_tab = '.st-rename-terms';
109 } elseif ($_POST['term_action'] == 'mergeterm') {
110 $taxonomy = isset($_POST['current_taxo']) ? sanitize_text_field($_POST['current_taxo']) : 'post_tag';
111 $post_type = isset($_POST['current_cpt']) ? sanitize_text_field($_POST['current_cpt']) : 'post';
112
113 SimpleTags_Admin::$taxonomy = $taxonomy;
114 SimpleTags_Admin::$post_type = $post_type;
115
116 $oldtag = isset($_POST['renameterm_old']) ? sanitize_text_field($_POST['renameterm_old']) : '';
117 $newtag = isset($_POST['renameterm_new']) ? sanitize_text_field($_POST['renameterm_new']) : '';
118 $merge_type = isset($_POST['mergeterm_type']) ? sanitize_text_field($_POST['mergeterm_type']) : '';
119 self::mergeTerms($taxonomy, $oldtag, $newtag, $merge_type);
120 $default_tab = '.st-merge-terms';
121 } elseif ($_POST['term_action'] == 'addterm') {
122 $taxonomy = isset($_POST['current_taxo']) ? sanitize_text_field($_POST['current_taxo']) : 'post_tag';
123 $post_type = isset($_POST['current_cpt']) ? sanitize_text_field($_POST['current_cpt']) : 'post';
124
125 SimpleTags_Admin::$taxonomy = $taxonomy;
126 SimpleTags_Admin::$post_type = $post_type;
127
128 $oldtag = isset($_POST['addterm_match']) ? sanitize_text_field($_POST['addterm_match']) : '';
129 $newtag = isset($_POST['addterm_new']) ? sanitize_text_field($_POST['addterm_new']) : '';
130 self::addMatchTerms($taxonomy, $oldtag, $newtag);
131 $default_tab = '.st-add-terms';
132 } elseif ($_POST['term_action'] == 'removeterm') {
133 $taxonomy = isset($_POST['current_taxo']) ? sanitize_text_field($_POST['current_taxo']) : 'post_tag';
134 $post_type = isset($_POST['current_cpt']) ? sanitize_text_field($_POST['current_cpt']) : 'post';
135
136 SimpleTags_Admin::$taxonomy = $taxonomy;
137 SimpleTags_Admin::$post_type = $post_type;
138
139 $matchtag = isset($_POST['removeterm_match']) ? sanitize_text_field($_POST['removeterm_match']) : '';
140 $removetag = isset($_POST['remove_term']) ? sanitize_text_field($_POST['remove_term']) : '';
141 self::removeMatchTerms($taxonomy, $matchtag, $removetag);
142 $default_tab = '.st-remove-terms';
143 } elseif ($_POST['term_action'] == 'remove-rarelyterms') {
144 $taxonomy = isset($_POST['current_taxo']) ? sanitize_text_field($_POST['current_taxo']) : 'post_tag';
145 $post_type = isset($_POST['current_cpt']) ? sanitize_text_field($_POST['current_cpt']) : 'post';
146
147 SimpleTags_Admin::$taxonomy = $taxonomy;
148 SimpleTags_Admin::$post_type = $post_type;
149
150 self::removeRarelyUsed($taxonomy, (int) $_POST['number-rarely']);
151 $default_tab = '.st-delete-unuused-terms';
152 } /* elseif ( $_POST['term_action'] == 'editslug' ) {
153
154 $matchtag = (isset($_POST['tagname_match'])) ? $_POST['tagname_match'] : '';
155 $newslug = (isset($_POST['tagslug_new'])) ? $_POST['tagslug_new'] : '';
156 self::editTermSlug( SimpleTags_Admin::$taxonomy, $matchtag, $newslug );
157
158 }*/
159 }
160
161 if ($default_tab && !empty($default_tab)) {
162 //trigger default tab click on load
163 echo '<div class="load-st-default-tab" data-page="'.esc_attr($default_tab).'"></div>';
164 }
165 $active_tab_slug = isset($_GET['tab']) ? sanitize_text_field($_GET['tab']) : 'add-terms';
166
167 // Default order
168 if (! isset($_GET['order'])) {
169 $_GET['order'] = 'name-asc';
170 }
171
172 settings_errors(__CLASS__); ?>
173 <div class="clear"></div>
174 <div class="taxopress-block-wrap">
175 <div class="wrap st_wrap tagcloudui st-manage-terms-page admin-settings wrap st_wrap">
176
177 <h1><?php _e('Manage Terms', 'simple-tags'); ?>
178 </h1>
179 <div class="taxopress-description"><?php esc_html_e('This feature allows you to manage your content terms by adding, renaming, merging and deleting unused terms.', 'simple-tags'); ?></div>
180
181 <div class="clear"></div>
182
183 <hr class="wp-header-end">
184 <div class="clear"></div>
185
186 <div id="col-container" class="wp-clearfix">
187 <div class="col-wrap">
188 <div class="form-wrap">
189 <ul class="simple-tags-nav-tab-wrapper">
190 <li class="nav-tab <?php echo $active_tab_slug === 'add-terms' ? 'nav-tab-active' : ''; ?>" data-page=".st-add-terms">
191 <?php echo esc_html__('Add terms', 'simple-tags'); ?>
192 </li>
193 <li class="nav-tab <?php echo $active_tab_slug === 'remove-terms' ? 'nav-tab-active' : ''; ?>" data-page=".st-remove-terms">
194 <?php echo esc_html__('Remove terms', 'simple-tags'); ?>
195 </li>
196 <li class="nav-tab <?php echo $active_tab_slug === 'rename-terms' ? 'nav-tab-active' : ''; ?>" data-page=".st-rename-terms">
197 <?php echo esc_html__('Rename terms', 'simple-tags'); ?>
198 </li>
199 <li class="nav-tab <?php echo $active_tab_slug === 'merge-terms' ? 'nav-tab-active' : ''; ?>" data-page=".st-merge-terms">
200 <?php echo esc_html__('Merge terms', 'simple-tags'); ?>
201 </li>
202 <li class="nav-tab <?php echo $active_tab_slug === 'delete-unuused-terms' ? 'nav-tab-active' : ''; ?>" data-page=".st-delete-unuused-terms">
203 <?php echo esc_html__('Delete unused terms', 'simple-tags'); ?>
204 </li>
205 </ul>
206 <div class="clear"></div>
207
208
209
210 <table class="form-table">
211
212 <tr valign="top" class="auto-terms-content st-add-terms" style="<?php echo $active_tab_slug === 'add-terms' ? '' : 'display:none;'; ?>">
213 <td>
214 <?php SimpleTags_Admin::tabSelectorTaxonomy('add-terms', 'st_manage'); ?>
215 <h2><?php _e('Add Terms', 'simple-tags'); ?></h2>
216 <p><?php printf(esc_html__('This feature lets you add one or more new terms to all %s which match any of the terms given.', 'simple-tags'), esc_html(SimpleTags_Admin::$post_type_name)); ?></p>
217 <p><?php printf(esc_html__('Terms will be added to all %s If no "Term(s) to match" is specified.', 'simple-tags'), esc_html(SimpleTags_Admin::$post_type_name)); ?></p>
218
219 <fieldset>
220 <form action="" method="post">
221 <input type="hidden" name="term_action" value="addterm" />
222 <input type="hidden" name="term_nonce" value="<?php echo esc_attr(wp_create_nonce('simpletags_admin')); ?>" />
223 <input type="hidden" name="current_tab" value="add-terms" />
224 <input type="hidden" name="current_taxo" value="<?php echo esc_attr(get_option('add-terms_taxo')); ?>" />
225 <input type="hidden" name="current_cpt" value="<?php echo esc_attr(get_option('add-terms_cpt')); ?>" />
226
227 <p class="terms-type-options">
228 <label>
229 <input type="radio" id="addterm_type" class="addterm_type_all_posts" name="addterm_type" value="all_posts" checked="checked">
230 <?php printf(esc_html__('Add terms to all %s.', 'simple-tags'), esc_html(SimpleTags_Admin::$post_type_name)); ?>
231 </label><br>
232 <label>
233 <input type="radio" id="addterm_type" class="addterm_type_matched_only" name="addterm_type" value="matched_only">
234 <?php _e('Add terms only to posts with specific terms attached.', 'simple-tags'); ?>
235 </label>
236 </p>
237
238 <p class="terms-to-maatch-input" style="display: none;">
239 <label for="addterm_match"><?php _e('Term(s) to match:', 'simple-tags'); ?></label><br />
240 <textarea type="text" class="autocomplete-input tag-cloud-input taxopress-expandable-textarea add-terms-autocomplete" id="addterm_match" name="addterm_match" size="80" data-tab="add-terms"
241 data-taxo="<?php echo esc_attr(get_option('add-terms_taxo')); ?>"></textarea>
242 </p>
243
244 <p>
245 <label for="addterm_new"><?php _e('Term(s) to add:', 'simple-tags'); ?></label><br />
246 <textarea type="text" class="autocomplete-input taxopress-expandable-textarea add-terms-autocomplete" id="addterm_new" name="addterm_new" size="80" data-tab="add-terms"
247 data-taxo="<?php echo esc_attr(get_option('add-terms_taxo')); ?>"></textarea>
248 </p>
249
250 <input class="button-primary" type="submit" name="Add" value="<?php _e('Add', 'simple-tags'); ?>" />
251 </form>
252 </fieldset>
253 </td>
254 </tr>
255
256 <tr valign="top" class="auto-terms-content st-remove-terms" style="<?php echo $active_tab_slug === 'remove-terms' ? '' : 'display:none;'; ?>">
257 <td>
258 <?php SimpleTags_Admin::tabSelectorTaxonomy('remove-terms', 'st_manage'); ?>
259 <h2><?php _e('Remove Terms', 'simple-tags'); ?></h2>
260 <p><?php printf(esc_html__('This feature lets you remove one or more terms from all %s which match any of the terms given.', 'simple-tags'), esc_html(SimpleTags_Admin::$post_type_name)); ?></p>
261 <p><?php printf(esc_html__('Terms will be removed from all %s If no "Term(s) to match" is specified.', 'simple-tags'), esc_html(SimpleTags_Admin::$post_type_name)); ?></p>
262
263 <fieldset>
264 <form action="" method="post">
265 <input type="hidden" name="term_action" value="removeterm" />
266 <input type="hidden" name="term_nonce" value="<?php echo esc_attr(wp_create_nonce('simpletags_admin')); ?>" />
267 <input type="hidden" name="current_tab" value="remove-terms" />
268 <input type="hidden" name="current_taxo" value="<?php echo esc_attr(get_option('remove-terms_taxo')); ?>" />
269 <input type="hidden" name="current_cpt" value="<?php echo esc_attr(get_option('remove-terms_cpt')); ?>" />
270
271 <p class="terms-type-options">
272 <label>
273 <input type="radio" id="removeterm_type" class="removeterm_type_all_posts" name="removeterm_type" value="all_posts" checked="checked">
274 <?php printf(esc_html__('Remove terms from all %s.', 'simple-tags'), esc_html(SimpleTags_Admin::$post_type_name)); ?>
275 </label><br>
276 <label>
277 <input type="radio" id="removeterm_type" class="removeterm_type_matched_only" name="removeterm_type" value="matched_only">
278 <?php _e('Remove terms only from posts with specific terms attached.', 'simple-tags'); ?>
279 </label>
280 </p>
281
282 <p class="removeterms-to-match-input" style="display: none;">
283 <label for="removeterm_match"><?php _e('Term(s) to match:', 'simple-tags'); ?></label><br />
284 <textarea type="text" class="autocomplete-input tag-cloud-input taxopress-expandable-textarea remove-terms-autocomplete" id="removeterm_match" name="removeterm_match" size="80" data-tab="remove-terms"
285 data-taxo="<?php echo esc_attr(get_option('remove-terms_taxo')); ?>"></textarea>
286 </p>
287
288 <p>
289 <label for="remove_term"><?php _e('Term(s) to remove:', 'simple-tags'); ?></label><br />
290 <textarea type="text" class="autocomplete-input taxopress-expandable-textarea remove-terms-autocomplete" id="remove_term" name="remove_term" size="80" data-tab="remove-terms"
291 data-taxo="<?php echo esc_attr(get_option('remove-terms_taxo')); ?>"></textarea>
292 </p>
293
294 <input class="button-primary" type="submit" name="Remove" value="<?php _e('Remove', 'simple-tags'); ?>" />
295 </form>
296 </fieldset>
297 </td>
298 </tr>
299
300 <tr valign="top" class="auto-terms-content st-rename-terms" style="<?php echo $active_tab_slug === 'rename-terms' ? '' : 'display:none;'; ?>">
301 <td>
302 <?php SimpleTags_Admin::tabSelectorTaxonomy('rename-terms', 'st_manage'); ?>
303 <h2><?php _e('Rename Terms', 'simple-tags'); ?></h2>
304 <p><?php _e('Enter the terms to rename and their new names.', 'simple-tags'); ?></p>
305
306 <fieldset>
307 <form action="" method="post">
308 <input type="hidden" name="term_action" value="renameterm" />
309 <input type="hidden" name="term_nonce" value="<?php echo esc_attr(wp_create_nonce('simpletags_admin')); ?>" />
310 <input type="hidden" name="current_tab" value="rename-terms" />
311 <input type="hidden" name="current_taxo" value="<?php echo esc_attr(get_option('rename-terms_taxo')); ?>" />
312 <input type="hidden" name="current_cpt" value="<?php echo esc_attr(get_option('rename-terms_cpt')); ?>" />
313 <p>
314 <label for="renameterm_old"><?php _e('Term(s) to rename:', 'simple-tags'); ?></label><br />
315 <textarea type="text" class="autocomplete-input tag-cloud-input taxopress-expandable-textarea rename-terms-autocomplete" id="renameterm_old" name="renameterm_old" size="80" data-taxo="<?php echo esc_attr(get_option('rename-terms_taxo')); ?>"></textarea>
316 </p>
317
318 <p>
319 <label for="renameterm_new"><?php _e('New term name(s):', 'simple-tags'); ?></label><br />
320 <textarea type="text" class="autocomplete-input taxopress-expandable-textarea rename-terms-autocomplete" id="renameterm_new" name="renameterm_new" size="80" data-taxo="<?php echo esc_attr(get_option('rename-terms_taxo')); ?>"></textarea>
321 </p>
322
323 <input class="button-primary" type="submit" name="rename" value="<?php _e('Rename', 'simple-tags'); ?>" />
324 </form>
325 </fieldset>
326 </td>
327 </tr>
328
329 <tr valign="top" class="auto-terms-content st-merge-terms" style="<?php echo $active_tab_slug === 'merge-terms' ? '' : 'display:none;'; ?>">
330 <td>
331 <?php SimpleTags_Admin::tabSelectorTaxonomy('merge-terms', 'st_manage'); ?>
332 <h2><?php _e('Merge Terms', 'simple-tags'); ?></h2>
333 <p><?php esc_html_e('This feature will delete existing terms and replace them with another term.', 'simple-tags'); ?></p>
334
335 <fieldset>
336 <form action="" method="post" class="merge-terms-form">
337 <input type="hidden" name="term_action" value="mergeterm" />
338 <input type="hidden" name="term_nonce" value="<?php echo esc_attr(wp_create_nonce('simpletags_admin')); ?>" />
339 <input type="hidden" name="current_tab" value="merge-terms" />
340 <input type="hidden" name="current_taxo" value="<?php echo esc_attr(get_option('merge-terms_taxo')); ?>" />
341 <input type="hidden" name="current_cpt" value="<?php echo esc_attr(get_option('merge-terms_cpt')); ?>" />
342
343 <p class="terms-type-options">
344 <label><input type="radio" id="mergeterm_type" class="mergeterm_type_different_name" name="mergeterm_type" value="different_name" checked="checked"><?php _e('Merge terms with different name.', 'simple-tags'); ?></label><br>
345 <label><input type="radio" id="mergeterm_type" class="mergeterm_type_same_name" name="mergeterm_type" value="same_name"><?php esc_html_e('Merge terms with same name.', 'simple-tags'); ?></label>
346 </p>
347
348 <p>
349 <label for="renameterm_old"><?php _e('Term(s) to merge.', 'simple-tags'); ?></label><br />
350 <textarea type="text" class="autocomplete-input tag-cloud-input taxopress-expandable-textarea merge-feature-autocomplete" id="mergeterm_old" name="renameterm_old" size="80" data-taxo="<?php echo esc_attr(get_option('merge-terms_taxo')); ?>"></textarea>
351 </p>
352
353 <p class="new_name_input">
354 <label for="renameterm_new"><?php _e('New term. The Old terms will be deleted and any posts assigned to the old terms will be re-assigned to this term.', 'simple-tags'); ?></label><br />
355 <textarea type="text" class="autocomplete-input taxopress-expandable-textarea merge-feature-autocomplete" id="mergeterm_new" name="renameterm_new" size="80" data-taxo="<?php echo esc_attr(get_option('merge-terms_taxo')); ?>"></textarea>
356 </p>
357
358 <input class="suggest-merge-terms" type="button" id="suggest-merge-terms" value="<?php _e('Suggest Terms to Merge', 'simple-tags'); ?>" />
359 <input class="button-primary" type="submit" name="merge" id="merge-terms" value="<?php _e('Merge Terms', 'simple-tags'); ?>" />
360 <div id="merge-progress" style="margin-top: 10px;"></div>
361 </form>
362 </fieldset>
363 </td>
364 </tr>
365
366 <tr valign="top" class="auto-terms-content st-delete-unuused-terms" style="<?php echo $active_tab_slug === 'delete-unuused-terms' ? '' : 'display:none;'; ?>">
367 <td>
368 <?php SimpleTags_Admin::tabSelectorTaxonomy('delete-unuused-terms', 'st_manage'); ?>
369 <h2><?php esc_html_e('Remove rarely used terms', 'simple-tags'); ?></h2>
370 <p><?php esc_html_e('This feature allows you to remove rarely used terms.', 'simple-tags'); ?></p>
371 <p><?php printf(esc_html__('If you choose 5, Taxopress will delete all terms attached to less than 5 %s.', 'simple-tags'), esc_html(SimpleTags_Admin::$post_type_name)); ?></p>
372
373 <fieldset>
374 <form action="" method="post">
375 <input type="hidden" name="term_action" value="remove-rarelyterms" />
376 <input type="hidden" name="term_nonce" value="<?php echo esc_attr(wp_create_nonce('simpletags_admin')); ?>" />
377 <input type="hidden" name="current_tab" value="delete-unuused-terms" />
378 <input type="hidden" name="current_taxo" value="<?php echo esc_attr(get_option('delete-unuused-terms_taxo')); ?>" />
379 <input type="hidden" name="current_cpt" value="<?php echo esc_attr(get_option('delete-unuused-terms_cpt')); ?>" />
380
381 <p>
382 <label for="number-delete"><?php _e('Minimum number of uses for each term:', 'simple-tags'); ?></label><br />
383 <select name="number-rarely" id="number-delete">
384 <?php for ($i = 1; $i <= 100; $i++) : ?>
385 <option value="<?php echo esc_attr($i); ?>"><?php echo esc_html($i); ?></option>
386 <?php endfor; ?>
387 </select>
388 </p>
389
390 <label for="check-terms"><?php _e('Check how many terms will be deleted:', 'simple-tags'); ?></label><br />
391 <input style="margin-top: 2px;" id="check-terms-btn" class="button-primary" type="submit" name="Check" value="<?php esc_attr_e('Check Terms', 'simple-tags'); ?>" />
392 <div id="terms-feedback"></div>
393
394 <label for="terms-delete"><?php _e('Delete rarely used terms:', 'simple-tags'); ?></label><br />
395 <input style="margin-top: 2px;" class="button-secondary delete-unused-term" type="submit" name="Delete" value="<?php esc_attr_e('Delete Terms', 'simple-tags'); ?>" />
396 </form>
397 </fieldset>
398 </td>
399 </tr>
400
401 <?php /*
402 <tr valign="top">
403 <th scope="row"><strong><?php _e('Edit Term Slug', 'simple-tags'); ?></strong></th>
404 <td>
405 <p><?php _e('Enter the term name to edit and its new slug. <a href="http://codex.wordpress.org/Glossary#Slug">Slug definition</a>', 'simple-tags'); ?></p>
406
407 <fieldset>
408 <form action="" method="post">
409 <input type="hidden" name="taxo" value="<?php echo esc_attr(SimpleTags_Admin::$taxonomy); ?>" />
410 <input type="hidden" name="cpt" value="<?php echo esc_attr(SimpleTags_Admin::$post_type); ?>" />
411
412 <input type="hidden" name="term_action" value="editslug" />
413 <input type="hidden" name="term_nonce" value="<?php echo wp_create_nonce('simpletags_admin'); ?>" />
414
415 <p>
416 <label for="tagname_match"><?php _e('Term(s) to match:', 'simple-tags'); ?></label>
417 <br />
418 <input type="text" class="autocomplete-input" id="tagname_match" name="tagname_match" size="80" />
419 </p>
420
421 <p>
422 <label for="tagslug_new"><?php _e('Slug(s) to set:', 'simple-tags'); ?></label>
423 <br />
424 <input type="text" class="autocomplete-input" id="tagslug_new" name="tagslug_new" size="80" />
425 </p>
426
427 <input class="button-primary" type="submit" name="edit" value="<?php _e('Edit', 'simple-tags'); ?>" />
428 </form>
429 </fieldset>
430 </td>
431 </tr>
432 */
433 ?>
434
435 </table>
436
437 <div class="remodal" data-remodal-id="taxopress-modal-merge-warning"
438 data-remodal-options="hashTracking: false, closeOnOutsideClick: false">
439 <div class="taxopress-merge-warning-title">
440 <?php echo esc_html__('Multiple merge suggestions selected', 'simple-tags'); ?>
441 </div>
442 <div id="taxopress-modal-merge-warning-content">
443 <?php echo esc_html__(
444 'You have selected multiple merge suggestions. All selected terms will be merged into a single new term.',
445 'simple-tags'
446 ); ?>
447 </div>
448 <br>
449 <button id="taxopress-merge-warning-cancel" data-remodal-action="cancel" class="button button-secondary remodal-cancel">
450 <?php echo esc_html__('Cancel', 'simple-tags'); ?>
451 </button>
452 <button id="taxopress-merge-warning-confirm" class="button button-primary">
453 <?php echo esc_html__('Continue', 'simple-tags'); ?>
454 </button>
455 </div>
456
457
458
459 </div>
460 </div>
461
462
463 <div class="clear"></div>
464
465 </div>
466 </div>
467 <div class="taxopress-right-sidebar admin-settings-sidebar">
468 <?php do_action('taxopress_admin_after_sidebar'); ?>
469 </div>
470
471 </div>
472
473
474 <?php SimpleTags_Admin::printAdminFooter(); ?>
475
476
477
478 <?php
479 do_action('simpletags-manage_terms', SimpleTags_Admin::$taxonomy);
480 }
481
482 /**
483 * Method to merge tags
484 *
485 * @param string $taxonomy
486 * @param string $old
487 * @param string $new
488 *
489 * @return boolean
490 * @author olatechpro
491 */
492 public static function mergeTerms($taxonomy = 'post_tag', $old = '', $new = '', $merge_type = '')
493 {
494 // Helper function to extract term name (ignoring slug in brackets)
495 $extractTermName = function ($term) {
496 return trim(preg_replace('/\s*\(.*?\)$/', '', $term));
497 };
498
499 if ($merge_type === 'same_name') {
500 $old_terms = explode(',', $old);
501 $old_terms = array_map($extractTermName, $old_terms);
502 $old_terms = array_filter($old_terms, '_delete_empty_element');
503 $old_terms = array_values(array_unique(array_map('sanitize_text_field', $old_terms)));
504 $retained_slug_param = isset($_POST['retained_slug']) ? sanitize_title($_POST['retained_slug']) : '';
505
506 if (empty($old_terms)) {
507 add_settings_error(__CLASS__, __CLASS__, esc_html__('No terms provided for merging!', 'simple-tags'), 'error taxopress-notice');
508 return false;
509 }
510
511 $terms = [];
512 $terms_by_id = [];
513 foreach ($old_terms as $term_name) {
514 $term_objects = get_terms([
515 'taxonomy' => $taxonomy,
516 'name' => sanitize_text_field($term_name),
517 'hide_empty' => false,
518 ]);
519
520 if (is_array($term_objects) && count($term_objects) > 1) {
521 foreach ($term_objects as $term_object) {
522 $terms_by_id[(int) $term_object->term_id] = $term_object;
523 }
524 }
525 }
526
527 $terms = array_values($terms_by_id);
528
529 if (empty($terms)) {
530 add_settings_error(__CLASS__, __CLASS__, esc_html__('No terms with the same name found.', 'simple-tags'), 'error taxopress-notice');
531 return false;
532 }
533
534 $sort_term_name = reset($old_terms);
535 usort($terms, function ($a, $b) use ($sort_term_name, $retained_slug_param) {
536 // If a retained slug is provided, sort that term to the top
537 if ($retained_slug_param) {
538 if ($a->slug === $retained_slug_param) {
539 return -1;
540 }
541 if ($b->slug === $retained_slug_param) {
542 return 1;
543 }
544 }
545 // Score based on similarity to term name
546 similar_text($sort_term_name, $a->slug, $similarity_a);
547 similar_text($sort_term_name, $b->slug, $similarity_b);
548
549 if ($similarity_a === $similarity_b) {
550 // If similarity is the same, sort by length (shortest first)
551 return strlen($a->slug) - strlen($b->slug);
552 }
553
554 // Otherwise, sort by similarity (higher first)
555 return $similarity_b - $similarity_a;
556 });
557
558 // Retain the term with the highest similarity and shortest slug (first in sorted array)
559 $retained_term = $terms[0];
560 $retained_slug = $retained_term->slug;
561 $retained_id = $retained_term->term_id;
562
563 // Collect terms to delete
564 $terms_to_delete = array_filter($terms, function ($term) use ($retained_id) {
565 return $term->term_id !== $retained_id;
566 });
567
568 // Reassign objects and delete old terms (existing logic)
569 $terms_id = array_map(function ($term) {
570 return $term->term_id;
571 }, $terms_to_delete);
572
573 $objects_id = get_objects_in_term($terms_id, $taxonomy, ['fields' => 'ids']);
574 foreach ($objects_id as $object_id) {
575 // Check if the object already has the term assigned
576 $current_terms = wp_get_object_terms($object_id, $taxonomy, ['fields' => 'ids']);
577 if (!in_array($retained_id, $current_terms)) {
578 wp_set_object_terms($object_id, $retained_slug, $taxonomy, true);
579 }
580 }
581
582 foreach ($terms_to_delete as $term) {
583 wp_delete_term($term->term_id, $taxonomy);
584 }
585
586 // Clean caches
587 clean_object_term_cache($objects_id, $taxonomy);
588 clean_term_cache($terms_id, $taxonomy);
589
590 add_settings_error(__CLASS__, __CLASS__, sprintf(esc_html__('Merged term(s) with the same name "%s". %d posts updated.', 'simple-tags'), $retained_term->name, count($objects_id)), 'updated taxopress-notice');
591 return [
592 'success' => true,
593 'retained_slug' => $retained_slug,
594 'posts_updated' => count($objects_id),
595 'post_ids' => $objects_id,
596 'terms_merged' => count($terms_to_delete) + 1,
597 ];
598
599 } else {
600
601 if (trim(str_replace(',', '', stripslashes($new))) == '' && $merge_type !== 'same_name') {
602 add_settings_error(__CLASS__, __CLASS__, esc_html__('No new term specified!', 'simple-tags'), 'error taxopress-notice');
603
604 return false;
605 }
606
607 // String to array
608 $old_terms = explode(',', $old);
609 $new_terms = explode(',', $new);
610
611 $old_terms = array_map($extractTermName, $old_terms);
612 $new_terms = array_map($extractTermName, $new_terms);
613
614 // Remove empty element and trim
615 $old_terms = array_filter($old_terms, '_delete_empty_element');
616 $new_terms = array_filter($new_terms, '_delete_empty_element');
617 $old_terms = array_values(array_unique(array_map('sanitize_text_field', $old_terms)));
618 $new_terms = array_values(array_unique(array_map('sanitize_text_field', $new_terms)));
619 $common_elements = array_intersect($old_terms, $new_terms);
620
621 // If old/new tag are empty => exit !
622 if (empty($old_terms) || empty($new_terms)) {
623 add_settings_error(__CLASS__, __CLASS__, esc_html__('No new/old valid term specified!', 'simple-tags'), 'error taxopress-notice');
624
625 return false;
626 }
627
628 if (!empty($common_elements) && $merge_type !== 'different_name') {
629 add_settings_error(__CLASS__, __CLASS__, esc_html__('Term to merge and New Term must not contain same term.', 'simple-tags'), 'error taxopress-notice');
630
631 return false;
632 }
633
634 $counter = 0;
635 $unique_objects = [];
636 $terms_id = [];
637 if (count($new_terms) == 1) { // Merge
638 // Set new tag
639 $new_tag = sanitize_text_field($new_terms[0]);
640 if (empty($new_tag)) {
641 add_settings_error(__CLASS__, __CLASS__, esc_html__('No valid new term.', 'simple-tags'), 'error taxopress-notice');
642
643 return false;
644 }
645
646 // Ensure the new term exists or create it
647 $new_term = get_term_by('name', $new_tag, $taxonomy);
648 if (!$new_term) {
649 $new_term_info = wp_insert_term($new_tag, $taxonomy);
650 if (is_wp_error($new_term_info)) {
651 add_settings_error(__CLASS__, __CLASS__, esc_html__('Failed to create the new term.', 'simple-tags'), 'error taxopress-notice');
652 return false;
653 }
654 $new_term_id = $new_term_info['term_id'];
655 $new_term_slug = isset($new_term_info['slug']) ? $new_term_info['slug'] : sanitize_title($new_tag);
656 } else {
657 $new_term_id = $new_term->term_id;
658 $new_term_slug = $new_term->slug;
659 }
660
661 // Get terms ID from old terms names
662 $terms_id = array();
663 $found_terms = array();
664 foreach ((array) $old_terms as $old_tag) {
665 $term = get_term_by('name', addslashes(sanitize_text_field($old_tag)), $taxonomy);
666 if ($term) {
667 $terms_id[] = (int) $term->term_id;
668 $found_terms[] = $term->name;
669 }
670 }
671
672 if (empty($terms_id)) {
673 add_settings_error(__CLASS__, __CLASS__, esc_html__('No matching terms found to merge.', 'simple-tags'), 'error taxopress-notice');
674 return false;
675 }
676
677 // Get objects from terms ID
678 $objects_id = get_objects_in_term($terms_id, $taxonomy, ['fields' => 'ids']);
679
680 // Use a set to track unique post IDs
681 $unique_objects = [];
682
683 // Assign the new term to all posts associated with the old terms
684 foreach ((array) $objects_id as $object_id) {
685 // Check if the object already has the term assigned
686 $current_terms = wp_get_object_terms($object_id, $taxonomy, ['fields' => 'ids']);
687 if (!in_array($new_term_id, $current_terms)) {
688 wp_set_object_terms($object_id, $new_term_slug, $taxonomy, true);
689 }
690 $unique_objects[$object_id] = true; // Add to unique set
691 }
692
693 // Count unique posts
694 $counter = count($unique_objects);
695
696 // Delete old terms
697 foreach ((array) $terms_id as $term_id) {
698 wp_delete_term($term_id, $taxonomy);
699 }
700
701 // Test if term is also a category
702 /*
703 if ( is_term($new_tag, 'category') ) {
704 // Edit the slug to use the new term
705 self::editTermSlug( $new_tag, sanitize_title($new_tag) );
706 }
707 */
708
709 // Clean cache
710 clean_object_term_cache($objects_id, $taxonomy);
711 clean_term_cache($terms_id, $taxonomy);
712
713
714 if (empty($found_terms)) {
715 add_settings_error(__CLASS__, __CLASS__, esc_html__('No terms were merged (terms may not exist).', 'simple-tags'), 'error taxopress-notice');
716 } else {
717 $message = sprintf(
718 esc_html__('Successfully merged %1$d term(s) "%2$s" to "%3$s". %4$s posts updated.', 'simple-tags'),
719 count($found_terms),
720 implode(', ', $found_terms),
721 rtrim($new, ','),
722 $counter
723 );
724 add_settings_error(__CLASS__, __CLASS__, $message, 'updated taxopress-notice');
725 }
726 } else { // Error
727 add_settings_error(__CLASS__, __CLASS__, sprintf(esc_html__('Error. You need to enter a single term to merge to in new term name !', 'simple-tags'), $old), 'error taxopress-notice');
728 return false;
729 }
730
731 return [
732 'success' => true,
733 'merged_into' => $new_tag,
734 'posts_updated' => $counter,
735 'post_ids' => array_keys($unique_objects),
736 'terms_merged' => count($terms_id) + 1,
737 ];
738
739
740 }
741 }
742
743 /**
744 * Find terms with same names but different slugs
745 */
746 public static function getSameNameMergeSuggestions($taxonomy = 'post_tag')
747 {
748 global $wpdb;
749
750 $query = $wpdb->prepare("
751 SELECT t.name, COUNT(*) as count, GROUP_CONCAT(CONCAT(t.name, ' (', t.slug, ')') SEPARATOR ', ') as terms
752 FROM {$wpdb->terms} t
753 INNER JOIN {$wpdb->term_taxonomy} tt ON t.term_id = tt.term_id
754 WHERE tt.taxonomy = %s
755 GROUP BY t.name
756 HAVING COUNT(*) > 1
757 ORDER BY count DESC, t.name ASC
758 ", $taxonomy);
759
760 $results = $wpdb->get_results($query);
761
762 $show_slug = (int) SimpleTags_Plugin::get_option_value('enable_merge_terms_slug');
763
764 if (!$show_slug) {
765 foreach ($results as &$result) {
766 $result->terms = preg_replace('/\s*\([^)]+\)/', '', $result->terms);
767 }
768 }
769
770 return $results;
771 }
772
773 /**
774 * Find terms that might be candidates for merging based on similarity
775 */
776 public static function getDifferentNameMergeSuggestions($taxonomy = 'post_tag', $limit = 50)
777 {
778 global $wpdb;
779
780 $limit = min(max((int) $limit, 1), 50);
781
782 $terms = get_terms([
783 'taxonomy' => $taxonomy,
784 'hide_empty' => false,
785 'number' => $limit * 2,
786 'update_term_meta_cache' => false,
787 ]);
788
789 $show_slug = (int) SimpleTags_Plugin::get_option_value('enable_merge_terms_slug');
790
791 $suggestions = [];
792
793 foreach ($terms as $i => $term1) {
794 foreach ($terms as $j => $term2) {
795 if ($i >= $j) {
796 continue;
797 }
798
799 $similarity_score = 0;
800 $reasons = [];
801
802 // 1. Levenshtein distance (for typos)
803 $term1_name = strtolower($term1->name);
804 $term2_name = strtolower($term2->name);
805 if (abs(strlen($term1_name) - strlen($term2_name)) <= 2 && max(strlen($term1_name), strlen($term2_name)) <= 100) {
806 $levenshtein = levenshtein($term1_name, $term2_name);
807 if ($levenshtein <= 2 && $levenshtein > 0) {
808 $similarity_score += 40;
809 $reasons[] = esc_html__('Similar spelling', 'simple-tags');
810 }
811 }
812
813 // 2. Soundex (phonetic similarity)
814 if (soundex($term1->name) === soundex($term2->name)) {
815 $similarity_score += 30;
816 $reasons[] = esc_html__('Sounds similar', 'simple-tags');
817 }
818
819 // 3. Common words/partial matches
820 $words1 = explode(' ', strtolower($term1->name));
821 $words2 = explode(' ', strtolower($term2->name));
822 $common_words = array_intersect($words1, $words2);
823 if (!empty($common_words)) {
824 $similarity_score += count($common_words) * 15;
825 $reasons[] = sprintf(esc_html__('Shared words: %s', 'simple-tags'), implode(', ', $common_words));
826 }
827
828 // 4. Prefix/suffix similarity
829 if (strpos($term1->name, $term2->name) !== false || strpos($term2->name, $term1->name) !== false) {
830 $similarity_score += 25;
831 $reasons[] = esc_html__('One contains the other', 'simple-tags');
832 }
833
834 if ($similarity_score >= 30) {
835 $suggested_name = '';
836
837 // Get clean term names for comparison
838 $term1_clean = strtolower(trim($term1->name));
839 $term2_clean = strtolower(trim($term2->name));
840
841 if (!empty($common_words)) {
842 $suggested_name = ucfirst(implode(' ', $common_words));
843 } else {
844 // Use the shorter term as base
845 $suggested_name = strlen($term1->name) <= strlen($term2->name) ? $term1->name : $term2->name;
846 }
847
848 // let's make sure suggested name is different from both original terms
849 $suggested_clean = strtolower(trim($suggested_name));
850 if ($suggested_clean === $term1_clean || $suggested_clean === $term2_clean) {
851
852 if (!empty($common_words)) {
853 $suggested_name = ucfirst($common_words[0]);
854 } else {
855 $popular_term = ($term1->count >= $term2->count) ? $term1 : $term2;
856 $suggested_name = $popular_term->name;
857 }
858
859 $suggested_clean = strtolower(trim($suggested_name));
860 }
861
862 $term1_display = $show_slug ? $term1->name . ' (' . $term1->slug . ')' : $term1->name;
863 $term2_display = $show_slug ? $term2->name . ' (' . $term2->slug . ')' : $term2->name;
864
865 $suggestions[] = [
866 'term1' => $term1_display,
867 'term2' => $term2_display,
868 'score' => $similarity_score,
869 'reasons' => implode(', ', $reasons),
870 'suggested_name' => $suggested_name
871 ];
872
873 }
874 }
875 }
876
877 usort($suggestions, function ($a, $b) {
878 return $b['score'] - $a['score'];
879 });
880
881 return array_slice($suggestions, 0, $limit);
882 }
883
884 /**
885 * AJAX handler for merge suggestions
886 */
887 public function handle_taxopress_merge_suggestions()
888 {
889 if (!current_user_can('simple_tags')) {
890 wp_send_json_error('Permission denied');
891 }
892
893 if (!wp_verify_nonce($_POST['nonce'], 'simpletags_admin')) {
894 wp_send_json_error('Invalid nonce');
895 }
896
897 $taxonomy = get_option('merge-terms_taxo', 'post_tag');
898 $merge_type = sanitize_text_field($_POST['merge_type']);
899
900 if ($merge_type === 'same_name') {
901 $suggestions = self::getSameNameMergeSuggestions($taxonomy);
902 wp_send_json_success([
903 'type' => 'same_name',
904 'suggestions' => $suggestions
905 ]);
906 } else {
907 $suggestions = self::getDifferentNameMergeSuggestions($taxonomy);
908 wp_send_json_success([
909 'type' => 'different_name',
910 'suggestions' => $suggestions
911 ]);
912 }
913 }
914
915 private static function get_merge_preflight_term_ids($taxonomy, $old_terms_input, $merge_type)
916 {
917 $extractTermName = function ($term) {
918 return trim(preg_replace('/\s*\(.*?\)$/', '', $term));
919 };
920
921 $term_ids = [];
922
923 foreach ($old_terms_input as $term_name) {
924 $term_name_clean = sanitize_text_field($extractTermName($term_name));
925
926 if (empty($term_name_clean)) {
927 continue;
928 }
929
930 if ($merge_type === 'same_name') {
931 $matching_terms = get_terms([
932 'taxonomy' => $taxonomy,
933 'name' => $term_name_clean,
934 'hide_empty' => false,
935 'fields' => 'ids',
936 'update_term_meta_cache' => false,
937 ]);
938
939 if (!is_wp_error($matching_terms) && !empty($matching_terms)) {
940 foreach ($matching_terms as $term_id) {
941 $term_ids[] = (int) $term_id;
942 }
943
944 continue;
945 }
946 }
947
948 $term = get_term_by('name', $term_name_clean, $taxonomy);
949 if (!$term || is_wp_error($term)) {
950 $term = get_term_by('slug', sanitize_title($term_name_clean), $taxonomy);
951 }
952
953 if ($term && !is_wp_error($term)) {
954 $term_ids[] = (int) $term->term_id;
955 }
956 }
957
958 return array_values(array_unique(array_filter($term_ids)));
959 }
960
961 private static function count_objects_for_merge_terms($taxonomy, $term_ids)
962 {
963 global $wpdb;
964
965 if (empty($term_ids)) {
966 return 0;
967 }
968
969 $term_ids = array_values(array_unique(array_map('intval', $term_ids)));
970 $cache_key = 'merge_preflight_' . md5($taxonomy . ':' . implode(',', $term_ids));
971 $cached_count = wp_cache_get($cache_key, 'taxopress_terms');
972
973 if ($cached_count !== false) {
974 return (int) $cached_count;
975 }
976
977 $term_id_placeholders = implode(',', array_fill(0, count($term_ids), '%d'));
978 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
979 $term_taxonomy_query = $wpdb->prepare(
980 "SELECT term_taxonomy_id FROM {$wpdb->term_taxonomy} WHERE taxonomy = %s AND term_id IN ({$term_id_placeholders})",
981 array_merge([$taxonomy], $term_ids)
982 );
983
984 // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
985 $term_taxonomy_ids = $wpdb->get_col($term_taxonomy_query);
986
987 if (empty($term_taxonomy_ids)) {
988 wp_cache_set($cache_key, 0, 'taxopress_terms', MINUTE_IN_SECONDS);
989 return 0;
990 }
991
992 $term_taxonomy_ids = array_values(array_unique(array_map('intval', $term_taxonomy_ids)));
993 $term_taxonomy_id_placeholders = implode(',', array_fill(0, count($term_taxonomy_ids), '%d'));
994 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
995 $object_count_query = $wpdb->prepare(
996 "SELECT COUNT(DISTINCT object_id) FROM {$wpdb->term_relationships} WHERE term_taxonomy_id IN ({$term_taxonomy_id_placeholders})",
997 $term_taxonomy_ids
998 );
999
1000 // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
1001 $object_count = (int) $wpdb->get_var($object_count_query);
1002
1003 wp_cache_set($cache_key, $object_count, 'taxopress_terms', MINUTE_IN_SECONDS);
1004
1005 return $object_count;
1006 }
1007
1008 public static function taxopress_merge_terms_preflight()
1009 {
1010 $nonce = isset($_POST['nonce']) ? sanitize_text_field(wp_unslash($_POST['nonce'])) : '';
1011 if (empty($nonce) || !wp_verify_nonce($nonce, 'st-admin-js')) {
1012 wp_send_json_error(['message' => __('Security check failed.', 'simple-tags')], 403);
1013 wp_die();
1014 }
1015
1016 if (!current_user_can('simple_tags')) {
1017 wp_send_json_error(['message' => __('Permission denied.', 'simple-tags')], 403);
1018 wp_die();
1019 }
1020
1021 $taxonomy = isset($_POST['taxonomy']) ? sanitize_text_field(wp_unslash($_POST['taxonomy'])) : '';
1022 if (empty($taxonomy) || !taxonomy_exists($taxonomy)) {
1023 wp_send_json_error(['message' => __('Invalid taxonomy.', 'simple-tags')], 400);
1024 wp_die();
1025 }
1026
1027 $merge_type = isset($_POST['merge_type']) ? sanitize_text_field(wp_unslash($_POST['merge_type'])) : 'different_name';
1028 $old_terms_input = isset($_POST['old_terms']) ? array_map('sanitize_text_field', (array) wp_unslash($_POST['old_terms'])) : [];
1029
1030 $term_ids = self::get_merge_preflight_term_ids($taxonomy, $old_terms_input, $merge_type);
1031 $affected_posts_count = self::count_objects_for_merge_terms($taxonomy, $term_ids);
1032 $workload = count($term_ids) * $affected_posts_count;
1033 $ajax_workload_threshold = (int) apply_filters('taxopress_merge_terms_ajax_workload_threshold', 20);
1034
1035 wp_send_json_success([
1036 'terms_count' => count($term_ids),
1037 'affected_posts_count' => $affected_posts_count,
1038 'workload' => $workload,
1039 'use_ajax' => $workload > $ajax_workload_threshold,
1040 ]);
1041 }
1042
1043 public static function taxopress_merge_terms_batch()
1044 {
1045 $nonce = isset($_POST['nonce']) ? sanitize_text_field($_POST['nonce']) : '';
1046 if (empty($nonce) || !wp_verify_nonce($nonce, 'st-admin-js')) {
1047 wp_send_json_error(['message' => __('Security check failed.', 'simple-tags')], 403);
1048 wp_die();
1049 }
1050
1051 if (!current_user_can('simple_tags')) {
1052 wp_send_json_error(['message' => __('Permission denied.', 'simple-tags')], 403);
1053 wp_die();
1054 }
1055
1056 $taxonomy = isset($_POST['taxonomy']) ? sanitize_text_field($_POST['taxonomy']) : '';
1057 $new_term = isset($_POST['new_term']) ? sanitize_text_field($_POST['new_term']) : '';
1058 $merge_type = isset($_POST['merge_type']) ? sanitize_text_field($_POST['merge_type']) : 'different_name';
1059 $old_terms_input = isset($_POST['old_terms']) ? array_map('sanitize_text_field', (array) $_POST['old_terms']) : [];
1060
1061 $extractTermName = function ($term) {
1062 return trim(preg_replace('/\s*\(.*?\)$/', '', $term));
1063 };
1064
1065 $old_terms = [];
1066
1067 foreach ($old_terms_input as $term_name) {
1068 $term_name_clean = $extractTermName($term_name);
1069 $term = get_term_by('name', $term_name_clean, $taxonomy);
1070 if (!$term || is_wp_error($term)) {
1071 $term = get_term_by('slug', sanitize_title($term_name_clean), $taxonomy);
1072 }
1073 if ($term && !is_wp_error($term)) {
1074 $old_terms[] = $term->name;
1075 }
1076 }
1077
1078 $old_terms = array_values(array_unique($old_terms));
1079
1080 if (empty($old_terms)) {
1081 wp_send_json_error([
1082 'message' => __('Please enter a valid term. Merge cancelled.', 'simple-tags')
1083 ]);
1084 wp_die();
1085 }
1086
1087 if ($merge_type === 'different_name' && !empty($new_term)) {
1088 $old_terms = array_values(array_filter($old_terms, function ($term_name) use ($new_term) {
1089 return strtolower(trim($term_name)) !== strtolower(trim($new_term));
1090 }));
1091 }
1092
1093
1094 // Execute the merge
1095 $result = SimpleTags_Admin_Manage::mergeTerms($taxonomy, implode(',', $old_terms), $new_term, $merge_type);
1096
1097 if ($result === true || (is_array($result) && !empty($result['success']))) {
1098 $response = ['message' => __('Merge successful', 'simple-tags')];
1099
1100 if (is_array($result)) {
1101 $response = array_merge($response, $result);
1102 }
1103
1104 wp_send_json_success($response);
1105 } else {
1106 global $wp_settings_errors;
1107 $errors = [];
1108
1109 if (!empty($wp_settings_errors)) {
1110 foreach ($wp_settings_errors as $error) {
1111 if (!empty($error['message'])) {
1112 $errors[] = $error['message'];
1113 }
1114 }
1115 }
1116
1117 if (is_wp_error($result)) {
1118 $errors[] = $result->get_error_message();
1119 } elseif (is_array($result) && isset($result['message'])) {
1120 $errors[] = $result['message'];
1121 }
1122
1123 wp_send_json_error(['message' => implode(' ', $errors)]);
1124 }
1125
1126 wp_die();
1127 }
1128
1129 /**
1130 * Method for remove tags
1131 *
1132 * @param string $taxonomy
1133 * @param string $post_type
1134 * @param string $tag
1135 *
1136 * @return boolean
1137 * @author WebFactory Ltd
1138 */
1139 public static function removeTerms($taxonomy = 'post_tag', $post_type = 'posts', $new = '')
1140 {
1141 if (trim(str_replace(',', '', stripslashes($new))) == '') {
1142 add_settings_error(__CLASS__, __CLASS__, esc_html__('No term specified!', 'simple-tags'), 'error taxopress-notice');
1143
1144 return false;
1145 }
1146
1147 // String to array
1148 $new_terms = explode(',', $new);
1149
1150 // Remove empty element and trim
1151 $new_terms = array_filter($new_terms, '_delete_empty_element');
1152
1153 // If new tag are empty => exit !
1154 if (empty($new_terms)) {
1155 add_settings_error(__CLASS__, __CLASS__, esc_html__('No valid term specified!', 'simple-tags'), 'error taxopress-notice');
1156
1157 return false;
1158 }
1159
1160 $counter = 0;
1161 if (count($new_terms) > 0) {
1162 foreach ((array) $new_terms as $term) {
1163 $term = get_term_by('name', sanitize_text_field($term), $taxonomy);
1164 if (empty($term) || !is_object($term)) {
1165 continue;
1166 }
1167
1168 $term = $term->term_id;
1169
1170 $args = array(
1171 'post_type' => $post_type, // post_type
1172 'posts_per_page' => -1,
1173 'tax_query' => array(
1174 array(
1175 'taxonomy' => $taxonomy,
1176 'field' => 'id',
1177 'terms' => $term
1178 )
1179 )
1180 );
1181 $posts = get_posts($args);
1182 foreach ($posts as $post) {
1183 $remove = wp_remove_object_terms($post->ID, $term, $taxonomy);
1184 if ($remove) {
1185 clean_object_term_cache($post->ID, $taxonomy);
1186 clean_term_cache($term, $taxonomy);
1187 $counter++;
1188 }
1189 }
1190 }
1191
1192 if ($counter == 0) {
1193 add_settings_error(__CLASS__, __CLASS__, sprintf(esc_html__('This term is not associated with any %1$s.', 'simple-tags'), SimpleTags_Admin::$post_type_name), 'error taxopress-notice');
1194 } else {
1195 add_settings_error(__CLASS__, __CLASS__, sprintf(esc_html__('Removed term(s) "%1$s" from %2$s %3$s', 'simple-tags'), $new, $counter, SimpleTags_Admin::$post_type_name), 'updated taxopress-notice');
1196 }
1197 } else { // Error
1198 add_settings_error(__CLASS__, __CLASS__, sprintf(esc_html__('Error. No enough terms specified.', 'simple-tags'), $old), 'error taxopress-notice');
1199 }
1200
1201 return true;
1202 }
1203
1204 /**
1205 * Method for rename tags
1206 *
1207 * @param string $taxonomy
1208 * @param string $old
1209 * @param string $new
1210 *
1211 * @return boolean
1212 * @author WebFactory Ltd
1213 */
1214 public static function renameTerms($taxonomy = 'post_tag', $old = '', $new = '')
1215 {
1216 // Helper function to extract term name (ignoring slug in brackets)
1217 $extractTermName = function ($term) {
1218 return trim(preg_replace('/\s*\(.*?\)$/', '', $term));
1219 };
1220
1221 if (trim(str_replace(',', '', stripslashes($new))) == '') {
1222 add_settings_error(__CLASS__, __CLASS__, esc_html__('No new term specified!', 'simple-tags'), 'error taxopress-notice');
1223
1224 return false;
1225 }
1226
1227 // String to array
1228 $old_terms = explode(',', $old);
1229 $new_terms = explode(',', $new);
1230
1231 // Clean up terms by removing slugs
1232 $old_terms = array_map($extractTermName, $old_terms);
1233 $new_terms = array_map($extractTermName, $new_terms);
1234
1235 // Remove empty element and trim
1236 $old_terms = array_filter($old_terms, '_delete_empty_element');
1237 $new_terms = array_filter($new_terms, '_delete_empty_element');
1238
1239 // If old/new tag are empty => exit !
1240 if (empty($old_terms) || empty($new_terms)) {
1241 add_settings_error(__CLASS__, __CLASS__, esc_html__('No new/old valid term specified!', 'simple-tags'), 'error taxopress-notice');
1242
1243 return false;
1244 }
1245
1246 $counter = 0;
1247 if (count($old_terms) === count($new_terms)) { // Rename only
1248 foreach ((array) $old_terms as $i => $old_tag) {
1249 $new_name = sanitize_text_field($new_terms[ $i ]);
1250
1251 // Get term by name
1252 $term = get_term_by('name', sanitize_text_field($old_tag), $taxonomy);
1253 if (! $term) {
1254 continue;
1255 }
1256
1257 // Get objects from term ID
1258 $objects_id = get_objects_in_term($term->term_id, $taxonomy, array( 'fields' => 'all_with_object_id' ));
1259
1260 // Create the new term
1261 if (! $term_info = term_exists($new_name, $taxonomy)) {
1262 $term_info = wp_insert_term($new_name, $taxonomy);
1263 }
1264
1265 // If default category, update the ID for new term...
1266 if ('category' == $taxonomy && $term->term_id == get_option('default_category')) {
1267 update_option('default_category', $term_info['term_id']);
1268 clean_term_cache($term_info['term_id'], $taxonomy);
1269 }
1270
1271 // Delete old term
1272 wp_delete_term($term->term_id, $taxonomy);
1273
1274 // Set objects to new term ! (Append no replace)
1275 foreach ((array) $objects_id as $object_id) {
1276 wp_set_object_terms($object_id, $new_name, $taxonomy, true);
1277 }
1278
1279 // Clean cache
1280 clean_object_term_cache($objects_id, $taxonomy);
1281 clean_term_cache($term->term_id, $taxonomy);
1282
1283 // Increment
1284 $counter++;
1285 }
1286
1287 if ($counter == 0) {
1288 add_settings_error(__CLASS__, __CLASS__, esc_html__('No term renamed.', 'simple-tags'), 'updated taxopress-notice');
1289 } else {
1290 add_settings_error(__CLASS__, __CLASS__, sprintf(esc_html__('Renamed term(s) "%1$s" to "%2$s"', 'simple-tags'), rtrim($old, ','), rtrim($new, ',')), 'updated taxopress-notice');
1291 }
1292 } else { // Error
1293 add_settings_error(__CLASS__, __CLASS__, sprintf(esc_html__('Error. No enough terms for rename.', 'simple-tags'), $old), 'error taxopress-notice');
1294 }
1295
1296 return true;
1297 }
1298
1299 /**
1300 * Method for delete a list of terms
1301 *
1302 * @param string $taxonomy
1303 * @param string $delete
1304 *
1305 * @return boolean
1306 * @author WebFactory Ltd
1307 */
1308 public static function deleteTermsByTermList($taxonomy = 'post_tag', $delete = '')
1309 {
1310 if (trim(str_replace(',', '', stripslashes($delete))) == '') {
1311 add_settings_error(__CLASS__, __CLASS__, esc_html__('No term specified!', 'simple-tags'), 'error taxopress-notice');
1312
1313 return false;
1314 }
1315
1316 // In array + filter
1317 $delete_terms = explode(',', $delete);
1318 $delete_terms = array_filter($delete_terms, '_delete_empty_element');
1319
1320 // Delete tags
1321 $counter = 0;
1322 foreach ((array) $delete_terms as $term) {
1323 $term = get_term_by('name', sanitize_text_field($term), $taxonomy);
1324 $term_id = (int) $term->term_id;
1325
1326 if ($term_id != 0) {
1327 wp_delete_term($term_id, $taxonomy);
1328 clean_term_cache($term_id, $taxonomy);
1329 $counter++;
1330 }
1331 }
1332
1333 if ($counter == 0) {
1334 add_settings_error(__CLASS__, __CLASS__, esc_html__('No term deleted.', 'simple-tags'), 'updated taxopress-notice');
1335 } else {
1336 add_settings_error(__CLASS__, __CLASS__, sprintf(esc_html__('%1s term(s) deleted.', 'simple-tags'), $counter), 'updated taxopress-notice');
1337 }
1338
1339 return true;
1340 }
1341
1342 /**
1343 * Method for add terms for all or specified posts
1344 *
1345 * @param string $taxonomy
1346 * @param string $match
1347 * @param string $new
1348 *
1349 * @return boolean
1350 * @author WebFactory Ltd
1351 */
1352 public static function addMatchTerms($taxonomy = 'post_tag', $match = '', $new = '')
1353 {
1354 // Helper function to extract term name (ignoring slug in brackets)
1355 $extractTermName = function ($term) {
1356 return trim(preg_replace('/\s*\(.*?\)$/', '', $term));
1357 };
1358
1359 if (trim(str_replace(',', '', stripslashes($new))) == '') {
1360 add_settings_error(__CLASS__, __CLASS__, esc_html__('No new term(s) specified!', 'simple-tags'), 'error taxopress-notice');
1361
1362 return false;
1363 }
1364
1365 $match_terms = explode(',', $match);
1366 $new_terms = explode(',', $new);
1367
1368 // Clean up terms by removing slugs
1369 $match_terms = array_map($extractTermName, $match_terms);
1370 $new_terms = array_map($extractTermName, $new_terms);
1371
1372 $match_terms = array_filter($match_terms, '_delete_empty_element');
1373 $new_terms = array_filter($new_terms, '_delete_empty_element');
1374
1375 $counter = 0;
1376 if (! empty($match_terms)) { // Match and add
1377 // Get terms ID from old match names
1378 $terms_id = array();
1379 foreach ((array) $match_terms as $match_term) {
1380 $term = get_term_by('name', sanitize_text_field($match_term), $taxonomy);
1381 $terms_id[] = (int) $term->term_id;
1382 }
1383
1384 // Get object ID with terms ID
1385 $objects_id = get_objects_in_term($terms_id, $taxonomy, array( 'fields' => 'all_with_object_id' ));
1386
1387 // Add new tags for specified post
1388 foreach ((array) $objects_id as $object_id) {
1389 wp_set_object_terms($object_id, $new_terms, $taxonomy, true); // Append terms
1390 $counter++;
1391 }
1392
1393 // Clean cache
1394 clean_object_term_cache($objects_id, $taxonomy);
1395 clean_term_cache($terms_id, $taxonomy);
1396 } else { // Add for all posts
1397 // Page or not ?
1398 $post_type_sql = "(post_status = 'publish' OR post_status = 'inherit') AND post_type = '".SimpleTags_Admin::$post_type."'";
1399
1400 // Get all posts ID
1401 global $wpdb;
1402 $objects_id = $wpdb->get_col("SELECT ID FROM {$wpdb->posts} WHERE {$post_type_sql}");
1403
1404 // Add new tags for all posts
1405 foreach ((array) $objects_id as $object_id) {
1406 wp_set_object_terms($object_id, $new_terms, $taxonomy, true); // Append terms
1407 clean_object_term_cache($object_id, $taxonomy);
1408 clean_term_cache($new_terms, $taxonomy);
1409 $counter++;
1410 }
1411
1412 // Clean cache
1413 clean_object_term_cache($objects_id, $taxonomy);
1414 }
1415
1416 if ($counter == 0) {
1417 add_settings_error(__CLASS__, __CLASS__, esc_html__('No term added.', 'simple-tags'), 'updated taxopress-notice');
1418 } else {
1419 add_settings_error(__CLASS__, __CLASS__, sprintf(esc_html__('Term(s) added to %1s %2s.', 'simple-tags'), $counter, SimpleTags_Admin::$post_type_name), 'updated taxopress-notice');
1420 }
1421
1422 return true;
1423 }
1424
1425 /**
1426 * Delete terms when counter if inferior to a specific number
1427 *
1428 * @param string $taxonomy
1429 * @param integer $number
1430 *
1431 * @return boolean
1432 * @author WebFactory Ltd
1433 */
1434 public static function removeRarelyUsed($taxonomy = 'post_tag', $number = 0)
1435 {
1436 global $wpdb;
1437
1438 if ((int) $number > 100) {
1439 wp_die('Tcheater ?');
1440 }
1441
1442 // Get terms with counter inferior to...
1443 $terms_id = $wpdb->get_col($wpdb->prepare("SELECT term_id FROM $wpdb->term_taxonomy WHERE taxonomy = %s AND count < %d", $taxonomy, (int) $number));
1444
1445 // Delete terms
1446 $counter = 0;
1447 foreach ((array) $terms_id as $term_id) {
1448 if ($term_id != 0) {
1449 wp_delete_term($term_id, $taxonomy);
1450 clean_term_cache($term_id, $taxonomy);
1451 $counter++;
1452 }
1453 }
1454
1455 if ($counter == 0) {
1456 add_settings_error(__CLASS__, __CLASS__, esc_html__('No term deleted.', 'simple-tags'), 'updated taxopress-notice');
1457 } else {
1458 add_settings_error(__CLASS__, __CLASS__, sprintf(esc_html__('%1s term(s) deleted.', 'simple-tags'), $counter), 'updated taxopress-notice');
1459 }
1460
1461 return true;
1462 }
1463
1464 public function handle_taxopress_check_delete_terms_ajax()
1465 {
1466
1467 if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'st-admin-js')) {
1468 wp_send_json_error(array('message' => __('Nonce verification failed.', 'simple-tags')));
1469 wp_die();
1470 }
1471
1472 global $wpdb;
1473
1474 $taxonomy = isset($_POST['taxonomy']) ? sanitize_text_field($_POST['taxonomy']) : 'post_tag';
1475 $number = isset($_POST['number']) ? intval($_POST['number']) : 0;
1476
1477 if ((int) $number > 100) {
1478 wp_die('Tcheater ?');
1479 }
1480
1481 if ($number > 0) {
1482 $terms = $wpdb->get_col($wpdb->prepare(
1483 "
1484 SELECT term_id FROM $wpdb->term_taxonomy
1485 WHERE taxonomy = %s AND count < %d",
1486 $taxonomy,
1487 (int) $number
1488 ));
1489
1490 $term_count = count($terms);
1491
1492 if ($term_count > 0) {
1493 wp_send_json_success(array('message' => sprintf(__('%d terms will be deleted.', 'simple-tags'), $term_count)));
1494 } else {
1495 wp_send_json_error(array('message' => __('No terms will be deleted.', 'simple-tags')));
1496 }
1497 } else {
1498 wp_send_json_error(array('message' => __('Invalid number specified.', 'simple-tags')));
1499 }
1500
1501 wp_die();
1502 }
1503
1504 /**
1505 * Method for removing terms from all or specified posts
1506 *
1507 * @param string $taxonomy
1508 * @param string $match
1509 * @param string $remove
1510 *
1511 * @return boolean
1512 * @author WebFactory Ltd
1513 */
1514 public static function removeMatchTerms($taxonomy = 'post_tag', $match = '', $remove = '')
1515 {
1516 // Helper function to extract term name (ignoring slug in brackets)
1517 $extractTermName = function ($term) {
1518 return trim(preg_replace('/\s*\(.*?\)$/', '', $term));
1519 };
1520
1521 if (trim(str_replace(',', '', stripslashes($remove))) == '') {
1522 add_settings_error(__CLASS__, __CLASS__, esc_html__('No term(s) specified for removal!', 'simple-tags'), 'error taxopress-notice');
1523 return false;
1524 }
1525
1526 $match_terms = explode(',', $match);
1527 $remove_terms = explode(',', $remove);
1528
1529 // Clean up terms by removing slugs
1530 $match_terms = array_map($extractTermName, $match_terms);
1531 $remove_terms = array_map($extractTermName, $remove_terms);
1532
1533 $match_terms = array_filter($match_terms, '_delete_empty_element');
1534 $remove_terms = array_filter($remove_terms, '_delete_empty_element');
1535
1536 // Arrays to track if terms entered is valid
1537 $valid_remove_terms = array();
1538 $invalid_remove_terms = array();
1539
1540 foreach ((array) $remove_terms as $remove_term) {
1541 $term = get_term_by('name', sanitize_text_field($remove_term), $taxonomy);
1542 if ($term) {
1543 $valid_remove_terms[] = $remove_term; // Add to valid list if the term exists
1544 } else {
1545 $invalid_remove_terms[] = $remove_term; // Collect invalid remove terms
1546 }
1547 }
1548
1549 if (empty($valid_remove_terms)) {
1550 add_settings_error(__CLASS__, __CLASS__, esc_html__('Term(s) does not exist.', 'simple-tags'), 'error taxopress-notice');
1551 return false;
1552 }
1553
1554 $counter = 0;
1555 if (!empty($match_terms)) {
1556 // Get terms ID from match terms
1557 $terms_id = array();
1558 foreach ((array) $match_terms as $match_term) {
1559 $term = get_term_by('name', sanitize_text_field($match_term), $taxonomy);
1560 if ($term) {
1561 $terms_id[] = (int) $term->term_id;
1562 }
1563 }
1564
1565 // Get object ID with terms ID
1566 $objects_id = get_objects_in_term($terms_id, $taxonomy, array('fields' => 'all_with_object_id'));
1567
1568 // Remove specified terms from matched posts
1569 foreach ((array) $objects_id as $object_id) {
1570 wp_remove_object_terms($object_id, $valid_remove_terms, $taxonomy);
1571 $counter++;
1572 }
1573
1574 clean_object_term_cache($objects_id, $taxonomy);
1575 clean_term_cache($terms_id, $taxonomy);
1576 } else {
1577 // Get all posts if no match terms were provided
1578 global $wpdb;
1579 $post_type_sql = "(post_status = 'publish' OR post_status = 'inherit') AND post_type = '".SimpleTags_Admin::$post_type."'";
1580 $objects_id = $wpdb->get_col("SELECT ID FROM {$wpdb->posts} WHERE {$post_type_sql}");
1581
1582 // Remove valid terms for all posts
1583 foreach ((array) $objects_id as $object_id) {
1584 wp_remove_object_terms($object_id, $valid_remove_terms, $taxonomy);
1585 clean_object_term_cache($object_id, $taxonomy);
1586 clean_term_cache($valid_remove_terms, $taxonomy);
1587 $counter++;
1588 }
1589
1590 clean_object_term_cache($objects_id, $taxonomy);
1591 }
1592
1593 if ($counter == 0) {
1594 add_settings_error(__CLASS__, __CLASS__, esc_html__('No matching term found.', 'simple-tags'), 'updated taxopress-notice');
1595 } else {
1596 add_settings_error(__CLASS__, __CLASS__, sprintf(esc_html__('Term(s) removed from %1s %2s.', 'simple-tags'), $counter, SimpleTags_Admin::$post_type_name), 'updated taxopress-notice');
1597 }
1598
1599 return true;
1600 }
1601
1602 public static function handle_taxopress_autocomplete_terms()
1603 {
1604 if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'st-admin-js')) {
1605 wp_send_json_error(['message' => __('Nonce verification failed.', 'simple-tags')]);
1606 wp_die();
1607 }
1608
1609 $taxonomy = isset($_POST['taxonomy']) ? sanitize_text_field($_POST['taxonomy']) : 'post_tag';
1610 $term = isset($_POST['term']) ? sanitize_text_field($_POST['term']) : '';
1611
1612 $terms = get_terms([
1613 'taxonomy' => $taxonomy,
1614 'name__like' => $term,
1615 'hide_empty' => false,
1616 'number' => (int) apply_filters('taxopress_autocomplete_terms_limit', 50),
1617 'update_term_meta_cache' => false,
1618 ]);
1619
1620 $results = [];
1621 foreach ($terms as $term) {
1622 $results[] = array(
1623 'name' => html_entity_decode(
1624 $term->name,
1625 ENT_QUOTES,
1626 get_bloginfo('charset')
1627 ),
1628 'slug' => $term->slug,
1629 );
1630 }
1631
1632 wp_send_json($results);
1633 wp_die();
1634 }
1635
1636
1637 /**
1638 * Method for edit one or more terms slug
1639 *
1640 * @param string $taxonomy
1641 * @param string $names
1642 * @param string $slugs
1643 *
1644 * @return boolean
1645 * @author WebFactory Ltd
1646 */
1647 /*
1648 public static function editTermSlug( $taxonomy = 'post_tag', $names = '', $slugs = '') {
1649 if ( trim( str_replace(',', '', stripslashes($slugs)) ) == '' ) {
1650 add_settings_error( __CLASS__, __CLASS__, esc_html__('No new slug(s) specified!', 'simple-tags'), 'error' );
1651 return false;
1652 }
1653
1654 $match_names = explode(',', $names);
1655 $new_slugs = explode(',', $slugs);
1656
1657 $match_names = array_filter($match_names, '_delete_empty_element');
1658 $new_slugs = array_filter($new_slugs, '_delete_empty_element');
1659
1660 if ( count($match_names) != count($new_slugs) ) {
1661 add_settings_error( __CLASS__, __CLASS__, esc_html__('Terms number and slugs number isn\'t the same!', 'simple-tags'), 'error' );
1662 return false;
1663 } else {
1664 $counter = 0;
1665 foreach ( (array) $match_names as $i => $match_name ) {
1666 // Sanitize slug + Escape
1667 $new_slug = sanitize_title($new_slugs[$i]);
1668
1669 // Get term by name
1670 $term = get_term_by('name', $match_name, $taxonomy);
1671 if ( !$term ) {
1672 continue;
1673 }
1674
1675 // Increment
1676 $counter++;
1677
1678 // Update term
1679 wp_update_term($term->term_id, $taxonomy, array('slug' => $new_slug));
1680
1681 // Clean cache
1682 clean_term_cache($term->term_id, $taxonomy);
1683 }
1684 }
1685
1686 if ( $counter == 0 ) {
1687 add_settings_error( __CLASS__, __CLASS__, esc_html__('No slug edited.', 'simple-tags'), 'updated' );
1688 } else {
1689 add_settings_error( __CLASS__, __CLASS__, sprintf(esc_html__('%s slug(s) edited.', 'simple-tags'), $counter), 'updated' );
1690 }
1691
1692 return true;
1693 }
1694 */
1695
1696
1697 /** Singleton instance */
1698 public static function get_instance()
1699 {
1700 if (! isset(self::$instance)) {
1701 self::$instance = new self();
1702 }
1703
1704 return self::$instance;
1705 }
1706 }
1707 ?>
1708