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

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

2,667 lines 94.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Construct a dropdown of our taxonomies so users can select which to edit.
5 *
6 *
7 * @param array $taxonomies Array of taxonomies that are registered. Optional.
8 */
9 function taxopress_taxonomies_dropdown($taxonomies = [])
10 {
11
12 $ui = new taxopress_admin_ui();
13
14 if (!empty($taxonomies)) {
15 $select = [];
16 $select['options'] = [];
17
18 foreach ($taxonomies as $tax) {
19 $text = !empty($tax['label']) ? esc_html($tax['label']) : esc_html($tax['name']);
20 $select['options'][] = [
21 'attr' => $tax['name'],
22 'text' => $text,
23 ];
24 }
25
26 $current = taxopress_get_current_taxonomy();
27 $select['selected'] = $current;
28
29 /**
30 * Filters the taxonomy dropdown options before rendering.
31 *
32 * @param array $select Array of options for the dropdown.
33 * @param array $taxonomies Array of original passed in post types.
34 */
35 $select = apply_filters('taxopress_taxonomies_dropdown_options', $select, $taxonomies);
36
37 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
38 echo $ui->get_select_input([
39 'namearray' => 'taxopress_selected_taxonomy',
40 'name' => 'taxonomy',
41 'selections' => $select,// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
42 'wrap' => false,
43 ]);
44 }
45 }
46
47 /**
48 * Get the selected taxonomy from the $_POST global.
49 *
50 *
51 * @param bool $taxonomy_deleted Whether or not a taxonomy was recently deleted. Optional. Default false.
52 * @return bool|string False on no result, sanitized taxonomy if set.
53 * @internal
54 *
55 */
56 function taxopress_get_current_taxonomy($taxonomy_deleted = false)
57 {
58
59 $tax = false;
60
61 if (!empty($_POST)) {
62 if (!empty($_POST['taxopress_select_taxonomy_nonce_field'])) {
63 check_admin_referer('taxopress_select_taxonomy_nonce_action', 'taxopress_select_taxonomy_nonce_field');
64 }
65 if (isset($_POST['taxopress_selected_taxonomy']['taxonomy'])) {
66 $tax = sanitize_text_field($_POST['taxopress_selected_taxonomy']['taxonomy']);
67 } elseif ($taxonomy_deleted) {
68 $taxonomies = taxopress_get_taxonomy_data();
69 $tax = key($taxonomies);
70 } elseif (isset($_POST['cpt_custom_tax']['name'])) {
71 // Return the submitted value.
72 if (!in_array($_POST['cpt_custom_tax']['name'], taxopress_reserved_taxonomies(), true)) {
73 $tax = sanitize_text_field($_POST['cpt_custom_tax']['name']);
74 } else {
75 // Return the original value since user tried to submit a reserved term.
76 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated -- Nonce verified by check_admin_referer
77 $tax = isset($_POST['tax_original']) ? sanitize_text_field($_POST['tax_original']) : '';
78 }
79 }
80 } elseif (!empty($_GET) && isset($_GET['taxopress_taxonomy'])) {
81 $tax = sanitize_text_field($_GET['taxopress_taxonomy']);
82 } else {
83 $taxonomies = taxopress_get_taxonomy_data();
84 if (!empty($taxonomies)) {
85 // Will return the first array key.
86 $tax = key($taxonomies);
87 }
88 }
89
90 /**
91 * Filters the current taxonomy to edit.
92 *
93 * @param string $tax Taxonomy slug.
94 */
95 return apply_filters('taxopress_current_taxonomy', $tax);
96 }
97
98 /**
99 * Delete our custom taxonomy from the array of taxonomies.
100 *
101 *
102 * @param array $data The $_POST values. Optional.
103 * @return bool|string False on failure, string on success.
104 * @internal
105 *
106 */
107 function taxopress_delete_taxonomy($data = [])
108 {
109
110 if (is_string($data) && taxonomy_exists($data)) {
111 $data = [
112 'cpt_custom_tax' => [
113 'name' => $data,
114 ],
115 ];
116 }
117
118 // Check if they selected one to delete.
119 if (empty($data['cpt_custom_tax']['name'])) {
120 return taxopress_admin_notices(
121 'error',
122 '',
123 false,
124 esc_html__('Please provide a taxonomy to delete', 'simple-tags')
125 );
126 }
127
128 /**
129 * Fires before a taxonomy is deleted from our saved options.
130 *
131 *
132 * @param array $data Array of taxonomy data we are deleting.
133 */
134 do_action('taxopress_before_delete_taxonomy', $data);
135
136 $taxonomies = taxopress_get_taxonomy_data();
137 $external_taxonomies = taxopress_get_extername_taxonomy_data();
138
139 if (array_key_exists(strtolower($data['cpt_custom_tax']['name']), $taxonomies)) {
140 unset($taxonomies[$data['cpt_custom_tax']['name']]);
141
142 /**
143 * Filters whether or not 3rd party options were saved successfully within taxonomy deletion.
144 *
145 * @param bool $value Whether or not someone else saved successfully. Default false.
146 * @param array $taxonomies Array of our updated taxonomies data.
147 * @param array $data Array of submitted taxonomy to update.
148 */
149 if (false === ($success = apply_filters('taxopress_taxonomy_delete_tax', false, $taxonomies, $data))) {
150 $success = update_option('taxopress_taxonomies', $taxonomies);
151 }
152 }
153
154 if (array_key_exists(strtolower($data['cpt_custom_tax']['name']), $external_taxonomies)) {
155 unset($external_taxonomies[$data['cpt_custom_tax']['name']]);
156
157 /**
158 * Filters whether or not 3rd party options were saved successfully within taxonomy deletion.
159 *
160 * @param bool $value Whether or not someone else saved successfully. Default false.
161 * @param array $external_taxonomies Array of our updated taxonomies data.
162 * @param array $data Array of submitted taxonomy to update.
163 */
164 if (false === ($success = apply_filters('taxopress_taxonomy_delete_tax', false, $external_taxonomies, $data))) {
165 $success = update_option('taxopress_external_taxonomies', $external_taxonomies);
166 }
167 }
168
169 if ($data['cpt_custom_tax']['name'] === 'media_tag') {
170 // phpcs:ignore WordPressVIPMinimum.Performance.TaxonomyMetaInOptions.PossibleTermMetaInOptions -- Default term stored in options for compatibility
171 $success = update_option('taxopress_media_tag_deleted', 1);
172 }
173
174 // phpcs:ignore WordPressVIPMinimum.Performance.TaxonomyMetaInOptions.PossibleTermMetaInOptions -- Default term stored in options for compatibility
175 delete_option("default_term_{$data['cpt_custom_tax']['name']}");
176
177 /**
178 * Fires after a taxonomy is deleted from our saved options.
179 *
180 *
181 * @param array $data Array of taxonomy data that was deleted.
182 */
183 do_action('taxopress_after_delete_taxonomy', $data);
184
185 // Used to help flush rewrite rules on init.
186 set_transient('taxopress_flush_rewrite_rules', 'true', 5 * 60);
187
188 if (isset($success)) {
189 return 'delete_success';
190 }
191
192 return 'delete_fail';
193 }
194
195 /**
196 * Add to or update our TAXOPRESS option with new data.
197 *
198 *
199 * @param array $data Array of taxonomy data to update. Optional.
200 * @return bool|string False on failure, string on success.
201 * @internal
202 *
203 */
204 function taxopress_update_taxonomy($data = [])
205 {
206
207 //update our custom checkbox value if not checked
208
209 if (!isset($data['cpt_custom_tax']['hierarchical'])) {
210 $data['cpt_custom_tax']['hierarchical'] = 0;
211 }
212 if (!isset($data['cpt_custom_tax']['rewrite'])) {
213 $data['cpt_custom_tax']['rewrite'] = 0;
214 }
215 if (!isset($data['cpt_custom_tax']['rewrite_withfront'])) {
216 $data['cpt_custom_tax']['rewrite_withfront'] = 0;
217 }
218 if (!isset($data['cpt_custom_tax']['rewrite_hierarchical'])) {
219 $data['cpt_custom_tax']['rewrite_hierarchical'] = 0;
220 }
221 if (!isset($data['cpt_custom_tax']['show_ui'])) {
222 $data['cpt_custom_tax']['show_ui'] = 0;
223 }
224 if (!isset($data['cpt_custom_tax']['show_in_menu'])) {
225 $data['cpt_custom_tax']['show_in_menu'] = 0;
226 }
227 if (!isset($data['cpt_custom_tax']['show_in_nav_menus'])) {
228 $data['cpt_custom_tax']['show_in_nav_menus'] = 0;
229 }
230 if (!isset($data['cpt_custom_tax']['show_admin_column'])) {
231 $data['cpt_custom_tax']['show_admin_column'] = 0;
232 }
233 if (!isset($data['cpt_custom_tax']['show_in_rest'])) {
234 $data['cpt_custom_tax']['show_in_rest'] = 0;
235 }
236 if (!isset($data['cpt_custom_tax']['show_in_quick_edit'])) {
237 $data['cpt_custom_tax']['show_in_quick_edit'] = 0;
238 }
239 if (!isset($data['cpt_custom_tax']['public'])) {
240 $data['cpt_custom_tax']['public'] = 0;
241 }
242 if (!isset($data['cpt_custom_tax']['publicly_queryable'])) {
243 $data['cpt_custom_tax']['publicly_queryable'] = 0;
244 }
245 if (!isset($data['cpt_custom_tax']['query_var'])) {
246 $data['cpt_custom_tax']['query_var'] = 0;
247 }
248 if (!isset($data['cpt_custom_tax']['include_in_result'])) {
249 $data['cpt_custom_tax']['include_in_result'] = 0;
250 }
251 if (! isset($data['cpt_custom_tax']['show_in_filter'])) {
252 $data['cpt_custom_tax']['show_in_filter'] = 0;
253 }
254 if (! isset($data['cpt_custom_tax']['order'])) {
255 $data['cpt_custom_tax']['order'] = 'asc';
256 }
257 if (! isset($data['cpt_custom_tax']['orderby'])) {
258 $data['cpt_custom_tax']['orderby'] = 'term_id';
259 }
260 if (! isset($data['cpt_custom_tax']['enable_taxopress_ordering'])) {
261 $data['cpt_custom_tax']['enable_taxopress_ordering'] = 0;
262 }
263
264 /**
265 * Fires before a taxonomy is updated to our saved options.
266 *
267 *
268 * @param array $data Array of taxonomy data we are updating.
269 */
270 do_action('taxopress_before_update_taxonomy', $data);
271
272 // They need to provide a name.
273 if (empty($data['cpt_custom_tax']['name'])) {
274 return taxopress_admin_notices('error', '', false, esc_html__('Please provide a taxonomy name', 'simple-tags'));
275 }
276
277 if (!isset($data['taxonomy_external_edit'])) {
278 // Maybe a little harsh, but we shouldn't be saving THAT frequently.
279 // phpcs:ignore WordPressVIPMinimum.Performance.TaxonomyMetaInOptions.PossibleTermMetaInOptions -- Default term stored in options for compatibility
280 delete_option("default_term_{$data['cpt_custom_tax']['name']}");
281 }
282
283 if (!isset($data['taxonomy_external_edit'])) {
284 if (!empty($data['tax_original']) && $data['tax_original'] !== $data['cpt_custom_tax']['name']) {
285 if (!empty($data['update_taxonomy'])) {
286 add_filter('taxopress_convert_taxonomy_terms', '__return_true');
287 }
288 }
289 }
290
291 $sanitized_data = [];
292 foreach ($data as $key => $value) {
293 if (!is_array($value)) {
294 $sanitized_data[$key] = taxopress_sanitize_text_field($value);
295 } else {
296 $new_value = [];
297 foreach ($data[$key] as $option_key => $option_value) {
298 $new_value[$option_key] = taxopress_sanitize_text_field($option_value);
299 }
300 $sanitized_data[$key] = $new_value;
301 }
302 }
303 $data = $sanitized_data;
304
305 if (
306 false !== strpos($data['cpt_custom_tax']['name'], '\'') ||
307 false !== strpos($data['cpt_custom_tax']['name'], '\"') ||
308 false !== strpos($data['cpt_custom_tax']['rewrite_slug'], '\'') ||
309 false !== strpos($data['cpt_custom_tax']['rewrite_slug'], '\"')
310 ) {
311 add_filter('taxopress_custom_error_message', 'taxopress_slug_has_quotes');
312
313 return 'error';
314 }
315
316 $taxonomies = taxopress_get_taxonomy_data();
317 $external_taxonomies = taxopress_get_extername_taxonomy_data();
318
319
320 if (!isset($data['taxonomy_external_edit'])) {
321 /**
322 * Check if we already have a post type of that name.
323 *
324 * @param bool $value Assume we have no conflict by default.
325 * @param string $value Post type slug being saved.
326 * @param array $post_types Array of existing post types from TAXOPRESS.
327 */
328 $slug_exists = apply_filters(
329 'taxopress_taxonomy_slug_exists',
330 false,
331 $data['cpt_custom_tax']['name'],
332 $taxonomies
333 );
334 if (true === $slug_exists) {
335 add_filter('taxopress_custom_error_message', 'taxopress_slug_matches_taxonomy');
336
337 return 'error';
338 }
339 }
340
341 foreach ($data['cpt_tax_labels'] as $key => $label) {
342 if (empty($label)) {
343 unset($data['cpt_tax_labels'][$key]);
344 }
345 $label = str_replace('"', '', htmlspecialchars_decode($label));
346 $label = htmlspecialchars($label, ENT_QUOTES);
347 $label = trim($label);
348 $data['cpt_tax_labels'][$key] = stripslashes_deep($label);
349 }
350
351 $label = ucwords(str_replace('_', ' ', $data['cpt_custom_tax']['name']));
352 if (!empty($data['cpt_custom_tax']['label'])) {
353 $label = str_replace('"', '', htmlspecialchars_decode($data['cpt_custom_tax']['label']));
354 $label = htmlspecialchars(stripslashes($label), ENT_QUOTES);
355 }
356
357 $name = trim($data['cpt_custom_tax']['name']);
358
359 $singular_label = ucwords(str_replace('_', ' ', $data['cpt_custom_tax']['name']));
360 if (!empty($data['cpt_custom_tax']['singular_label'])) {
361 $singular_label = str_replace('"', '', htmlspecialchars_decode($data['cpt_custom_tax']['singular_label']));
362 $singular_label = htmlspecialchars(stripslashes($singular_label));
363 }
364 $description = sanitize_textarea_field(stripslashes_deep($data['cpt_custom_tax']['description']));
365 $query_var_slug = trim($data['cpt_custom_tax']['query_var_slug']);
366 $rewrite_slug = trim($data['cpt_custom_tax']['rewrite_slug']);
367 $rest_base = trim($data['cpt_custom_tax']['rest_base']);
368 $rest_controller_class = trim($data['cpt_custom_tax']['rest_controller_class']);
369 $show_quickpanel_bulk = !empty($data['cpt_custom_tax']['show_in_quick_edit']) ? taxopress_disp_boolean($data['cpt_custom_tax']['show_in_quick_edit']) : '';
370 $show_in_filter = !empty($data['cpt_custom_tax']['show_in_filter']) ? taxopress_disp_boolean($data['cpt_custom_tax']['show_in_filter']) : '';
371 $order = !empty($data['cpt_custom_tax']['order']) ? sanitize_text_field($data['cpt_custom_tax']['order']) : 'asc';
372 $orderby = !empty($data['cpt_custom_tax']['orderby']) ? sanitize_text_field($data['cpt_custom_tax']['orderby']) : 'term_id';
373 $enable_taxopress_ordering = !empty($data['cpt_custom_tax']['enable_taxopress_ordering']) ? taxopress_disp_boolean($data['cpt_custom_tax']['enable_taxopress_ordering']) : 0;
374 $default_term = trim($data['cpt_custom_tax']['default_term']);
375
376 $meta_box_cb = trim($data['cpt_custom_tax']['meta_box_cb']);
377 // We may or may not need to force a boolean false keyword.
378 $maybe_false = strtolower(trim($data['cpt_custom_tax']['meta_box_cb']));
379 if ('false' === $maybe_false) {
380 $meta_box_cb = $maybe_false;
381 }
382
383 $internal_taxonomy_edit = true;
384
385 if (isset($data['taxonomy_external_edit']) || $name === 'media_tag') {
386 $internal_taxonomy_edit = false;
387 }
388
389 if ($internal_taxonomy_edit) {
390 $taxonomies[$data['cpt_custom_tax']['name']] = [
391 'name' => $name,
392 'label' => $label,
393 'singular_label' => $singular_label,
394 'description' => $description,
395 'public' => taxopress_disp_boolean($data['cpt_custom_tax']['public']),
396 'publicly_queryable' => taxopress_disp_boolean($data['cpt_custom_tax']['publicly_queryable']),
397 'include_in_result' => taxopress_disp_boolean($data['cpt_custom_tax']['include_in_result']),
398 'hierarchical' => taxopress_disp_boolean($data['cpt_custom_tax']['hierarchical']),
399 'show_ui' => taxopress_disp_boolean($data['cpt_custom_tax']['show_ui']),
400 'show_in_menu' => taxopress_disp_boolean($data['cpt_custom_tax']['show_in_menu']),
401 'show_in_nav_menus' => taxopress_disp_boolean($data['cpt_custom_tax']['show_in_nav_menus']),
402 'query_var' => taxopress_disp_boolean($data['cpt_custom_tax']['query_var']),
403 'query_var_slug' => $query_var_slug,
404 'rewrite' => taxopress_disp_boolean($data['cpt_custom_tax']['rewrite']),
405 'rewrite_slug' => $rewrite_slug,
406 'rewrite_withfront' => $data['cpt_custom_tax']['rewrite_withfront'],
407 'rewrite_hierarchical' => $data['cpt_custom_tax']['rewrite_hierarchical'],
408 'show_admin_column' => taxopress_disp_boolean($data['cpt_custom_tax']['show_admin_column']),
409 'show_in_rest' => taxopress_disp_boolean($data['cpt_custom_tax']['show_in_rest']),
410 'show_in_quick_edit' => $show_quickpanel_bulk,
411 'rest_base' => $rest_base,
412 'rest_controller_class' => $rest_controller_class,
413 'labels' => $data['cpt_tax_labels'],
414 'meta_box_cb' => $meta_box_cb,
415 'default_term' => $default_term,
416 'show_in_filter' => $show_in_filter,
417 'order' => $order,
418 'orderby' => $orderby,
419 'enable_taxopress_ordering' => $enable_taxopress_ordering,
420 ];
421
422 $taxonomies[$data['cpt_custom_tax']['name']]['object_types'] = isset($data['cpt_post_types']) ? $data['cpt_post_types'] : '';
423
424
425 /**
426 * Filters final data to be saved right before saving taxoomy data.
427 *
428 * @param array $taxonomies Array of final taxonomy data to save.
429 * @param string $name Taxonomy slug for taxonomy being saved.
430 */
431 $taxonomies = apply_filters('taxopress_pre_save_taxonomy', $taxonomies, $name);
432
433 /**
434 * Filters whether or not 3rd party options were saved successfully within taxonomy add/update.
435 *
436 * @param bool $value Whether or not someone else saved successfully. Default false.
437 * @param array $taxonomies Array of our updated taxonomies data.
438 * @param array $data Array of submitted taxonomy to update.
439 */
440 if (false === ($success = apply_filters('taxopress_taxonomy_update_save', false, $taxonomies, $data))) {
441 $success = update_option('taxopress_taxonomies', $taxonomies);
442 }
443 } else {
444 $external_taxonomies[$data['cpt_custom_tax']['name']] = [
445 'name' => $name,
446 'label' => $label,
447 'singular_label' => $singular_label,
448 'description' => $description,
449 'public' => taxopress_disp_boolean($data['cpt_custom_tax']['public']),
450 'publicly_queryable' => taxopress_disp_boolean($data['cpt_custom_tax']['publicly_queryable']),
451 'include_in_result' => taxopress_disp_boolean($data['cpt_custom_tax']['include_in_result']),
452 'hierarchical' => taxopress_disp_boolean($data['cpt_custom_tax']['hierarchical']),
453 'show_ui' => taxopress_disp_boolean($data['cpt_custom_tax']['show_ui']),
454 'show_in_menu' => taxopress_disp_boolean($data['cpt_custom_tax']['show_in_menu']),
455 'show_in_nav_menus' => taxopress_disp_boolean($data['cpt_custom_tax']['show_in_nav_menus']),
456 'query_var' => taxopress_disp_boolean($data['cpt_custom_tax']['query_var']),
457 'query_var_slug' => $query_var_slug,
458 'rewrite' => taxopress_disp_boolean($data['cpt_custom_tax']['rewrite']),
459 'rewrite_slug' => $rewrite_slug,
460 'rewrite_withfront' => $data['cpt_custom_tax']['rewrite_withfront'],
461 'rewrite_hierarchical' => $data['cpt_custom_tax']['rewrite_hierarchical'],
462 'show_admin_column' => taxopress_disp_boolean($data['cpt_custom_tax']['show_admin_column']),
463 'show_in_rest' => taxopress_disp_boolean($data['cpt_custom_tax']['show_in_rest']),
464 'show_in_quick_edit' => $show_quickpanel_bulk,
465 'rest_base' => $rest_base,
466 'rest_controller_class' => $rest_controller_class,
467 'labels' => $data['cpt_tax_labels'],
468 'meta_box_cb' => $meta_box_cb,
469 'default_term' => $default_term,
470 'show_in_filter' => $show_in_filter,
471 'order' => $order,
472 'orderby' => $orderby,
473 'enable_taxopress_ordering' => $enable_taxopress_ordering,
474 ];
475
476 $external_taxonomies[$data['cpt_custom_tax']['name']]['object_types'] = isset($data['cpt_post_types']) ? $data['cpt_post_types'] : [];
477 $success = update_option(
478 'taxopress_external_taxonomies',
479 $external_taxonomies
480 );
481 }
482
483 /**
484 * Fires after a taxonomy is updated to our saved options.
485 *
486 *
487 * @param array $data Array of taxonomy data that was updated.
488 */
489 do_action('taxopress_after_update_taxonomy', $data);
490
491 // Used to help flush rewrite rules on init.
492 set_transient('taxopress_flush_rewrite_rules', 'true', 5 * 60);
493
494 if (isset($success) && 'new' === $data['cpt_tax_status']) {
495 return 'add_success';
496 }
497
498 return 'update_success';
499 }
500
501 /**
502 * Return an array of names that users should not or can not use for taxonomy names.
503 *
504 * @return array $value Array of names that are recommended against.
505 */
506 function taxopress_reserved_taxonomies()
507 {
508
509 $reserved = [
510 'action',
511 'attachment',
512 'attachment_id',
513 'author',
514 'author_name',
515 'calendar',
516 'cat',
517 'category',
518 'category__and',
519 'category__in',
520 'category__not_in',
521 'category_name',
522 'comments_per_page',
523 'comments_popup',
524 'customize_messenger_channel',
525 'customized',
526 'cpage',
527 'day',
528 'debug',
529 'error',
530 'exact',
531 'feed',
532 'fields',
533 'hour',
534 'include',
535 'link_category',
536 'm',
537 'minute',
538 'monthnum',
539 'more',
540 'name',
541 'nav_menu',
542 'nonce',
543 'nopaging',
544 'offset',
545 'order',
546 'orderby',
547 'p',
548 'page',
549 'page_id',
550 'paged',
551 'pagename',
552 'pb',
553 'perm',
554 'post',
555 'post__in',
556 'post__not_in',
557 'post_format',
558 'post_mime_type',
559 'post_status',
560 'post_tag',
561 'post_type',
562 'posts',
563 'posts_per_archive_page',
564 'posts_per_page',
565 'preview',
566 'robots',
567 's',
568 'search',
569 'second',
570 'sentence',
571 'showposts',
572 'static',
573 'subpost',
574 'subpost_id',
575 'tag',
576 'tag__and',
577 'tag__in',
578 'tag__not_in',
579 'tag_id',
580 'tag_slug__and',
581 'tag_slug__in',
582 'taxonomy',
583 'tb',
584 'term',
585 'theme',
586 'type',
587 'types',
588 'w',
589 'withcomments',
590 'withoutcomments',
591 'year',
592 'output',
593 ];
594
595 /**
596 * Filters the list of reserved post types to check against.
597 * 3rd party plugin authors could use this to prevent duplicate post types.
598 *
599 *
600 * @param array $value Array of post type slugs to forbid.
601 */
602 $custom_reserved = apply_filters('taxopress_reserved_taxonomies', []);
603
604 if (is_string($custom_reserved) && !empty($custom_reserved)) {
605 $reserved[] = $custom_reserved;
606 } elseif (is_array($custom_reserved) && !empty($custom_reserved)) {
607 foreach ($custom_reserved as $slug) {
608 $reserved[] = $slug;
609 }
610 }
611
612 return $reserved;
613 }
614
615 /**
616 * Convert taxonomies.
617 *
618 * @param string $original_slug Original taxonomy slug. Optional. Default empty string.
619 * @param string $new_slug New taxonomy slug. Optional. Default empty string.
620 * @internal
621 *
622 */
623 function taxopress_convert_taxonomy_terms($original_slug = '', $new_slug = '')
624 {
625 global $wpdb;
626
627 $args = [
628 'taxonomy' => $original_slug,
629 'hide_empty' => false,
630 'fields' => 'ids',
631 ];
632
633 $term_ids = get_terms($args);
634
635 if (is_int($term_ids)) {
636 $term_ids = (array)$term_ids;
637 }
638
639 if (is_array($term_ids) && !empty($term_ids)) {
640 // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- Term IDs are integers from array, safely imploded
641 $term_ids = implode(',', $term_ids);
642
643 $query = "UPDATE `{$wpdb->term_taxonomy}` SET `taxonomy` = %s WHERE `taxonomy` = %s AND `term_id` IN ( {$term_ids} )";
644
645 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared -- Term IDs safely imploded; direct query necessary for bulk taxonomy update
646 $wpdb->query($wpdb->prepare($query, $new_slug, $original_slug));
647 }
648 taxopress_delete_taxonomy($original_slug);
649 }
650
651 /**
652 * Checks if we are trying to register an already registered taxonomy slug.
653 *
654 * @param bool $slug_exists Whether or not the post type slug exists. Optional. Default false.
655 * @param string $taxonomy_slug The post type slug being saved. Optional. Default empty string.
656 * @param array $taxonomies Array of TAXOPRESS-registered post types. Optional.
657 *
658 * @return bool
659 */
660 function taxopress_check_existing_taxonomy_slugs($slug_exists = false, $taxonomy_slug = '', $taxonomies = [])
661 {
662
663 // If true, then we'll already have a conflict, let's not re-process.
664 if (true === $slug_exists) {
665 return $slug_exists;
666 }
667
668 // Check if TAXOPRESS has already registered this slug.
669 if (array_key_exists(strtolower($taxonomy_slug), $taxonomies)) {
670 return true;
671 }
672
673 // Check if we're registering a reserved post type slug.
674 if (in_array($taxonomy_slug, taxopress_reserved_taxonomies())) {
675 return true;
676 }
677
678 // Check if other plugins have registered this same slug.
679 $public = get_taxonomies(['_builtin' => false, 'public' => true]);
680 $private = get_taxonomies(['_builtin' => false, 'public' => false]);
681 $registered_taxonomies = array_merge($public, $private);
682 if (in_array($taxonomy_slug, $registered_taxonomies)) {
683 return true;
684 }
685
686 // phpcs:ignore Squiz.PHP.CommentedOutCode.Found -- Reference comment for logic tracking
687 // If we're this far, it's false.
688 return $slug_exists;
689 }
690
691 add_filter('taxopress_taxonomy_slug_exists', 'taxopress_check_existing_taxonomy_slugs', 10, 3);
692
693 /**
694 * Handle the save and deletion of taxonomy data.
695 */
696 function taxopress_process_taxonomy()
697 {
698
699 if (wp_doing_ajax()) {
700 return;
701 }
702
703 if (!is_admin()) {
704 return;
705 }
706
707 if (empty($_GET)) {
708 return;
709 }
710
711 if (!isset($_GET['page'])) {
712 return;
713 }
714 if ('st_taxonomies' !== $_GET['page']) {
715 return;
716 }
717
718 if (!current_user_can('simple_tags')) {
719 return;
720 }
721
722 if (isset($_GET['new_taxonomy'])) {
723 if ((int)$_GET['new_taxonomy'] === 1) {
724 add_action('admin_notices', "taxopress_add_success_message_admin_notice");
725 add_filter('removable_query_args', 'taxopress_filter_removable_query_args_3');
726 }
727 }
728
729 if (!empty($_POST) && (isset($_POST['cpt_submit']) || isset($_POST['cpt_delete']))) {
730 $result = '';
731 if (isset($_POST['cpt_submit'])) {
732 check_admin_referer('taxopress_addedit_taxonomy_nonce_action', 'taxopress_addedit_taxonomy_nonce_field');
733 $result = taxopress_update_taxonomy($_POST);
734 } elseif (isset($_POST['cpt_delete'])) {
735 check_admin_referer('taxopress_addedit_taxonomy_nonce_action', 'taxopress_addedit_taxonomy_nonce_field');
736 $result = taxopress_delete_taxonomy($_POST);
737 add_filter('taxopress_taxonomy_deleted', '__return_true');
738 }
739
740 if ($result && is_callable("taxopress_{$result}_admin_notice")) {
741 if ($result === 'add_success') {
742 taxopress_add_success_admin_notice();
743 } else {
744 add_action('admin_notices', "taxopress_{$result}_admin_notice");
745 }
746 }
747
748 if (isset($_POST['cpt_delete'])) {
749 wp_safe_redirect(
750 add_query_arg(
751 ['page' => 'st_taxonomies'],
752 taxopress_admin_url('admin.php?page=st_taxonomies')
753 )
754 );
755 exit();
756 }
757 } elseif (isset($_REQUEST['action']) && $_REQUEST['action'] === 'taxopress-deactivate-taxonomy') {
758 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated -- Nonce verified below
759 $nonce = isset($_REQUEST['_wpnonce']) ? sanitize_text_field(wp_unslash($_REQUEST['_wpnonce'])) : '';
760 if (wp_verify_nonce($nonce, 'taxonomy-action-request-nonce')) {
761 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated -- Nonce verified above
762 $taxonomy = isset($_REQUEST['taxonomy']) ? sanitize_text_field(wp_unslash($_REQUEST['taxonomy'])) : '';
763 taxopress_deactivate_taxonomy($taxonomy);
764 add_action('admin_notices', "taxopress_deactivated_admin_notice");
765 }
766 add_filter('removable_query_args', 'taxopress_filter_removable_query_args');
767 } elseif (isset($_REQUEST['action']) && $_REQUEST['action'] === 'taxopress-reactivate-taxonomy') {
768 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated -- Nonce verified below
769 $nonce = isset($_REQUEST['_wpnonce']) ? sanitize_text_field(wp_unslash($_REQUEST['_wpnonce'])) : '';
770 if (wp_verify_nonce($nonce, 'taxonomy-action-request-nonce')) {
771 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated -- Nonce verified above
772 $taxonomy = isset($_REQUEST['taxonomy']) ? sanitize_text_field(wp_unslash($_REQUEST['taxonomy'])) : '';
773 taxopress_activate_taxonomy($taxonomy);
774 add_action('admin_notices', "taxopress_activated_admin_notice");
775 }
776 add_filter('removable_query_args', 'taxopress_filter_removable_query_args');
777 } elseif (isset($_REQUEST['action']) && $_REQUEST['action'] === 'taxopress-delete-taxonomy') {
778 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated -- Nonce verified below
779 $nonce = isset($_REQUEST['_wpnonce']) ? sanitize_text_field(wp_unslash($_REQUEST['_wpnonce'])) : '';
780 if (wp_verify_nonce($nonce, 'taxonomy-action-request-nonce')) {
781 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated -- Nonce verified above
782 $taxonomy = isset($_REQUEST['taxonomy']) ? sanitize_text_field(wp_unslash($_REQUEST['taxonomy'])) : '';
783 taxopress_action_delete_taxonomy($taxonomy);
784 }
785 add_filter('removable_query_args', 'taxopress_filter_removable_query_args');
786 } elseif (isset($_REQUEST['action2']) && $_REQUEST['action2'] === 'taxopress-reactivate-taxonomy') {
787 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated -- Nonce verified below
788 $nonce = isset($_REQUEST['_wpnonce']) ? sanitize_text_field(wp_unslash($_REQUEST['_wpnonce'])) : '';
789 if (wp_verify_nonce($nonce, 'taxonomy-action-request-nonce')) {
790 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated -- Nonce verified above
791 $taxonomy = isset($_REQUEST['taxonomy']) ? sanitize_text_field(wp_unslash($_REQUEST['taxonomy'])) : '';
792 taxopress_activate_taxonomy($taxonomy);
793 add_action('admin_notices', "taxopress_activated_admin_notice");
794 }
795 add_filter('removable_query_args', 'taxopress_filter_removable_query_args_2');
796 } elseif (isset($_REQUEST['action2']) && $_REQUEST['action2'] === 'taxopress-deactivate-taxonomy') {
797 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated -- Nonce verified below
798 $nonce = isset($_REQUEST['_wpnonce']) ? sanitize_text_field(wp_unslash($_REQUEST['_wpnonce'])) : '';
799 if (wp_verify_nonce($nonce, 'taxonomy-action-request-nonce')) {
800 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated -- Nonce verified above
801 $taxonomy = isset($_REQUEST['taxonomy']) ? sanitize_text_field(wp_unslash($_REQUEST['taxonomy'])) : '';
802 taxopress_deactivate_taxonomy($taxonomy);
803 add_action('admin_notices', "taxopress_deactivated_admin_notice");
804 }
805 add_filter('removable_query_args', 'taxopress_filter_removable_query_args_2');
806 }
807 }
808
809
810 /**
811 * Handle the conversion of taxonomy terms.
812 *
813 * This function came to be because we needed to convert AFTER registration.
814 */
815 function taxopress_do_convert_taxonomy_terms()
816 {
817
818 /**
819 * Whether or not to convert taxonomy terms.
820 *
821 * @param bool $value Whether or not to convert.
822 */
823 if (apply_filters('taxopress_convert_taxonomy_terms', false)) {
824 check_admin_referer('taxopress_addedit_taxonomy_nonce_action', 'taxopress_addedit_taxonomy_nonce_field');
825
826 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated -- Nonce verified by check_admin_referer above
827 $tax_original = isset($_POST['tax_original']) ? sanitize_text_field(wp_unslash($_POST['tax_original'])) : '';
828 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated -- Nonce verified by check_admin_referer above
829 $cpt_name = isset($_POST['cpt_custom_tax']['name']) ? sanitize_text_field(wp_unslash($_POST['cpt_custom_tax']['name'])) : '';
830 taxopress_convert_taxonomy_terms($tax_original, $cpt_name);
831 }
832 }
833
834 /**
835 * Handles slug_exist checks for cases of editing an existing taxonomy.
836 *
837 * @param bool $slug_exists Current status for exist checks.
838 * @param string $taxonomy_slug Taxonomy slug being processed.
839 * @param array $taxonomies TAXOPRESS taxonomies.
840 * @return bool
841 */
842 function taxopress_updated_taxonomy_slug_exists($slug_exists, $taxonomy_slug = '', $taxonomies = [])
843 {
844 if (
845 // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Function called after nonce verification in parent handler
846 (isset($_POST['cpt_tax_status']) && 'edit' === $_POST['cpt_tax_status']) && !in_array($taxonomy_slug, taxopress_reserved_taxonomies(), true) &&
847 // phpcs:ignore WordPress.Security.NonceVerification.Missing
848 (isset($_POST['tax_original']) && $taxonomy_slug === $_POST['tax_original'])
849 ) {
850 $slug_exists = false;
851 }
852
853 return $slug_exists;
854 }
855
856 add_filter('taxopress_taxonomy_slug_exists', 'taxopress_updated_taxonomy_slug_exists', 11, 3);
857
858
859 /**
860 * Return boolean status depending on passed in value.
861 *
862 * @param mixed $bool_text text to compare to typical boolean values.
863 * @return bool Which bool value the passed in value was.
864 */
865 function get_taxopress_disp_boolean($bool_text)
866 {
867 $bool_text = (string)$bool_text;
868 if (empty($bool_text) || '0' === $bool_text || 'false' === $bool_text) {
869 return false;
870 }
871
872 return true;
873 }
874
875 /**
876 * Return string versions of boolean values.
877 *
878 * @param string $bool_text String boolean value.
879 * @return string standardized boolean text.
880 */
881 function taxopress_disp_boolean($bool_text)
882 {
883 $bool_text = (string)$bool_text;
884 if (empty($bool_text) || '0' === $bool_text || 'false' === $bool_text) {
885 return 'false';
886 }
887
888 return 'true';
889 }
890
891 /**
892 * Conditionally flushes rewrite rules if we have reason to.
893 */
894 function taxopress_flush_rewrite_rules()
895 {
896
897 if (wp_doing_ajax()) {
898 return;
899 }
900
901 /*
902 * Wise men say that you should not do flush_rewrite_rules on init or admin_init. Due to the nature of our plugin
903 * and how new post types or taxonomies can suddenly be introduced, we need to...potentially. For this,
904 * we rely on a short lived transient. Only 5 minutes life span. If it exists, we do a soft flush before
905 * deleting the transient to prevent subsequent flushes. The only times the transient gets created, is if
906 * post types or taxonomies are created, updated, deleted, or imported. Any other time and this condition
907 * should not be met.
908 */
909 if ('true' === ($flush_it = get_transient('taxopress_flush_rewrite_rules'))) {
910 // phpcs:ignore WordPressVIPMinimum.Functions.RestrictedFunctions.flush_rewrite_rules_flush_rewrite_rules -- Necessary for custom taxonomy registration
911 flush_rewrite_rules(false);
912 // So we only run this once.
913 delete_transient('taxopress_flush_rewrite_rules');
914 }
915 }
916
917 /**
918 * Return the current action being done within TAXOPRESS context.
919 *
920 * @return string Current action being done by TAXOPRESS
921 */
922 function taxopress_get_current_action()
923 {
924 $current_action = '';
925 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reading GET parameter for display only, no state change
926 if (!empty($_GET) && isset($_GET['action'])) {
927 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
928 $current_action .= esc_textarea(sanitize_text_field($_GET['action']));
929 }
930
931 return $current_action;
932 }
933
934 /**
935 * Return an array of all taxonomy slugs from Custom Post Type UI.
936 *
937 * @return array TAXOPRESS taxonomy slugs.
938 */
939 function taxopress_get_taxonomy_slugs()
940 {
941 $taxonomies = get_option('taxopress_taxonomies');
942 if (!empty($taxonomies)) {
943 return array_keys($taxonomies);
944 }
945
946 return [];
947 }
948
949 /**
950 * Return the appropriate admin URL depending on our context.
951 *
952 * @param string $path URL path.
953 * @return string
954 */
955 function taxopress_admin_url($path)
956 {
957 if (is_multisite() && is_network_admin()) {
958 return network_admin_url($path);
959 }
960
961 return admin_url($path);
962 }
963
964 /**
965 * Construct action tag for `<form>` tag.
966 *
967 * @param object|string $ui TAXOPRESS Admin UI instance. Optional. Default empty string.
968 * @return string
969 */
970 function taxopress_get_post_form_action($ui = '')
971 {
972 /**
973 * Filters the string to be used in an `action=""` attribute.
974 */
975 return apply_filters('taxopress_post_form_action', '', $ui);
976 }
977
978 /**
979 * Display action tag for `<form>` tag.
980 *
981 * @param object $ui TAXOPRESS Admin UI instance.
982 */
983 function taxopress_post_form_action($ui)
984 {
985 echo esc_attr(taxopress_get_post_form_action($ui));
986 }
987
988 /**
989 * Fetch our TAXOPRESS taxonomies option.
990 *
991 * @return mixed
992 */
993 function taxopress_get_taxonomy_data()
994 {
995 $data = apply_filters('taxopress_get_taxonomy_data', get_option('taxopress_taxonomies', []), get_current_blog_id());
996 return is_array($data) ? $data : [];
997 }
998
999 /**
1000 * Fetch both internal and external edited taxopress taxonomies
1001 *
1002 * @return mixed
1003 */
1004 function taxopress_get_all_edited_taxonomy_data()
1005 {
1006 $internal_taxonomies = (array) taxopress_get_taxonomy_data();
1007 $external_taxonomies = (array) taxopress_get_extername_taxonomy_data();
1008
1009 $all_taxonomies = array_merge($internal_taxonomies, $external_taxonomies);
1010
1011 return array_filter($all_taxonomies);
1012 }
1013
1014
1015
1016
1017 /**
1018 * Fetch our TAXOPRESS taxonomies option.
1019 *
1020 * @return mixed
1021 */
1022 function taxopress_get_extername_taxonomy_data()
1023 {
1024 return array_filter((array)apply_filters(
1025 'taxopress_get_extername_taxonomy_data',
1026 get_option('taxopress_external_taxonomies', []),
1027 get_current_blog_id()
1028 ));
1029 }
1030
1031
1032 /**
1033 * Checks if a taxonomy is already registered.
1034 *
1035 * @param string $slug Taxonomy slug to check. Optional. Default empty string.
1036 * @param array|string $data Taxonomy data being utilized. Optional.
1037 *
1038 * @return mixed
1039 */
1040 function taxopress_get_taxonomy_exists($slug = '', $data = [])
1041 {
1042
1043 /**
1044 * Filters the boolean value for if a taxonomy exists for 3rd parties.
1045 *
1046 * @param string $slug Taxonomy slug to check.
1047 * @param array|string $data Taxonomy data being utilized.
1048 */
1049 return apply_filters('taxopress_get_taxonomy_exists', taxonomy_exists($slug), $data);
1050 }
1051
1052 /**
1053 * Secondary admin notices function for use with admin_notices hook.
1054 *
1055 * Constructs admin notice HTML.
1056 *
1057 * @param string $message Message to use in admin notice. Optional. Default empty string.
1058 * @param bool $success Whether or not a success. Optional. Default true.
1059 * @return mixed
1060 */
1061 function taxopress_admin_notices_helper($message = '', $success = true)
1062 {
1063
1064 $class = [];
1065 $class[] = $success ? 'updated' : 'error';
1066 $class[] = 'notice is-dismissible taxopress-notice';
1067
1068 $messagewrapstart = '<div id="message" class="' . esc_attr(implode(' ', $class)) . '"><p>';
1069
1070 $messagewrapend = '</p></div>';
1071
1072 $action = '';
1073
1074 /**
1075 * Filters the custom admin notice for TAXOPRESS.
1076 *
1077 *
1078 * @param string $value Complete HTML output for notice.
1079 * @param string $action Action whose message is being generated.
1080 * @param string $message The message to be displayed.
1081 * @param string $messagewrapstart Beginning wrap HTML.
1082 * @param string $messagewrapend Ending wrap HTML.
1083 */
1084 return apply_filters(
1085 'taxopress_admin_notice',
1086 $messagewrapstart . $message . $messagewrapend,
1087 $action,
1088 $message,
1089 $messagewrapstart,
1090 $messagewrapend
1091 );
1092 }
1093
1094 /**
1095 * Grab post type or taxonomy slug from $_POST global, if available.
1096 *
1097 * @return string
1098 * @internal
1099 *
1100 */
1101 function taxopress_get_object_from_post_global()
1102 {
1103 // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Helper function called after nonce verification in parent handler
1104 if (isset($_POST['cpt_custom_post_type']['name'])) {
1105 // phpcs:ignore WordPress.Security.NonceVerification.Missing
1106 return sanitize_text_field($_POST['cpt_custom_post_type']['name']);
1107 }
1108
1109 // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Helper function called after nonce verification in parent handler
1110 if (isset($_POST['cpt_custom_tax']['name'])) {
1111 // phpcs:ignore WordPress.Security.NonceVerification.Missing
1112 return sanitize_text_field($_POST['cpt_custom_tax']['name']);
1113 }
1114
1115 return esc_html__('Object', 'simple-tags');
1116 }
1117
1118 /**
1119 * Successful add callback.
1120 */
1121 function taxopress_add_success_admin_notice()
1122 {
1123 //redirect to new taxonomy if success
1124 wp_safe_redirect(
1125 add_query_arg(
1126 [
1127 'page' => 'st_taxonomies',
1128 'add' => 'taxonomy',
1129 'action' => 'edit',
1130 'taxopress_taxonomy' => taxopress_get_object_from_post_global(),
1131 'new_taxonomy' => 1,
1132 ],
1133 taxopress_admin_url('admin.php')
1134 )
1135 );
1136 exit();
1137 }
1138
1139 /**
1140 * Successful add callback.
1141 */
1142 function taxopress_add_success_message_admin_notice()
1143 {
1144 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reading GET parameter for display only, no state change
1145 $taxonomy = isset($_GET['taxopress_taxonomy']) ? sanitize_text_field(wp_unslash($_GET['taxopress_taxonomy'])) : '';
1146 echo wp_kses_post(
1147 taxopress_admin_notices_helper(
1148 sprintf(
1149 esc_html__('%s has been successfully added', 'simple-tags'),
1150 $taxonomy
1151 )
1152 )
1153 );
1154 }
1155
1156 /**
1157 * Fail to add callback.
1158 */
1159 function taxopress_add_fail_admin_notice()
1160 {
1161 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1162 echo taxopress_admin_notices_helper(
1163 sprintf(
1164 esc_html__('%s has failed to be added', 'simple-tags'),
1165 taxopress_get_object_from_post_global()
1166 ),
1167 false
1168 );
1169 }
1170
1171 /**
1172 * Successful update callback.
1173 */
1174 function taxopress_update_success_admin_notice()
1175 {
1176 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1177 echo taxopress_admin_notices_helper(
1178 sprintf(
1179 esc_html__('%s has been successfully updated', 'simple-tags'),
1180 taxopress_get_object_from_post_global()
1181 )
1182 );
1183 }
1184
1185 /**
1186 * Fail to update callback.
1187 */
1188 function taxopress_update_fail_admin_notice()
1189 {
1190 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1191 echo taxopress_admin_notices_helper(
1192 sprintf(
1193 esc_html__('%s has failed to be updated', 'simple-tags'),
1194 taxopress_get_object_from_post_global()
1195 ),
1196 false
1197 );
1198 }
1199
1200 /**
1201 * Successful delete callback.
1202 */
1203 function taxopress_delete_success_admin_notice()
1204 {
1205 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1206 echo taxopress_admin_notices_helper(
1207 sprintf(
1208 esc_html__('%s has been successfully deleted', 'simple-tags'),
1209 taxopress_get_object_from_post_global()
1210 )
1211 );
1212 }
1213
1214 /**
1215 * Fail to delete callback.
1216 */
1217 function taxopress_delete_fail_admin_notice()
1218 {
1219 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1220 echo taxopress_admin_notices_helper(
1221 sprintf(
1222 esc_html__('%s has failed to be deleted', 'simple-tags'),
1223 taxopress_get_object_from_post_global()
1224 ),
1225 false
1226 );
1227 }
1228
1229
1230 function taxopress_nonce_fail_admin_notice()
1231 {
1232 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1233 echo taxopress_admin_notices_helper(
1234 esc_html__('Nonce failed verification', 'simple-tags'),
1235 false
1236 );
1237 }
1238
1239 /**
1240 * Returns error message for if trying to register existing taxonomy.
1241 *
1242 * @return string
1243 */
1244 function taxopress_slug_matches_taxonomy()
1245 {
1246 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1247 return sprintf(
1248 esc_html__('Please choose a different taxonomy name. %s is already registered.', 'simple-tags'),
1249 taxopress_get_object_from_post_global()
1250 );
1251 }
1252
1253
1254 /**
1255 * Returns error message for if not providing a post type to associate taxonomy to.
1256 *
1257 * @return string
1258 */
1259 function taxopress_empty_cpt_on_taxonomy()
1260 {
1261 return esc_html__('Please provide a post type to attach to.', 'simple-tags');
1262 }
1263
1264 /**
1265 * Returns error message for if trying to register post type with matching page slug.
1266 *
1267 * @return string
1268 */
1269 function taxopress_slug_matches_page()
1270 {
1271 $slug = taxopress_get_object_from_post_global();
1272 $matched_slug = get_page_by_path(
1273 taxopress_get_object_from_post_global()
1274 );
1275 if ($matched_slug instanceof WP_Post) {
1276 $slug = sprintf(
1277 '<a href="%s">%s</a>',
1278 get_edit_post_link($matched_slug->ID),
1279 taxopress_get_object_from_post_global()
1280 );
1281 }
1282
1283 return sprintf(
1284 esc_html__(
1285 'Please choose a different post type name. %s matches an existing page slug, which can cause conflicts.',
1286 'simple-tags'
1287 ),
1288 $slug
1289 );
1290 }
1291
1292 /**
1293 * Returns error message for if trying to use quotes in slugs or rewrite slugs.
1294 *
1295 * @return string
1296 */
1297 function taxopress_slug_has_quotes()
1298 {
1299 return sprintf(
1300 esc_html__('Please do not use quotes in post type/taxonomy names or rewrite slugs', 'simple-tags'),
1301 taxopress_get_object_from_post_global()
1302 );
1303 }
1304
1305 /**
1306 * Error admin notice.
1307 */
1308 function taxopress_error_admin_notice()
1309 {
1310 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1311 echo taxopress_admin_notices_helper(
1312 apply_filters('taxopress_custom_error_message', ''),
1313 false
1314 );
1315 }
1316
1317 /**
1318 * Returns saved values for single taxonomy from TAXOPRESS settings.
1319 *
1320 * @param string $taxonomy Taxonomy to retrieve TAXOPRESS object for.
1321 * @return string
1322 */
1323 function taxopress_get_taxopress_taxonomy_object($taxonomy = '')
1324 {
1325 $taxonomies = get_option('taxopress_taxonomies');
1326
1327 // phpcs:ignore WordPressVIPMinimum.Functions.CheckReturnValue -- get_option returns false or array, checked before use
1328 if (is_array($taxonomies) && array_key_exists($taxonomy, $taxonomies)) {
1329 return $taxonomies[$taxonomy];
1330 }
1331
1332 return '';
1333 }
1334
1335
1336 /**
1337 * Register our users' custom taxonomies.
1338 *
1339 * @internal
1340 */
1341 function taxopress_create_custom_taxonomies()
1342 {
1343 $taxes = get_option('taxopress_taxonomies');
1344
1345 if (empty($taxes)) {
1346 return;
1347 }
1348
1349 /**
1350 * Fires before the start of the taxonomy registrations.
1351 *
1352 * @param array $taxes Array of taxonomies to register.
1353 */
1354 do_action('taxopress_pre_register_taxonomies', $taxes);
1355
1356 if (is_array($taxes)) {
1357 foreach ($taxes as $tax) {
1358 /**
1359 * Filters whether or not to skip registration of the current iterated taxonomy.
1360 *
1361 * Dynamic part of the filter name is the chosen taxonomy slug.
1362 *
1363 * @param bool $value Whether or not to skip the taxonomy.
1364 * @param array $tax Current taxonomy being registered.
1365 */
1366 if ((bool)apply_filters("taxopress_disable_{$tax['name']}_tax", false, $tax)) {
1367 continue;
1368 }
1369
1370 /**
1371 * Filters whether or not to skip registration of the current iterated taxonomy.
1372 *
1373 * @param bool $value Whether or not to skip the taxonomy.
1374 * @param array $tax Current taxonomy being registered.
1375 */
1376 if ((bool)apply_filters('taxopress_disable_tax', false, $tax)) {
1377 continue;
1378 }
1379
1380 taxopress_register_single_taxonomy($tax);
1381 }
1382 }
1383
1384 /**
1385 * Fires after the completion of the taxonomy registrations.
1386 *
1387 * @param array $taxes Array of taxonomies registered.
1388 */
1389 do_action('taxopress_post_register_taxonomies', $taxes);
1390 }
1391
1392 /**
1393 * Helper function to register the actual taxonomy.
1394 *
1395 * @param array $taxonomy Taxonomy array to register. Optional.
1396 * @return null Result of register_taxonomy.
1397 * @internal
1398 *
1399 */
1400 function taxopress_register_single_taxonomy($taxonomy = [])
1401 {
1402 $labels = [
1403 'name' => $taxonomy['label'],
1404 'singular_name' => $taxonomy['singular_label'],
1405 ];
1406
1407 $description = '';
1408 if (!empty($taxonomy['description'])) {
1409 $description = $taxonomy['description'];
1410 }
1411
1412 $preserved = taxopress_get_preserved_keys('taxonomies');
1413 $preserved_labels = taxopress_get_preserved_labels();
1414 foreach ($taxonomy['labels'] as $key => $label) {
1415 if (!empty($label)) {
1416 $labels[$key] = $label;
1417 } elseif (empty($label) && in_array($key, $preserved, true)) {
1418 $singular_or_plural = (in_array(
1419 $key,
1420 array_keys($preserved_labels['taxonomies']['plural'])
1421 )) ? 'plural' : 'singular';
1422 $label_plurality = ('plural' === $singular_or_plural) ? $taxonomy['label'] : $taxonomy['singular_label'];
1423 $labels[$key] = sprintf($preserved_labels['taxonomies'][$singular_or_plural][$key], $label_plurality);
1424 }
1425 }
1426
1427 $rewrite = get_taxopress_disp_boolean($taxonomy['rewrite']);
1428 if (false !== get_taxopress_disp_boolean($taxonomy['rewrite'])) {
1429 $rewrite = [];
1430 $rewrite['slug'] = !empty($taxonomy['rewrite_slug']) ? $taxonomy['rewrite_slug'] : $taxonomy['name'];
1431 $rewrite['with_front'] = true;
1432 if (isset($taxonomy['rewrite_withfront'])) {
1433 $rewrite['with_front'] = ('false' === taxopress_disp_boolean($taxonomy['rewrite_withfront'])) ? false : true;
1434 }
1435 $rewrite['hierarchical'] = false;
1436 if (isset($taxonomy['rewrite_hierarchical'])) {
1437 $rewrite['hierarchical'] = ('true' === taxopress_disp_boolean($taxonomy['rewrite_hierarchical'])) ? true : false;
1438 }
1439 }
1440
1441 if (in_array($taxonomy['query_var'], ['true', 'false', '0', '1'], true)) {
1442 $taxonomy['query_var'] = get_taxopress_disp_boolean($taxonomy['query_var']);
1443 }
1444 if (true === $taxonomy['query_var'] && !empty($taxonomy['query_var_slug'])) {
1445 $taxonomy['query_var'] = $taxonomy['query_var_slug'];
1446 }
1447
1448 $public = (!empty($taxonomy['public']) && false === get_taxopress_disp_boolean($taxonomy['public'])) ? false : true;
1449 $publicly_queryable = (!empty($taxonomy['publicly_queryable']) && false === get_taxopress_disp_boolean($taxonomy['publicly_queryable'])) ? false : true;
1450 if (empty($taxonomy['publicly_queryable'])) {
1451 $publicly_queryable = $public;
1452 }
1453
1454 $show_admin_column = (!empty($taxonomy['show_admin_column']) && false !== get_taxopress_disp_boolean($taxonomy['show_admin_column'])) ? true : false;
1455
1456 $show_in_menu = (!empty($taxonomy['show_in_menu']) && false !== get_taxopress_disp_boolean($taxonomy['show_in_menu'])) ? true : false;
1457
1458 if (empty($taxonomy['show_in_menu'])) {
1459 $show_in_menu = get_taxopress_disp_boolean($taxonomy['show_ui']);
1460 }
1461
1462 $show_in_nav_menus = (!empty($taxonomy['show_in_nav_menus']) && false !== get_taxopress_disp_boolean($taxonomy['show_in_nav_menus'])) ? true : false;
1463 if (empty($taxonomy['show_in_nav_menus'])) {
1464 $show_in_nav_menus = $public;
1465 }
1466
1467 $show_in_rest = (!empty($taxonomy['show_in_rest']) && false !== get_taxopress_disp_boolean($taxonomy['show_in_rest'])) ? true : false;
1468
1469 $show_in_quick_edit = (!empty($taxonomy['show_in_quick_edit']) && false !== get_taxopress_disp_boolean($taxonomy['show_in_quick_edit'])) ? true : false;
1470
1471 $show_in_filter = (!empty($taxonomy['show_in_filter']) && false !== get_taxopress_disp_boolean($taxonomy['show_in_filter'])) ? true : false;
1472
1473 $rest_base = null;
1474 if (!empty($taxonomy['rest_base'])) {
1475 $rest_base = $taxonomy['rest_base'];
1476 }
1477
1478 $rest_controller_class = null;
1479 if (!empty($post_type['rest_controller_class'])) {
1480 $rest_controller_class = $post_type['rest_controller_class'];
1481 }
1482
1483 $meta_box_cb = null;
1484 if (!empty($taxonomy['meta_box_cb'])) {
1485 $meta_box_cb = (false !== get_taxopress_disp_boolean($taxonomy['meta_box_cb'])) ? $taxonomy['meta_box_cb'] : false;
1486 }
1487 $default_term = null;
1488 if (!empty($taxonomy['default_term'])) {
1489 $term_parts = explode(',', $taxonomy['default_term']);
1490 $term_parts = array_filter($term_parts);
1491 if (!empty($term_parts)) {
1492 $default_term = [];
1493 foreach ($term_parts as $term_part) {
1494 $default_term[] = ['name' => $term_part, 'slug' => $term_part];
1495 }
1496 }
1497 }
1498
1499 $args = [
1500 'labels' => $labels,
1501 'label' => $taxonomy['label'],
1502 'description' => $description,
1503 'public' => $public,
1504 'publicly_queryable' => $publicly_queryable,
1505 'hierarchical' => get_taxopress_disp_boolean($taxonomy['hierarchical']),
1506 'show_ui' => get_taxopress_disp_boolean($taxonomy['show_ui']),
1507 'show_in_menu' => $show_in_menu,
1508 'show_in_nav_menus' => $show_in_nav_menus,
1509 'query_var' => $taxonomy['query_var'],
1510 'rewrite' => $rewrite,
1511 'show_admin_column' => $show_admin_column,
1512 'show_in_rest' => $show_in_rest,
1513 'rest_base' => $rest_base,
1514 'rest_controller_class' => $rest_controller_class,
1515 'show_in_quick_edit' => $show_in_quick_edit,
1516 'show_in_filter' => $show_in_filter,
1517 'meta_box_cb' => $meta_box_cb,
1518 'default_term' => $default_term,
1519 ];
1520
1521 $object_type = !empty($taxonomy['object_types']) ? $taxonomy['object_types'] : '';
1522
1523 /**
1524 * Filters the arguments used for a taxonomy right before registering.
1525 *
1526 * @param array $args Array of arguments to use for registering taxonomy.
1527 * @param string $value Taxonomy slug to be registered.
1528 * @param array $taxonomy Original passed in values for taxonomy.
1529 * @param array $object_type Array of chosen post types for the taxonomy.
1530 */
1531 $args = apply_filters('taxopress_pre_register_taxonomy', $args, $taxonomy['name'], $taxonomy, $object_type);
1532
1533 return register_taxonomy($taxonomy['name'], $object_type, $args);
1534 }
1535
1536
1537 /**
1538 * Return a notice based on conditions.
1539 *
1540 * @param string $action The type of action that occurred. Optional. Default empty string.
1541 * @param string $object_type Whether it's from a post type or taxonomy. Optional. Default empty string.
1542 * @param bool $success Whether the action succeeded or not. Optional. Default true.
1543 * @param string $custom Custom message if necessary. Optional. Default empty string.
1544 * @return bool|string false on no message, else HTML div with our notice message.
1545 */
1546 function taxopress_admin_notices($action = '', $object_type = '', $success = true, $custom = '')
1547 {
1548 $class = [];
1549 $class[] = $success ? 'updated' : 'error';
1550 $class[] = 'notice is-dismissible taxopress-notice';
1551 $object_type = esc_attr($object_type);
1552
1553 $messagewrapstart = '<div id="message" class="' . implode(' ', $class) . '"><p>';
1554 $message = '';
1555
1556 $messagewrapend = '</p></div>';
1557
1558 if ('add' === $action) {
1559 if ($success) {
1560 $message .= sprintf(__('%s has been successfully added', 'simple-tags'), $object_type);
1561 } else {
1562 $message .= sprintf(__('%s has failed to be added', 'simple-tags'), $object_type);
1563 }
1564 } elseif ('update' === $action) {
1565 if ($success) {
1566 $message .= sprintf(__('%s has been successfully updated', 'simple-tags'), $object_type);
1567 } else {
1568 $message .= sprintf(__('%s has failed to be updated', 'simple-tags'), $object_type);
1569 }
1570 } elseif ('delete' === $action) {
1571 if ($success) {
1572 $message .= sprintf(__('%s has been successfully deleted', 'simple-tags'), $object_type);
1573 } else {
1574 $message .= sprintf(__('%s has failed to be deleted', 'simple-tags'), $object_type);
1575 }
1576 } elseif ('import' === $action) {
1577 if ($success) {
1578 $message .= sprintf(__('%s has been successfully imported', 'simple-tags'), $object_type);
1579 } else {
1580 $message .= sprintf(__('%s has failed to be imported', 'simple-tags'), $object_type);
1581 }
1582 } elseif ('error' === $action) {
1583 if (!empty($custom)) {
1584 $message = $custom;
1585 }
1586 }
1587
1588 if ($message) {
1589
1590 /**
1591 * Filters the custom admin notice for TAXOPRESS.
1592 *
1593 * @param string $value Complete HTML output for notice.
1594 * @param string $action Action whose message is being generated.
1595 * @param string $message The message to be displayed.
1596 * @param string $messagewrapstart Beginning wrap HTML.
1597 * @param string $messagewrapend Ending wrap HTML.
1598 */
1599 return apply_filters(
1600 'taxopress_admin_notice',
1601 $messagewrapstart . $message . $messagewrapend,
1602 $action,
1603 $message,
1604 $messagewrapstart,
1605 $messagewrapend
1606 );
1607 }
1608
1609 return false;
1610 }
1611
1612 /**
1613 * Return array of keys needing preserved.
1614 *
1615 * @param string $type Type to return. Either 'post_types' or 'taxonomies'. Optional. Default empty string.
1616 * @return array Array of keys needing preservered for the requested type.
1617 */
1618 function taxopress_get_preserved_keys($type = '')
1619 {
1620 $preserved_labels = [
1621 'post_types' => [
1622 'add_new_item',
1623 'edit_item',
1624 'new_item',
1625 'view_item',
1626 'view_items',
1627 'all_items',
1628 'search_items',
1629 'not_found',
1630 'not_found_in_trash',
1631 ],
1632 'taxonomies' => [
1633 'search_items',
1634 'popular_items',
1635 'all_items',
1636 'parent_item',
1637 'parent_item_colon',
1638 'edit_item',
1639 'update_item',
1640 'add_new_item',
1641 'new_item_name',
1642 'separate_items_with_commas',
1643 'add_or_remove_items',
1644 'choose_from_most_used',
1645 ],
1646 ];
1647
1648 return !empty($type) ? $preserved_labels[$type] : [];
1649 }
1650
1651 /**
1652 * Return label for the requested type and label key.
1653 *
1654 * @param string $type Type to return. Either 'post_types' or 'taxonomies'. Optional. Default empty string.
1655 * @param string $key Requested label key. Optional. Default empty string.
1656 * @param string $plural Plural verbiage for the requested label and type. Optional. Default empty string.
1657 * @param string $singular Singular verbiage for the requested label and type. Optional. Default empty string.
1658 * @return string Internationalized default label.
1659 * @deprecated
1660 *
1661 */
1662 function taxopress_get_preserved_label($type = '', $key = '', $plural = '', $singular = '')
1663 {
1664 $preserved_labels = [
1665 'post_types' => [
1666 'add_new_item' => sprintf(__('Add new %s', 'simple-tags'), $singular),
1667 'edit_item' => sprintf(__('Edit %s', 'simple-tags'), $singular),
1668 'new_item' => sprintf(__('New %s', 'simple-tags'), $singular),
1669 'view_item' => sprintf(__('View %s', 'simple-tags'), $singular),
1670 'view_items' => sprintf(__('View %s', 'simple-tags'), $plural),
1671 'all_items' => sprintf(__('All %s', 'simple-tags'), $plural),
1672 'search_items' => sprintf(__('Search %s', 'simple-tags'), $plural),
1673 'not_found' => sprintf(__('No %s found.', 'simple-tags'), $plural),
1674 'not_found_in_trash' => sprintf(__('No %s found in trash.', 'simple-tags'), $plural),
1675 ],
1676 'taxonomies' => [
1677 'search_items' => sprintf(__('Search %s', 'simple-tags'), $plural),
1678 'popular_items' => sprintf(__('Popular %s', 'simple-tags'), $plural),
1679 'all_items' => sprintf(__('All %s', 'simple-tags'), $plural),
1680 'parent_item' => sprintf(__('Parent %s', 'simple-tags'), $singular),
1681 'parent_item_colon' => sprintf(__('Parent %s:', 'simple-tags'), $singular),
1682 'edit_item' => sprintf(__('Edit %s', 'simple-tags'), $singular),
1683 'update_item' => sprintf(__('Update %s', 'simple-tags'), $singular),
1684 'add_new_item' => sprintf(__('Add new %s', 'simple-tags'), $singular),
1685 'new_item_name' => sprintf(__('New %s name', 'simple-tags'), $singular),
1686 'separate_items_with_commas' => sprintf(__('Separate %s with commas', 'simple-tags'), $plural),
1687 'add_or_remove_items' => sprintf(__('Add or remove %s', 'simple-tags'), $plural),
1688 'choose_from_most_used' => sprintf(__('Choose from the most used %s', 'simple-tags'), $plural),
1689 ],
1690 ];
1691
1692 return $preserved_labels[$type][$key];
1693 }
1694
1695 /**
1696 * Returns an array of translated labels, ready for use with sprintf().
1697 *
1698 * Replacement for taxopress_get_preserved_label for the sake of performance.
1699 *
1700 * @return array
1701 */
1702 function taxopress_get_preserved_labels()
1703 {
1704 return [
1705 'post_types' => [
1706 'singular' => [
1707 'add_new_item' => esc_html__('Add new %s', 'simple-tags'),
1708 'edit_item' => esc_html__('Edit %s', 'simple-tags'),
1709 'new_item' => esc_html__('New %s', 'simple-tags'),
1710 'view_item' => esc_html__('View %s', 'simple-tags'),
1711 ],
1712 'plural' => [
1713 'view_items' => esc_html__('View %s', 'simple-tags'),
1714 'all_items' => esc_html__('All %s', 'simple-tags'),
1715 'search_items' => esc_html__('Search %s', 'simple-tags'),
1716 'not_found' => esc_html__('No %s found.', 'simple-tags'),
1717 'not_found_in_trash' => esc_html__('No %s found in trash.', 'simple-tags'),
1718 ],
1719 ],
1720 'taxonomies' => [
1721 'singular' => [
1722 'parent_item' => esc_html__('Parent %s', 'simple-tags'),
1723 'parent_item_colon' => esc_html__('Parent %s:', 'simple-tags'),
1724 'edit_item' => esc_html__('Edit %s', 'simple-tags'),
1725 'update_item' => esc_html__('Update %s', 'simple-tags'),
1726 'add_new_item' => esc_html__('Add new %s', 'simple-tags'),
1727 'new_item_name' => esc_html__('New %s name', 'simple-tags'),
1728 ],
1729 'plural' => [
1730 'search_items' => esc_html__('Search %s', 'simple-tags'),
1731 'popular_items' => esc_html__('Popular %s', 'simple-tags'),
1732 'all_items' => esc_html__('All %s', 'simple-tags'),
1733 'separate_items_with_commas' => esc_html__('Separate %s with commas', 'simple-tags'),
1734 'add_or_remove_items' => esc_html__('Add or remove %s', 'simple-tags'),
1735 'choose_from_most_used' => esc_html__('Choose from the most used %s', 'simple-tags'),
1736 ],
1737 ],
1738 ];
1739 }
1740
1741
1742 function get_all_taxopress_taxonomies_request()
1743 {
1744
1745 $category = get_taxonomies(
1746 ['name' => 'category'],
1747 'objects'
1748 );
1749 $post_tag = get_taxonomies(
1750 ['name' => 'post_tag'],
1751 'objects'
1752 );
1753
1754 $public = get_taxonomies(['public' => true], 'objects');
1755 $private = get_taxonomies(['public' => false], 'objects');
1756
1757 if (!array_key_exists('category', $public) && !array_key_exists('category', $public)) {
1758 $public = array_merge($category, $public);
1759 }
1760 if (!array_key_exists('post_tag', $public) && !array_key_exists('post_tag', $public)) {
1761 $public = array_merge($post_tag, $public);
1762 }
1763
1764 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reading GET parameter for filtering display, no state change
1765 if (isset($_GET['taxonomy_type']) && $_GET['taxonomy_type'] === 'all') {
1766 $registered_taxonomies = array_merge($public, $private);
1767 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
1768 } elseif (isset($_GET['taxonomy_type']) && $_GET['taxonomy_type'] === 'private') {
1769 $registered_taxonomies = $private;
1770 } else {
1771 $registered_taxonomies = $public;
1772 }
1773
1774 return $registered_taxonomies;
1775 }
1776
1777
1778 function get_all_taxopress_taxonomies()
1779 {
1780
1781 $registered_taxonomies = get_taxonomies([], 'objects');
1782
1783 return $registered_taxonomies;
1784 }
1785
1786
1787 function get_all_taxopress_public_taxonomies()
1788 {
1789 return get_taxonomies(['public' => true], 'objects');
1790 }
1791
1792 /**
1793 * Return an array of all deactivated taxonomy.
1794 *
1795 * @return array TAXOPRESS taxonomy.
1796 */
1797 function taxopress_get_deactivated_taxonomy()
1798 {
1799 $taxonomies = get_option('taxopress_deactivated_taxonomies');
1800 if (!empty($taxonomies)) {
1801 return (array)$taxonomies;
1802 }
1803
1804 return [];
1805 }
1806
1807 /**
1808 * None callback.
1809 */
1810 function taxopress_noaction_admin_notice()
1811 {
1812 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1813 echo taxopress_admin_notices_helper(
1814 esc_html__('Kindly select an action in bulk action dropdown!', 'simple-tags'),
1815 false
1816 );
1817 }
1818
1819 /**
1820 * None callback.
1821 */
1822 function taxopress_none_admin_notice()
1823 {
1824 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1825 echo taxopress_admin_notices_helper(
1826 esc_html__('Kindly select atleast one taxonomy to proceed', 'simple-tags'),
1827 false
1828 );
1829 }
1830
1831 /**
1832 * Deactivated callback.
1833 */
1834 function taxopress_deactivated_admin_notice()
1835 {
1836 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1837 echo taxopress_admin_notices_helper(esc_html__('Taxonomy has been successfully deactivated', 'simple-tags'));
1838 }
1839
1840 /**
1841 * Activated callback.
1842 */
1843 function taxopress_activated_admin_notice()
1844 {
1845 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1846 echo taxopress_admin_notices_helper(esc_html__('Taxonomy has been successfully activated', 'simple-tags'));
1847 }
1848
1849 /**
1850 * Delete callback.
1851 */
1852 function taxopress_taxdeleted_admin_notice()
1853 {
1854 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1855 echo taxopress_admin_notices_helper(esc_html__('Taxonomy has been successfully deleted', 'simple-tags'));
1856 }
1857
1858 /**
1859 * Deactivated taxonomy.
1860 *
1861 * @return array TAXOPRESS taxonomy.
1862 */
1863 function taxopress_deactivate_taxonomy($term_object)
1864 {
1865 $all_taxonomies = (array)get_option('taxopress_deactivated_taxonomies');
1866 $all_taxonomies[] = $term_object;
1867 $all_taxonomies = array_unique(array_filter($all_taxonomies));
1868 $success = update_option('taxopress_deactivated_taxonomies', $all_taxonomies);
1869 }
1870
1871 /**
1872 * Activate taxonomy.
1873 *
1874 * @return array TAXOPRESS taxonomy.
1875 */
1876 function taxopress_activate_taxonomy($term_object)
1877 {
1878 $all_taxonomies = (array)get_option('taxopress_deactivated_taxonomies');
1879 if (($key = array_search($term_object, $all_taxonomies)) !== false) {
1880 unset($all_taxonomies[$key]);
1881 $success = update_option('taxopress_deactivated_taxonomies', $all_taxonomies);
1882 }
1883 }
1884
1885
1886 /**
1887 * Fetch our TAXOPRESS disabled taxonomies option.
1888 *
1889 * @return mixed
1890 */
1891 function taxopress_get_deactivated_taxonomy_data()
1892 {
1893 return apply_filters(
1894 'taxopress_get_deactivated_taxonomy_data',
1895 get_option('taxopress_deactivated_taxonomies', []),
1896 get_current_blog_id()
1897 );
1898 }
1899
1900
1901 /**
1902 * Filters the list of query arguments which get removed from admin area URLs in WordPress.
1903 *
1904 * @link https://core.trac.wordpress.org/ticket/23367
1905 *
1906 * @param string[] $args Array of removable query arguments.
1907 * @return string[] Updated array of removable query arguments.
1908 */
1909 function taxopress_filter_removable_query_args(array $args)
1910 {
1911 return array_merge($args, [
1912 'action',
1913 'taxonomy',
1914 '_wpnonce',
1915 ]);
1916 }
1917
1918 /**
1919 * Filters the list of query arguments which get removed from admin area URLs in WordPress.
1920 *
1921 * @link https://core.trac.wordpress.org/ticket/23367
1922 *
1923 * @param string[] $args Array of removable query arguments.
1924 * @return string[] Updated array of removable query arguments.
1925 */
1926 function taxopress_filter_removable_query_args_2(array $args)
1927 {
1928 return array_merge($args, [
1929 'action2',
1930 'taxonomy',
1931 '_wpnonce',
1932 ]);
1933 }
1934
1935 /**
1936 * Filters the list of query arguments which get removed from admin area URLs in WordPress.
1937 *
1938 * @link https://core.trac.wordpress.org/ticket/23367
1939 *
1940 * @param string[] $args Array of removable query arguments.
1941 * @return string[] Updated array of removable query arguments.
1942 */
1943 function taxopress_filter_removable_query_args_3(array $args)
1944 {
1945 return array_merge($args, [
1946 'new_taxonomy',
1947 ]);
1948 }
1949
1950
1951 /**
1952 * Delete our custom taxonomy from the array of taxonomies.
1953 * @return bool|string False on failure, string on success.
1954 */
1955 function taxopress_action_delete_taxonomy($term_object)
1956 {
1957
1958 $data = [
1959 'cpt_custom_tax' => [
1960 'name' => $term_object,
1961 ],
1962 ];
1963 // Check if they selected one to delete.
1964 if (empty($data['cpt_custom_tax']['name'])) {
1965 return taxopress_admin_notices(
1966 'error',
1967 '',
1968 false,
1969 esc_html__('Please provide a taxonomy to delete', 'simple-tags')
1970 );
1971 }
1972
1973 /**
1974 * Fires before a taxonomy is deleted from our saved options.
1975 *
1976 *
1977 * @param array $data Array of taxonomy data we are deleting.
1978 */
1979 do_action('taxopress_before_delete_taxonomy', $data);
1980
1981 $taxonomies = taxopress_get_taxonomy_data();
1982
1983 if (array_key_exists(strtolower($data['cpt_custom_tax']['name']), $taxonomies)) {
1984 unset($taxonomies[$data['cpt_custom_tax']['name']]);
1985
1986 /**
1987 * Filters whether or not 3rd party options were saved successfully within taxonomy deletion.
1988 *
1989 * @param bool $value Whether or not someone else saved successfully. Default false.
1990 * @param array $taxonomies Array of our updated taxonomies data.
1991 * @param array $data Array of submitted taxonomy to update.
1992 */
1993 if (false === ($success = apply_filters('taxopress_taxonomy_delete_tax', false, $taxonomies, $data))) {
1994 $success = update_option('taxopress_taxonomies', $taxonomies);
1995 }
1996 }
1997 // phpcs:ignore WordPressVIPMinimum.Performance.TaxonomyMetaInOptions.PossibleTermMetaInOptions -- Default term stored in options for compatibility
1998 delete_option("default_term_{$data['cpt_custom_tax']['name']}");
1999
2000 /**
2001 * Fires after a taxonomy is deleted from our saved options.
2002 *
2003 *
2004 * @param array $data Array of taxonomy data that was deleted.
2005 */
2006 do_action('taxopress_after_delete_taxonomy', $data);
2007
2008 // Used to help flush rewrite rules on init.
2009 set_transient('taxopress_flush_rewrite_rules', 'true', 5 * 60);
2010
2011 if (isset($success)) {
2012 add_action('admin_notices', "taxopress_taxdeleted_admin_notice");
2013
2014 return 'delete_success';
2015 }
2016
2017 add_action('admin_notices', "taxopress_delete_fail_admin_notice");
2018
2019 return 'delete_fail';
2020 }
2021
2022 function unregister_tags()
2023 {
2024 global $remove_current_taxonomy;
2025
2026 $all_taxonomies = (array)get_option('taxopress_deactivated_taxonomies');
2027 $all_taxonomies = array_unique(array_filter($all_taxonomies));
2028
2029 if (count($all_taxonomies) > 0) {
2030 foreach ($all_taxonomies as $taxonomy) {
2031 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reading GET parameter for page check, no state change
2032 if (!empty($_GET) && isset($_GET['page']) && 'st_taxonomies' == $_GET['page']) {
2033 $remove_current_taxonomy = $taxonomy;
2034 add_action('admin_menu', 'taxopress_remove_taxonomy_from_menus');
2035 } else {
2036 taxopress_unregister_taxonomy($taxonomy);
2037 }
2038 }
2039 }
2040 }
2041
2042 // phpcs:ignore Squiz.PHP.CommentedOutCode.Found -- Reference comment for context
2043 // Remove menu
2044 function taxopress_remove_taxonomy_from_menus()
2045 {
2046 global $remove_current_taxonomy;
2047 remove_menu_page('edit-tags.php?taxonomy=' . $remove_current_taxonomy);
2048 }
2049
2050
2051 function taxopress_unregister_taxonomy($taxonomy)
2052 {
2053 if (!taxonomy_exists($taxonomy)) {
2054 return new WP_Error('invalid_taxonomy', esc_html__('Invalid taxonomy.'));
2055 }
2056
2057 $taxonomy_object = get_taxonomy($taxonomy);
2058
2059 // Do not allow unregistering internal taxonomies.
2060 // phpcs:ignore Squiz.PHP.CommentedOutCode.Found -- Legacy validation logic kept for reference
2061 /*if ( $taxonomy_object->_builtin ) {
2062 return new WP_Error( 'invalid_taxonomy', esc_html__( 'Unregistering a built-in taxonomy is not allowed.' ) );
2063 }*/
2064
2065 global $wp_taxonomies;
2066
2067 // Instead of removing totally, keep minimal structure but disable functionality
2068 if (isset($wp_taxonomies[$taxonomy])) {
2069 $wp_taxonomies[$taxonomy]->public = false;
2070 $wp_taxonomies[$taxonomy]->show_ui = false;
2071 $wp_taxonomies[$taxonomy]->show_in_menu = false;
2072 $wp_taxonomies[$taxonomy]->show_in_nav_menus = false;
2073 $wp_taxonomies[$taxonomy]->show_in_rest = false;
2074 $wp_taxonomies[$taxonomy]->show_tagcloud = false;
2075 $wp_taxonomies[$taxonomy]->show_in_quick_edit = false;
2076 $wp_taxonomies[$taxonomy]->show_admin_column = false;
2077 $wp_taxonomies[$taxonomy]->query_var = false;
2078
2079 // Remove rewrite rules
2080 if ($taxonomy_object) {
2081 $taxonomy_object->remove_rewrite_rules();
2082 $taxonomy_object->remove_hooks();
2083 }
2084
2085 // Remove custom taxonomy default term option.
2086 if (!empty($taxonomy_object->default_term)) {
2087 delete_option('default_term_' . $taxonomy_object->name);
2088 }
2089 }
2090
2091 /**
2092 * Fires after a taxonomy is unregistered.
2093 *
2094 * @param string $taxonomy Taxonomy name.
2095 */
2096 do_action('unregistered_taxonomy', $taxonomy);
2097
2098 return true;
2099 }
2100
2101
2102 function taxopress_convert_external_taxonomy($taxonomy_object, $request_tax)
2103 {
2104
2105 if (array_key_exists($request_tax, taxopress_get_extername_taxonomy_data())) {
2106 return taxopress_get_extername_taxonomy_data()[$request_tax];
2107 }
2108
2109 $taxonomy_data = (array)$taxonomy_object;
2110
2111 foreach ($taxonomy_data as $key => $value) {
2112 //change label to array
2113 if ($key === 'labels') {
2114 $taxonomy_data[$key] = (array)$value;
2115 }
2116 //change cap to array
2117 if ($key === 'cap') {
2118 $taxonomy_data[$key] = (array)$value;
2119 }
2120 //change default terms to strings
2121 if ($key === 'default_term') {
2122 if (is_array($value) && count($value) > 0) {
2123 $taxonomy_data[$key] = join(',', array_filter($value));
2124 }
2125 }
2126 //set query var value if not empty
2127 if ($key === 'query_var') {
2128 if (empty(trim($value))) {
2129 $taxonomy_data['query_var'] = 'false';
2130 $taxonomy_data['query_var_slug'] = '';
2131 } else {
2132 $taxonomy_data['query_var'] = 'true';
2133 $taxonomy_data['query_var_slug'] = $value;
2134 }
2135 }
2136 //set rewrite
2137 if ($key === 'rewrite') {
2138 if (!empty($value) && is_array($value)) {
2139 if (count($value) > 0) {
2140 foreach ($value as $holdkey => $holdvalue) {
2141 if ($holdkey === 'with_front') {
2142 $taxonomy_data['rewrite_withfront'] = is_bool($holdvalue) ? taxopress_disp_boolean($holdvalue) : $holdvalue;
2143 } else {
2144 $taxonomy_data[$key . '_' . $holdkey] = is_bool($holdvalue) ? taxopress_disp_boolean($holdvalue) : $holdvalue;
2145 }
2146 }
2147 }
2148 $taxonomy_data[$key] = (count($value) > 0) ? 'true' : 'false';
2149 } else {
2150 $taxonomy_data[$key] = 'false';
2151 $taxonomy_data['rewrite_hierarchical'] = '';
2152 $taxonomy_data['rewrite_withfront'] = '';
2153 }
2154 }
2155 //dispose bool value
2156 if (is_bool($value)) {
2157 $taxonomy_data[$key] = taxopress_disp_boolean($value);
2158 }
2159 }
2160 //add singular label
2161 $taxonomy_data['singular_label'] = $taxonomy_data['labels']['singular_name'];
2162 //add object terms
2163 $taxonomy_data['object_types'] = $taxonomy_data['object_type'];
2164
2165 return $taxonomy_data;
2166 }
2167
2168 /**
2169 * Register our users' custom taxonomies.
2170 *
2171 * @internal
2172 */
2173 function taxopress_recreate_custom_taxonomies()
2174 {
2175 $taxes = taxopress_get_extername_taxonomy_data();
2176
2177 if (empty($taxes)) {
2178 return;
2179 }
2180 /**
2181 * Fires before the start of the taxonomy registrations.
2182 *
2183 * @param array $taxes Array of taxonomies to register.
2184 */
2185 do_action('taxopress_pre_register_taxonomies', $taxes);
2186
2187 if (is_array($taxes)) {
2188 foreach ($taxes as $tax) {
2189 if ($tax['name'] === 'media_tag' && (int)get_option('taxopress_media_tag_deleted') > 0) {
2190 continue;
2191 }
2192
2193 taxopress_re_register_single_taxonomy($tax);
2194 }
2195 }
2196
2197 /**
2198 * Fires after the completion of the taxonomy registrations.
2199 *
2200 * @param array $taxes Array of taxonomies registered.
2201 */
2202 do_action('taxopress_post_register_taxonomies', $taxes);
2203 }
2204
2205 /**
2206 * Helper function to register the actual taxonomy.
2207 *
2208 * @param array $taxonomy Taxonomy array to register. Optional.
2209 * @return null Result of register_taxonomy.
2210 * @internal
2211 *
2212 */
2213 function taxopress_re_register_single_taxonomy($taxonomy)
2214 {
2215
2216 $labels = [
2217 'name' => $taxonomy['label'],
2218 'singular_name' => $taxonomy['singular_label'],
2219 ];
2220
2221 $description = '';
2222 if (!empty($taxonomy['description'])) {
2223 $description = $taxonomy['description'];
2224 }
2225
2226 $preserved = taxopress_get_preserved_keys('taxonomies');
2227 $preserved_labels = taxopress_get_preserved_labels();
2228 foreach ($taxonomy['labels'] as $key => $label) {
2229 if (!empty($label)) {
2230 $labels[$key] = $label;
2231 } elseif (empty($label) && in_array($key, $preserved, true)) {
2232 $singular_or_plural = (in_array(
2233 $key,
2234 array_keys($preserved_labels['taxonomies']['plural'])
2235 )) ? 'plural' : 'singular';
2236 $label_plurality = ('plural' === $singular_or_plural) ? $taxonomy['label'] : $taxonomy['singular_label'];
2237 $labels[$key] = sprintf($preserved_labels['taxonomies'][$singular_or_plural][$key], $label_plurality);
2238 }
2239 }
2240
2241 $rewrite = get_taxopress_disp_boolean($taxonomy['rewrite']);
2242 if (false !== get_taxopress_disp_boolean($taxonomy['rewrite'])) {
2243 $rewrite = [];
2244 $rewrite['slug'] = !empty($taxonomy['rewrite_slug']) ? $taxonomy['rewrite_slug'] : $taxonomy['name'];
2245 $rewrite['with_front'] = true;
2246 if (isset($taxonomy['rewrite_withfront'])) {
2247 $rewrite['with_front'] = ('false' === taxopress_disp_boolean($taxonomy['rewrite_withfront'])) ? false : true;
2248 }
2249 $rewrite['hierarchical'] = false;
2250 if (isset($taxonomy['rewrite_hierarchical'])) {
2251 $rewrite['hierarchical'] = ('true' === taxopress_disp_boolean($taxonomy['rewrite_hierarchical'])) ? true : false;
2252 }
2253 }
2254
2255 if (in_array($taxonomy['query_var'], ['true', 'false', '0', '1'], true)) {
2256 $taxonomy['query_var'] = get_taxopress_disp_boolean($taxonomy['query_var']);
2257 }
2258 if (true === $taxonomy['query_var'] && !empty($taxonomy['query_var_slug'])) {
2259 $taxonomy['query_var'] = $taxonomy['query_var_slug'];
2260 }
2261
2262 $public = (!empty($taxonomy['public']) && false === get_taxopress_disp_boolean($taxonomy['public'])) ? false : true;
2263 $publicly_queryable = (!empty($taxonomy['publicly_queryable']) && false === get_taxopress_disp_boolean($taxonomy['publicly_queryable'])) ? false : true;
2264 if (empty($taxonomy['publicly_queryable'])) {
2265 $publicly_queryable = $public;
2266 }
2267
2268 $show_admin_column = (!empty($taxonomy['show_admin_column']) && false !== get_taxopress_disp_boolean($taxonomy['show_admin_column'])) ? true : false;
2269
2270 $show_in_menu = (!empty($taxonomy['show_in_menu']) && false !== get_taxopress_disp_boolean($taxonomy['show_in_menu'])) ? true : false;
2271
2272 if (empty($taxonomy['show_in_menu'])) {
2273 $show_in_menu = get_taxopress_disp_boolean($taxonomy['show_ui']);
2274 }
2275
2276 $show_in_nav_menus = (!empty($taxonomy['show_in_nav_menus']) && false !== get_taxopress_disp_boolean($taxonomy['show_in_nav_menus'])) ? true : false;
2277 if (empty($taxonomy['show_in_nav_menus'])) {
2278 $show_in_nav_menus = $public;
2279 }
2280
2281 $show_in_rest = (!empty($taxonomy['show_in_rest']) && false !== get_taxopress_disp_boolean($taxonomy['show_in_rest'])) ? true : false;
2282
2283 $show_in_quick_edit = (!empty($taxonomy['show_in_quick_edit']) && false !== get_taxopress_disp_boolean($taxonomy['show_in_quick_edit'])) ? true : false;
2284
2285 $show_in_filter = (!empty($taxonomy['show_in_filter']) && false !== get_taxopress_disp_boolean($taxonomy['show_in_filter'])) ? true : false;
2286
2287 $rest_base = null;
2288 if (!empty($taxonomy['rest_base'])) {
2289 $rest_base = $taxonomy['rest_base'];
2290 }
2291
2292 $rest_controller_class = null;
2293 if (!empty($post_type['rest_controller_class'])) {
2294 $rest_controller_class = $post_type['rest_controller_class'];
2295 }
2296
2297 $meta_box_cb = null;
2298 if (!empty($taxonomy['meta_box_cb'])) {
2299 $meta_box_cb = (false !== get_taxopress_disp_boolean($taxonomy['meta_box_cb'])) ? $taxonomy['meta_box_cb'] : false;
2300 }
2301 $default_term = null;
2302
2303 if (!empty($taxonomy['default_term'])) {
2304 $term_parts = explode(',', $taxonomy['default_term']);
2305 $term_parts = array_filter($term_parts);
2306 if (!empty($term_parts)) {
2307 $default_term = [];
2308 foreach ($term_parts as $term_part) {
2309 $default_term[] = ['name' => $term_part, 'slug' => $term_part];
2310 }
2311 }
2312 }
2313
2314 $args = [
2315 'labels' => $labels,
2316 'label' => $taxonomy['label'],
2317 'description' => $description,
2318 'public' => $public,
2319 'publicly_queryable' => $publicly_queryable,
2320 'hierarchical' => get_taxopress_disp_boolean($taxonomy['hierarchical']),
2321 'show_ui' => get_taxopress_disp_boolean($taxonomy['show_ui']),
2322 'show_in_menu' => $show_in_menu,
2323 'show_in_nav_menus' => $show_in_nav_menus,
2324 'query_var' => $taxonomy['query_var'],
2325 'rewrite' => $rewrite,
2326 'show_admin_column' => $show_admin_column,
2327 'show_in_rest' => $show_in_rest,
2328 'rest_base' => $rest_base,
2329 'rest_controller_class' => $rest_controller_class,
2330 'show_in_quick_edit' => $show_in_quick_edit,
2331 'show_in_filter' => $show_in_filter,
2332 'meta_box_cb' => $meta_box_cb,
2333 'default_term' => $default_term,
2334 ];
2335
2336 $object_type = !empty($taxonomy['object_types']) ? $taxonomy['object_types'] : '';
2337
2338 /**
2339 * Filters the arguments used for a taxonomy right before registering.
2340 *
2341 * @param array $args Array of arguments to use for registering taxonomy.
2342 * @param string $value Taxonomy slug to be registered.
2343 * @param array $taxonomy Original passed in values for taxonomy.
2344 * @param array $object_type Array of chosen post types for the taxonomy.
2345 */
2346 $args = apply_filters('taxopress_pre_register_taxonomy', $args, $taxonomy['name'], $taxonomy, $object_type);
2347
2348 return register_taxonomy($taxonomy['name'], $object_type, $args);
2349 }
2350
2351 /**
2352 * Set post taxonomy default term
2353 *
2354 * @param integer $post_id
2355 * @param object $post
2356 * @return void
2357 */
2358 function taxopress_set_default_taxonomy_terms($post_id, $post)
2359 {
2360 if ('auto-draft' === $post->post_status) {
2361 $taxonomies = get_object_taxonomies($post->post_type, 'object');
2362 foreach ($taxonomies as $taxonomy => $tax_object) {
2363 if (!empty($tax_object->default_term)) {
2364 if (is_array($tax_object->default_term)) {
2365 $new_terms = [];
2366 foreach ($tax_object->default_term as $term => $option) {
2367 if (is_array($option) && isset($option['name'])) {
2368 $new_terms[] = trim($option['name']);
2369 }
2370 }
2371 if (!empty($new_terms)) {
2372 wp_set_object_terms($post_id, $new_terms, $taxonomy, true);
2373 }
2374 }
2375 }
2376 }
2377 }
2378 }
2379
2380 function taxopress_show_all_cpt_in_archive_result($request_tax)
2381 {
2382
2383 $taxonomies = taxopress_get_taxonomy_data();
2384
2385 $current = false;
2386 if ($request_tax && is_array($taxonomies) && array_key_exists($request_tax, $taxonomies)) {
2387 $current = $taxonomies[$request_tax];
2388 } elseif (taxonomy_exists($request_tax)) {
2389 //not out taxonomy
2390 $external_taxonomy = get_taxonomies(['name' => $request_tax], 'objects');
2391 if (isset($external_taxonomy) > 0) {
2392 $current = taxopress_convert_external_taxonomy(
2393 $external_taxonomy[$request_tax],
2394 $request_tax
2395 );
2396 }
2397 }
2398
2399 $status = isset($current) && isset($current['include_in_result']) ? get_taxopress_disp_boolean($current['include_in_result']) : false;
2400
2401 return $status;
2402 }
2403
2404 /**
2405 * Filter the dropdown cats to remove the value="0" to solve issue with filter when
2406 * tag=0 https://github.com/TaxoPress/TaxoPress/issues/2372
2407 * @param string $output
2408 * @return string
2409 */
2410 function taxopress_filter_dropdown_cats($output)
2411 {
2412
2413 if (strpos($output, 'taxopress-select2-term-filter') !== false) {
2414 $output = str_replace(['value="0"', "value='0'"], ['value=""', "value=''"], $output);
2415 }
2416
2417 return $output;
2418 }
2419
2420 /* Show taxonomy filter on post list */
2421 function taxopress_filter_dropdown($taxonomy, $show_filter)
2422 {
2423
2424 $show_filter = get_taxopress_disp_boolean($show_filter);
2425
2426 if ($show_filter == true) {
2427 wp_dropdown_categories(
2428 array(
2429 'show_option_all' => sprintf(__('All %s', 'simple-tags'), $taxonomy->label),
2430 'orderby' => 'name',
2431 'order' => 'ASC',
2432 'hide_empty' => false,
2433 'hide_if_empty' => true,
2434 // phpcs:ignore WordPressVIPMinimum.Security.PHPFilterFunctions.RestrictedFilter -- Using FILTER_UNSAFE_RAW intentionally to preserve user-supplied query var format
2435 'selected' => sanitize_text_field(filter_input(INPUT_GET, $taxonomy->query_var, FILTER_UNSAFE_RAW)),
2436 'hierarchical' => true,
2437 'name' => $taxonomy->query_var,
2438 'taxonomy' => $taxonomy->name,
2439 'value_field' => 'slug',
2440 'id' => $taxonomy->name,
2441 'class' => 'taxopress-select2-term-filter'
2442 )
2443 );
2444 }
2445 }
2446
2447 function taxopress_get_all_taxonomies()
2448 {
2449 $custom_taxonomies = get_taxonomies(['_builtin' => false], 'objects');
2450 $builtin_taxonomies = get_taxonomies(['_builtin' => true], 'objects');
2451 return array_merge($custom_taxonomies, $builtin_taxonomies);
2452 }
2453
2454 function taxopress_get_dropdown()
2455 {
2456
2457 global $pagenow, $typenow;
2458
2459 if (is_admin()) {
2460 $type = 'post';
2461
2462 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reading GET parameter for post type filtering, no state change
2463 if (isset($_GET['post_type'])) {
2464 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
2465 $type = sanitize_text_field($_GET['post_type']);
2466 }
2467
2468 $taxonomies = taxopress_get_all_edited_taxonomy_data();
2469
2470 if (!empty($taxonomies)) {
2471 $all_taxonomies = taxopress_get_all_taxonomies();
2472
2473 foreach ($all_taxonomies as $taxonomy) {
2474 $taxonomy_name = $taxonomy->name;
2475
2476 if (array_key_exists($taxonomy_name, $taxonomies)) {
2477 $current = isset($taxonomies[ $taxonomy_name ]) ? $taxonomies[ $taxonomy_name ] : '';
2478
2479 if (is_array($current) && array_key_exists('show_in_filter', $current)) {
2480 if (isset($current['object_types']) && !empty($current['object_types'])) {
2481 foreach ($current['object_types'] as $object_type) {
2482 //Media Page
2483 if ($pagenow === 'upload.php') {
2484 if ($object_type == "attachment") {
2485 taxopress_filter_dropdown($taxonomy, $current['show_in_filter']);
2486 }
2487 } else {
2488 if ($object_type == $type) {
2489 taxopress_filter_dropdown($taxonomy, $current['show_in_filter']);
2490 }
2491 }
2492 }
2493 }
2494 }
2495 }
2496 }
2497 }
2498 }
2499 }
2500
2501 /**
2502 * Helper to sort terms based on TaxoPress settings.
2503 */
2504 function taxopress_sort_terms_by_settings($terms, $taxonomy, $settings = [], $is_admin = false)
2505 {
2506 static $custom_orders_cache = [];
2507
2508 if (!is_array($terms) || empty($terms) || empty($taxonomy)) {
2509 return $terms;
2510 }
2511
2512 // Default fallback settings
2513 $valid_orderby = ['name', 'term_id', 'ID', 'count', 'random', 'taxopress_term_order'];
2514 $valid_order = ['asc', 'desc'];
2515 $default_orderby = 'name';
2516 $default_order = 'asc';
2517
2518 $orderby_setting = isset($settings['orderby']) && in_array($settings['orderby'], $valid_orderby, true)
2519 ? $settings['orderby']
2520 : $default_orderby;
2521
2522 $order_setting = isset($settings['order']) && in_array(strtolower($settings['order']), $valid_order, true)
2523 ? strtolower($settings['order'])
2524 : $default_order;
2525
2526 // Custom order logic
2527 if ($orderby_setting === 'taxopress_term_order') {
2528 if (!isset($custom_orders_cache[$taxonomy])) {
2529 $custom_orders_cache[$taxonomy] = get_option('taxopress_term_order_' . $taxonomy, []);
2530 }
2531 $custom_order = $custom_orders_cache[$taxonomy];
2532 if (!empty($custom_order)) {
2533 $terms_by_id = [];
2534 foreach ($terms as $term) {
2535 if (is_object($term) && isset($term->term_id)) {
2536 $terms_by_id[$term->term_id] = $term;
2537 }
2538 }
2539 $ordered_terms = [];
2540 foreach ($custom_order as $term_id) {
2541 if (isset($terms_by_id[$term_id])) {
2542 $ordered_terms[] = $terms_by_id[$term_id];
2543 unset($terms_by_id[$term_id]);
2544 }
2545 }
2546 // Append missing terms
2547 foreach ($terms_by_id as $term) {
2548 $ordered_terms[] = $term;
2549 }
2550
2551 if (count($ordered_terms) !== count($terms)) {
2552 foreach ($terms as $term) {
2553 if (!in_array($term, $ordered_terms, true)) {
2554 $ordered_terms[] = $term;
2555 }
2556 }
2557 }
2558
2559 return $order_setting === 'desc' ? array_reverse($ordered_terms) : $ordered_terms;
2560 }
2561 }
2562
2563 // Built-in sorting fallbacks
2564 usort($terms, function ($a, $b) use ($orderby_setting, $order_setting) {
2565 $get = fn ($term, $key) => is_object($term) && isset($term->$key) ? $term->$key : null;
2566
2567 switch ($orderby_setting) {
2568 case 'term_id':
2569 case 'ID':
2570 return ($order_setting === 'desc' ? -1 : 1) * ((int) $get($a, 'term_id') - (int) $get($b, 'term_id'));
2571
2572 case 'count':
2573 return ($order_setting === 'desc' ? -1 : 1) * ((int) $get($a, 'count') - (int) $get($b, 'count'));
2574
2575 case 'name':
2576 $a_name = (string) ($get($a, 'name') ?? '');
2577 $b_name = (string) ($get($b, 'name') ?? '');
2578 return ($order_setting === 'desc')
2579 ? strcasecmp($b_name, $a_name)
2580 : strcasecmp($a_name, $b_name);
2581 }
2582
2583 return 0;
2584 });
2585
2586
2587 if ($orderby_setting === 'random') {
2588 shuffle($terms);
2589 }
2590
2591 return $terms;
2592 }
2593
2594 function taxopress_get_terms_args($args, $taxonomies)
2595 {
2596 if (!is_admin()) {
2597 return $args;
2598 }
2599
2600 $screen = function_exists('get_current_screen') ? get_current_screen() : null;
2601 if (!$screen || $screen->base !== 'edit-tags') {
2602 return $args;
2603 }
2604
2605 $tax = is_array($taxonomies) ? reset($taxonomies) : $taxonomies;
2606 if (!$tax) {
2607 return $args;
2608 }
2609
2610 $taxonomy_settings = taxopress_get_all_edited_taxonomy_data();
2611 $settings = $taxonomy_settings[$tax] ?? [];
2612
2613 // Only run if enabled
2614 if (!isset($settings['enable_taxopress_ordering']) || empty($settings['enable_taxopress_ordering'])) {
2615 return $args;
2616 }
2617
2618 // Validate/sanitize
2619 $valid_orderby = ['name', 'term_id', 'ID', 'count', 'random', 'taxopress_term_order'];
2620 $valid_order = ['asc', 'desc'];
2621
2622 $args['orderby'] = isset($settings['orderby']) && in_array($settings['orderby'], $valid_orderby, true)
2623 ? $settings['orderby']
2624 : 'name';
2625
2626 $args['order'] = isset($settings['order']) && in_array(strtolower($settings['order']), $valid_order, true)
2627 ? strtolower($settings['order'])
2628 : 'asc';
2629
2630 return $args;
2631 }
2632
2633 function taxopress_filter_terms($terms, $taxonomies, $args, $term_query)
2634 {
2635 $tax = is_array($taxonomies) ? reset($taxonomies) : $taxonomies;
2636 if (!$tax || empty($terms)) {
2637 return $terms;
2638 }
2639
2640 $taxonomy_settings = taxopress_get_all_edited_taxonomy_data();
2641 $settings = $taxonomy_settings[$tax] ?? [];
2642
2643 // Only run if enabled
2644 if (!isset($settings['enable_taxopress_ordering']) || empty($settings['enable_taxopress_ordering'])) {
2645 return $terms;
2646 }
2647
2648 return taxopress_sort_terms_by_settings($terms, $tax, $settings, true);
2649 }
2650
2651 function taxopress_terms_order_frontend($terms, $post_id, $taxonomy)
2652 {
2653 if (!is_array($terms) || empty($terms) || empty($taxonomy)) {
2654 return $terms;
2655 }
2656
2657 $taxonomy_settings = taxopress_get_all_edited_taxonomy_data();
2658 $settings = $taxonomy_settings[$taxonomy] ?? [];
2659
2660 //Only run if enabled
2661 if (!isset($settings['enable_taxopress_ordering']) || empty($settings['enable_taxopress_ordering'])) {
2662 return $terms;
2663 }
2664
2665 return taxopress_sort_terms_by_settings($terms, $taxonomy, $settings, false);
2666 }
2667