PluginProbe
Tag, Category, and Taxonomy Manager – Autotagger Automatically Add Terms / 3.54.0
Tag, Category, and Taxonomy Manager – Autotagger Automatically Add Terms v3.54.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 / terms-functions.php

terms-functions.php in Tag, Category, and Taxonomy Manager – Autotagger Automatically Add Terms 3.54.0, at inc/terms-functions.php

361 lines 12.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Generate a unique term slug should user decide to copy same term more than once.
5 *
6 * @param string $slug The initial slug to check
7 * @param string $taxonomy The taxonomy to check against
8 * @return string Unique slug
9 */
10 function taxopress_get_unique_term_slug($slug, $taxonomy)
11 {
12 $original_slug = $slug;
13 $count = 1;
14
15 while (term_exists($slug, $taxonomy)) {
16 $slug = $original_slug . '-' . $count;
17 $count++;
18 }
19
20 return $slug;
21 }
22
23 /**
24 * Check the current user's native capabilities for a taxonomy operation.
25 *
26 * @param string $taxonomy Taxonomy name.
27 * @param string|array $capabilities Taxonomy capability property or properties.
28 * @return bool
29 */
30 function taxopress_current_user_can_for_taxonomy($taxonomy, $capabilities)
31 {
32 $taxonomy_object = get_taxonomy(sanitize_key($taxonomy));
33 if (!$taxonomy_object) {
34 return false;
35 }
36
37 foreach ((array) $capabilities as $capability) {
38 if (
39 empty($taxonomy_object->cap->{$capability})
40 || !current_user_can($taxonomy_object->cap->{$capability})
41 ) {
42 return false;
43 }
44 }
45
46 return true;
47 }
48
49 /**
50 * Fetch post IDs for Terms screen bulk/row actions without hydrating WP_Post objects.
51 *
52 * @param array $args Optional WP_Query arguments.
53 * @return int[]
54 */
55 function taxopress_get_post_ids_for_terms_action($args = [])
56 {
57 $batch_size = 500;
58 $defaults = [
59 'post_type' => 'any',
60 'fields' => 'ids',
61 'no_found_rows' => true,
62 'update_post_meta_cache' => false,
63 'update_post_term_cache' => false,
64 ];
65
66 $post_ids = [];
67 $page = 1;
68
69 do {
70 $query_args = array_merge(
71 $defaults,
72 $args,
73 [
74 'posts_per_page' => $batch_size,
75 'paged' => $page,
76 ]
77 );
78 $batch_post_ids = get_posts($query_args);
79
80 foreach ($batch_post_ids as $post_id) {
81 $post_ids[] = (int) $post_id;
82 }
83
84 $page++;
85 } while (count($batch_post_ids) === $batch_size);
86
87 return $post_ids;
88 }
89
90 /**
91 * Preserve the current Terms screen filters when row actions redirect/reload.
92 *
93 * @param array $extra Extra query arguments.
94 * @return array
95 */
96 function taxopress_get_terms_screen_query_args($extra = [])
97 {
98 $preserve_keys = [
99 'terms_filter_post_type',
100 'terms_filter_taxonomy',
101 'taxonomy_type',
102 'taxopress_terms_taxonomy',
103 'taxopress_show_all',
104 'orderby',
105 'order',
106 'paged',
107 's',
108 ];
109
110 $query_args = ['page' => 'st_terms'];
111
112 foreach ($preserve_keys as $key) {
113 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Preserving current non-state-changing table filters.
114 if (isset($_REQUEST[$key]) && is_scalar($_REQUEST[$key]) && $_REQUEST[$key] !== '') {
115 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Preserving current non-state-changing table filters.
116 $value = sanitize_text_field(wp_unslash($_REQUEST[$key]));
117
118 if (in_array($key, ['taxopress_show_all', 'paged'], true)) {
119 $query_args[$key] = absint($value);
120 } elseif (in_array($key, ['terms_filter_post_type', 'terms_filter_taxonomy', 'taxonomy_type', 'taxopress_terms_taxonomy', 'orderby', 'order'], true)) {
121 $query_args[$key] = sanitize_key($value);
122 } else {
123 $query_args[$key] = sanitize_text_field($value);
124 }
125 }
126 }
127
128 return array_merge($query_args, $extra);
129 }
130
131 /**
132 * Keep a copied term near the original in saved manual order when that order exists.
133 *
134 * @param string $taxonomy Taxonomy slug.
135 * @param int $original_term_id Original term ID.
136 * @param int $copied_term_id Copied term ID.
137 */
138 function taxopress_place_copied_term_near_original($taxonomy, $original_term_id, $copied_term_id)
139 {
140 $taxonomy = sanitize_key($taxonomy);
141 $original_term_id = (int) $original_term_id;
142 $copied_term_id = (int) $copied_term_id;
143
144 if (empty($taxonomy) || $original_term_id <= 0 || $copied_term_id <= 0) {
145 return;
146 }
147
148 $option_name = 'taxopress_term_order_' . $taxonomy;
149 $custom_order = array_values(array_filter(array_map('intval', (array) get_option($option_name, []))));
150
151 if (empty($custom_order)) {
152 return;
153 }
154
155 $custom_order = array_values(array_diff($custom_order, [$copied_term_id]));
156 $original_position = array_search($original_term_id, $custom_order, true);
157
158 if ($original_position === false) {
159 $custom_order[] = $copied_term_id;
160 } else {
161 $taxonomy_settings = taxopress_get_all_edited_taxonomy_data();
162 $order_setting = isset($taxonomy_settings[$taxonomy]['order']) ? strtolower($taxonomy_settings[$taxonomy]['order']) : 'asc';
163 $insert_position = ($order_setting === 'desc') ? $original_position + 1 : $original_position;
164 array_splice($custom_order, $insert_position, 0, [$copied_term_id]);
165 }
166
167 update_option($option_name, array_values(array_unique($custom_order)));
168 }
169
170 /**
171 * Handle the save and deletion of terms data.
172 */
173 function taxopress_process_terms()
174 {
175
176 if (wp_doing_ajax()) {
177 return;
178 }
179
180 if (!is_admin()) {
181 return;
182 }
183
184 if (!current_user_can('simple_tags')) {
185 return;
186 }
187
188 if (empty($_GET)) {
189 return;
190 }
191
192 if (!isset($_GET['page'])) {
193 return;
194 }
195 if ('st_terms' !== $_GET['page']) {
196 return;
197 }
198
199 if (isset($_REQUEST['action']) && $_REQUEST['action'] === 'taxopress-delete-terms') {
200 $nonce = !empty($_REQUEST['_wpnonce']) ? sanitize_text_field(wp_unslash($_REQUEST['_wpnonce'])) : '';
201 if (wp_verify_nonce($nonce, 'terms-action-request-nonce') && isset($_REQUEST['taxopress_terms'])) {
202 $term = get_term(sanitize_text_field(wp_unslash($_REQUEST['taxopress_terms'])));
203 if (
204 !$term
205 || is_wp_error($term)
206 || !taxopress_current_user_can_for_taxonomy($term->taxonomy, 'delete_terms')
207 ) {
208 wp_die(esc_html__('Permission denied.', 'simple-tags'), '', ['response' => 403]);
209 }
210 wp_delete_term($term->term_id, $term->taxonomy);
211 }
212 add_action('admin_notices', "taxopress_term_delete_success_admin_notice");
213 add_filter('removable_query_args', 'taxopress_delete_terms_filter_removable_query_args');
214 }
215
216 if (isset($_REQUEST['action']) && $_REQUEST['action'] === 'taxopress-remove-from-posts') {
217 $nonce = !empty($_REQUEST['_wpnonce']) ? sanitize_text_field(wp_unslash($_REQUEST['_wpnonce'])) : '';
218 if (wp_verify_nonce($nonce, 'terms-action-request-nonce') && isset($_REQUEST['taxopress_terms'])) {
219 $term = get_term(sanitize_text_field(wp_unslash($_REQUEST['taxopress_terms'])));
220 if (
221 !$term
222 || is_wp_error($term)
223 || !taxopress_current_user_can_for_taxonomy($term->taxonomy, 'assign_terms')
224 ) {
225 wp_die(esc_html__('Permission denied.', 'simple-tags'), '', ['response' => 403]);
226 }
227 $args = array(
228 'post_type' => 'any',
229 // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query -- Necessary to filter posts by specific term for accurate removal
230 'tax_query' => array(
231 array(
232 'taxonomy' => $term->taxonomy,
233 'field' => 'id',
234 'terms' => $term->term_id
235 )
236 )
237 );
238 $post_ids = taxopress_get_post_ids_for_terms_action($args);
239 $counter = 0;
240 foreach ($post_ids as $post_id) {
241 if (!current_user_can('edit_post', $post_id)) {
242 continue;
243 }
244 $remove = wp_remove_object_terms($post_id, $term->term_id, $term->taxonomy);
245 if ($remove) {
246 clean_object_term_cache($post_id, $term->taxonomy);
247 clean_term_cache($term->term_id, $term->taxonomy);
248 $counter++;
249 }
250 }
251 }
252 add_action('admin_notices', "taxopress_term_posts_remov_success_admin_notice");
253 add_filter('removable_query_args', 'taxopress_delete_terms_filter_removable_query_args');
254 }
255
256 if (isset($_REQUEST['action']) && $_REQUEST['action'] === 'taxopress-copy-term') {
257 $nonce = !empty($_REQUEST['_wpnonce']) ? sanitize_text_field(wp_unslash($_REQUEST['_wpnonce'])) : '';
258 if (wp_verify_nonce($nonce, 'terms-action-request-nonce') && isset($_REQUEST['taxopress_terms'])) {
259 $term = get_term(sanitize_text_field(wp_unslash($_REQUEST['taxopress_terms'])));
260
261 if (
262 !$term
263 || is_wp_error($term)
264 || !taxopress_current_user_can_for_taxonomy(
265 $term->taxonomy,
266 ['edit_terms', 'assign_terms']
267 )
268 ) {
269 wp_die(esc_html__('Permission denied.', 'simple-tags'), '', ['response' => 403]);
270 }
271
272 $taxopress_term_name = $term->name . ' Copy';
273 $base_slug = $term->slug . '-copy';
274 $taxopress_term_slug = taxopress_get_unique_term_slug($base_slug, $term->taxonomy);
275 $taxopress_term_data = wp_insert_term($taxopress_term_name, $term->taxonomy, [
276 'slug' => $taxopress_term_slug,
277 'description' => $term->description,
278 'parent' => $term->parent,
279 ]);
280
281 if (!is_wp_error($taxopress_term_data)) {
282 $taxopress_term_id = $taxopress_term_data['term_id'];
283 taxopress_place_copied_term_near_original($term->taxonomy, $term->term_id, $taxopress_term_id);
284 $_REQUEST['taxopress_copied_term_id'] = $taxopress_term_id;
285 $_REQUEST['taxopress_original_term_id'] = $term->term_id;
286 $_REQUEST['taxopress_copied_taxonomy'] = $term->taxonomy;
287
288 $args = array(
289 'post_type' => 'any',
290 // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query -- Necessary to filter posts by specific term for accurate term copying
291 'tax_query' => array(
292 array(
293 'taxonomy' => $term->taxonomy,
294 'field' => 'id',
295 'terms' => $term->term_id
296 )
297 )
298 );
299 $post_ids = taxopress_get_post_ids_for_terms_action($args);
300
301 foreach ($post_ids as $post_id) {
302 if (!current_user_can('edit_post', $post_id)) {
303 continue;
304 }
305 wp_set_object_terms($post_id, $taxopress_term_id, $term->taxonomy, true);
306 }
307 }
308 }
309 add_action('admin_notices', "taxopress_term_copy_success_admin_notice");
310 add_filter('removable_query_args', 'taxopress_delete_terms_filter_removable_query_args');
311 }
312 }
313 add_action('admin_init', 'taxopress_process_terms', 8);
314
315 /**
316 * Successful term copy callback.
317 */
318 function taxopress_term_copy_success_admin_notice()
319 {
320 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
321 echo taxopress_admin_notices_helper(esc_html__('Term copied successfully.', 'simple-tags'), true);
322 }
323
324 /**
325 * Successful deleted callback.
326 */
327 function taxopress_term_delete_success_admin_notice()
328 {
329 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
330 echo taxopress_admin_notices_helper(esc_html__('Term deleted successfully.', 'simple-tags'), false);
331 }
332
333 /**
334 * Successful remove term from posts callback.
335 */
336 function taxopress_term_posts_remov_success_admin_notice()
337 {
338 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
339 echo taxopress_admin_notices_helper(esc_html__('Term removed from all posts successfully.', 'simple-tags'), true);
340 }
341
342 /**
343 * Filters the list of query arguments which get removed from admin area URLs in WordPress.
344 *
345 * @link https://core.trac.wordpress.org/ticket/23367
346 *
347 * @param string[] $args Array of removable query arguments.
348 * @return string[] Updated array of removable query arguments.
349 */
350 function taxopress_delete_terms_filter_removable_query_args(array $args)
351 {
352 return array_merge($args, [
353 'action',
354 'taxopress_terms',
355 '_wpnonce',
356 'taxopress_copied_term_id',
357 'taxopress_original_term_id',
358 'taxopress_copied_taxonomy',
359 ]);
360 }
361