PluginProbe
Tag, Category, and Taxonomy Manager – Autotagger Automatically Add Terms / 3.52.0
Tag, Category, and Taxonomy Manager – Autotagger Automatically Add Terms v3.52.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.52.0, at inc/terms-functions.php

296 lines 10.2 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 * Fetch post IDs for Terms screen bulk/row actions without hydrating WP_Post objects.
25 *
26 * @param array $args Optional WP_Query arguments.
27 * @return int[]
28 */
29 function taxopress_get_post_ids_for_terms_action($args = [])
30 {
31 $batch_size = 500;
32 $defaults = [
33 'post_type' => 'any',
34 'fields' => 'ids',
35 'no_found_rows' => true,
36 'update_post_meta_cache' => false,
37 'update_post_term_cache' => false,
38 ];
39
40 $post_ids = [];
41 $page = 1;
42
43 do {
44 $query_args = array_merge(
45 $defaults,
46 $args,
47 [
48 'posts_per_page' => $batch_size,
49 'paged' => $page,
50 ]
51 );
52 $batch_post_ids = get_posts($query_args);
53
54 foreach ($batch_post_ids as $post_id) {
55 $post_ids[] = (int) $post_id;
56 }
57
58 $page++;
59 } while (count($batch_post_ids) === $batch_size);
60
61 return $post_ids;
62 }
63
64 /**
65 * Preserve the current Terms screen filters when row actions redirect/reload.
66 *
67 * @param array $extra Extra query arguments.
68 * @return array
69 */
70 function taxopress_get_terms_screen_query_args($extra = [])
71 {
72 $preserve_keys = [
73 'terms_filter_post_type',
74 'terms_filter_taxonomy',
75 'taxonomy_type',
76 'taxopress_terms_taxonomy',
77 'taxopress_show_all',
78 'orderby',
79 'order',
80 'paged',
81 's',
82 ];
83
84 $query_args = ['page' => 'st_terms'];
85
86 foreach ($preserve_keys as $key) {
87 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Preserving current non-state-changing table filters.
88 if (isset($_REQUEST[$key]) && $_REQUEST[$key] !== '') {
89 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Preserving current non-state-changing table filters.
90 $query_args[$key] = sanitize_text_field(wp_unslash($_REQUEST[$key]));
91 }
92 }
93
94 return array_merge($query_args, $extra);
95 }
96
97 /**
98 * Keep a copied term near the original in saved manual order when that order exists.
99 *
100 * @param string $taxonomy Taxonomy slug.
101 * @param int $original_term_id Original term ID.
102 * @param int $copied_term_id Copied term ID.
103 */
104 function taxopress_place_copied_term_near_original($taxonomy, $original_term_id, $copied_term_id)
105 {
106 $taxonomy = sanitize_key($taxonomy);
107 $original_term_id = (int) $original_term_id;
108 $copied_term_id = (int) $copied_term_id;
109
110 if (empty($taxonomy) || $original_term_id <= 0 || $copied_term_id <= 0) {
111 return;
112 }
113
114 $option_name = 'taxopress_term_order_' . $taxonomy;
115 $custom_order = array_values(array_filter(array_map('intval', (array) get_option($option_name, []))));
116
117 if (empty($custom_order)) {
118 return;
119 }
120
121 $custom_order = array_values(array_diff($custom_order, [$copied_term_id]));
122 $original_position = array_search($original_term_id, $custom_order, true);
123
124 if ($original_position === false) {
125 $custom_order[] = $copied_term_id;
126 } else {
127 $taxonomy_settings = taxopress_get_all_edited_taxonomy_data();
128 $order_setting = isset($taxonomy_settings[$taxonomy]['order']) ? strtolower($taxonomy_settings[$taxonomy]['order']) : 'asc';
129 $insert_position = ($order_setting === 'desc') ? $original_position + 1 : $original_position;
130 array_splice($custom_order, $insert_position, 0, [$copied_term_id]);
131 }
132
133 update_option($option_name, array_values(array_unique($custom_order)));
134 }
135
136 /**
137 * Handle the save and deletion of terms data.
138 */
139 function taxopress_process_terms()
140 {
141
142 if (wp_doing_ajax()) {
143 return;
144 }
145
146 if (!is_admin()) {
147 return;
148 }
149
150 if (!current_user_can('simple_tags')) {
151 return;
152 }
153
154 if (empty($_GET)) {
155 return;
156 }
157
158 if (!isset($_GET['page'])) {
159 return;
160 }
161 if ('st_terms' !== $_GET['page']) {
162 return;
163 }
164
165 if (isset($_REQUEST['action']) && $_REQUEST['action'] === 'taxopress-delete-terms') {
166 $nonce = !empty($_REQUEST['_wpnonce']) ? sanitize_text_field(wp_unslash($_REQUEST['_wpnonce'])) : '';
167 if (wp_verify_nonce($nonce, 'terms-action-request-nonce') && isset($_REQUEST['taxopress_terms'])) {
168 $term = get_term(sanitize_text_field(wp_unslash($_REQUEST['taxopress_terms'])));
169 wp_delete_term($term->term_id, $term->taxonomy);
170 }
171 add_action('admin_notices', "taxopress_term_delete_success_admin_notice");
172 add_filter('removable_query_args', 'taxopress_delete_terms_filter_removable_query_args');
173 }
174
175 if (isset($_REQUEST['action']) && $_REQUEST['action'] === 'taxopress-remove-from-posts') {
176 $nonce = !empty($_REQUEST['_wpnonce']) ? sanitize_text_field(wp_unslash($_REQUEST['_wpnonce'])) : '';
177 if (wp_verify_nonce($nonce, 'terms-action-request-nonce') && isset($_REQUEST['taxopress_terms'])) {
178 $term = get_term(sanitize_text_field(wp_unslash($_REQUEST['taxopress_terms'])));
179 $args = array(
180 'post_type' => 'any',
181 // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query -- Necessary to filter posts by specific term for accurate removal
182 'tax_query' => array(
183 array(
184 'taxonomy' => $term->taxonomy,
185 'field' => 'id',
186 'terms' => $term->term_id
187 )
188 )
189 );
190 $post_ids = taxopress_get_post_ids_for_terms_action($args);
191 $counter = 0;
192 foreach ($post_ids as $post_id) {
193 $remove = wp_remove_object_terms($post_id, $term->term_id, $term->taxonomy);
194 if ($remove) {
195 clean_object_term_cache($post_id, $term->taxonomy);
196 clean_term_cache($term->term_id, $term->taxonomy);
197 $counter++;
198 }
199 }
200 }
201 add_action('admin_notices', "taxopress_term_posts_remov_success_admin_notice");
202 add_filter('removable_query_args', 'taxopress_delete_terms_filter_removable_query_args');
203 }
204
205 if (isset($_REQUEST['action']) && $_REQUEST['action'] === 'taxopress-copy-term') {
206 $nonce = !empty($_REQUEST['_wpnonce']) ? sanitize_text_field(wp_unslash($_REQUEST['_wpnonce'])) : '';
207 if (wp_verify_nonce($nonce, 'terms-action-request-nonce') && isset($_REQUEST['taxopress_terms'])) {
208 $term = get_term(sanitize_text_field(wp_unslash($_REQUEST['taxopress_terms'])));
209
210 $taxopress_term_name = $term->name . ' Copy';
211 $base_slug = $term->slug . '-copy';
212 $taxopress_term_slug = taxopress_get_unique_term_slug($base_slug, $term->taxonomy);
213 $taxopress_term_data = wp_insert_term($taxopress_term_name, $term->taxonomy, [
214 'slug' => $taxopress_term_slug,
215 'description' => $term->description,
216 'parent' => $term->parent,
217 ]);
218
219 if (!is_wp_error($taxopress_term_data)) {
220 $taxopress_term_id = $taxopress_term_data['term_id'];
221 taxopress_place_copied_term_near_original($term->taxonomy, $term->term_id, $taxopress_term_id);
222 $_REQUEST['taxopress_copied_term_id'] = $taxopress_term_id;
223 $_REQUEST['taxopress_original_term_id'] = $term->term_id;
224 $_REQUEST['taxopress_copied_taxonomy'] = $term->taxonomy;
225
226 $args = array(
227 'post_type' => 'any',
228 // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query -- Necessary to filter posts by specific term for accurate term copying
229 'tax_query' => array(
230 array(
231 'taxonomy' => $term->taxonomy,
232 'field' => 'id',
233 'terms' => $term->term_id
234 )
235 )
236 );
237 $post_ids = taxopress_get_post_ids_for_terms_action($args);
238
239 foreach ($post_ids as $post_id) {
240 wp_set_object_terms($post_id, $taxopress_term_id, $term->taxonomy, true);
241 }
242 }
243 }
244 add_action('admin_notices', "taxopress_term_copy_success_admin_notice");
245 add_filter('removable_query_args', 'taxopress_delete_terms_filter_removable_query_args');
246 }
247 }
248 add_action('admin_init', 'taxopress_process_terms', 8);
249
250 /**
251 * Successful term copy callback.
252 */
253 function taxopress_term_copy_success_admin_notice()
254 {
255 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
256 echo taxopress_admin_notices_helper(esc_html__('Term copied successfully.', 'simple-tags'), true);
257 }
258
259 /**
260 * Successful deleted callback.
261 */
262 function taxopress_term_delete_success_admin_notice()
263 {
264 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
265 echo taxopress_admin_notices_helper(esc_html__('Term deleted successfully.', 'simple-tags'), false);
266 }
267
268 /**
269 * Successful remove term from posts callback.
270 */
271 function taxopress_term_posts_remov_success_admin_notice()
272 {
273 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
274 echo taxopress_admin_notices_helper(esc_html__('Term removed from all posts successfully.', 'simple-tags'), true);
275 }
276
277 /**
278 * Filters the list of query arguments which get removed from admin area URLs in WordPress.
279 *
280 * @link https://core.trac.wordpress.org/ticket/23367
281 *
282 * @param string[] $args Array of removable query arguments.
283 * @return string[] Updated array of removable query arguments.
284 */
285 function taxopress_delete_terms_filter_removable_query_args(array $args)
286 {
287 return array_merge($args, [
288 'action',
289 'taxopress_terms',
290 '_wpnonce',
291 'taxopress_copied_term_id',
292 'taxopress_original_term_id',
293 'taxopress_copied_taxonomy',
294 ]);
295 }
296