PluginProbe ʕ •ᴥ•ʔ
Secure Custom Fields / 6.4.2
Secure Custom Fields v6.4.2
6.9.2 6.9.1 6.9.0 6.8.9 6.8.7 6.8.8 6.8.6 6.8.4 6.8.5 trunk 6.4.0-beta1 6.4.0-beta2 6.4.1 6.4.1-beta3 6.4.1-beta4 6.4.1-beta5 6.4.1-beta6 6.4.1-beta7 6.4.2 6.5.0 6.5.1 6.5.2 6.5.3 6.5.4 6.5.5 6.5.6 6.5.7 6.6.0 6.7.0 6.7.1 6.8.0 6.8.1 6.8.2 6.8.3
secure-custom-fields / includes / post-types / class-acf-taxonomy.php
secure-custom-fields / includes / post-types Last commit date
class-acf-field-group.php 1 year ago class-acf-post-type.php 1 year ago class-acf-taxonomy.php 1 year ago class-acf-ui-options-page.php 1 year ago index.php 1 year ago
class-acf-taxonomy.php
809 lines
1 <?php
2
3 if ( ! defined( 'ABSPATH' ) ) {
4 exit; // Exit if accessed directly.
5 }
6
7 if ( ! class_exists( 'ACF_Taxonomy' ) ) {
8 class ACF_Taxonomy extends ACF_Internal_Post_Type {
9
10 /**
11 * The ACF internal post type name.
12 *
13 * @var string
14 */
15 public $post_type = 'acf-taxonomy';
16
17 /**
18 * The prefix for the key used in the main post array.
19 *
20 * @var string
21 */
22 public $post_key_prefix = 'taxonomy_';
23
24 /**
25 * The cache key for a singular post.
26 *
27 * @var string
28 */
29 public $cache_key = 'acf_get_taxonomy_post:key:';
30
31 /**
32 * The cache key for a collection of posts.
33 *
34 * @var string
35 */
36 public $cache_key_plural = 'acf_get_taxonomy_posts';
37
38 /**
39 * The hook name for a singular post.
40 *
41 * @var string
42 */
43 public $hook_name = 'taxonomy';
44
45 /**
46 * The hook name for a collection of posts.
47 *
48 * @var string
49 */
50 public $hook_name_plural = 'taxonomies';
51
52 /**
53 * The name of the store used for the post type.
54 *
55 * @var string
56 */
57 public $store = 'taxonomies';
58
59 /**
60 * Constructs the class.
61 */
62 public function __construct() {
63 $this->register_post_type();
64
65 // Include admin classes in admin.
66 if ( is_admin() ) {
67 acf_include( 'includes/admin/admin-internal-post-type-list.php' );
68 acf_include( 'includes/admin/admin-internal-post-type.php' );
69 acf_include( 'includes/admin/post-types/admin-taxonomy.php' );
70 acf_include( 'includes/admin/post-types/admin-taxonomies.php' );
71 }
72
73 parent::__construct();
74
75 add_action( 'acf/init', array( $this, 'register_taxonomies' ), 6 );
76 }
77
78 /**
79 * Registers the acf-taxonomy custom post type with WordPress.
80 *
81 * @since ACF 6.1
82 */
83 public function register_post_type() {
84 $cap = acf_get_setting( 'capability' );
85
86 register_post_type(
87 'acf-taxonomy',
88 array(
89 'labels' => array(
90 'name' => __( 'Taxonomies', 'secure-custom-fields' ),
91 'singular_name' => __( 'Taxonomies', 'secure-custom-fields' ),
92 'add_new' => __( 'Add New', 'secure-custom-fields' ),
93 'add_new_item' => __( 'Add New Taxonomy', 'secure-custom-fields' ),
94 'edit_item' => __( 'Edit Taxonomy', 'secure-custom-fields' ),
95 'new_item' => __( 'New Taxonomy', 'secure-custom-fields' ),
96 'view_item' => __( 'View Taxonomy', 'secure-custom-fields' ),
97 'search_items' => __( 'Search Taxonomies', 'secure-custom-fields' ),
98 'not_found' => __( 'No Taxonomies found', 'secure-custom-fields' ),
99 'not_found_in_trash' => __( 'No Taxonomies found in Trash', 'secure-custom-fields' ),
100 ),
101 'public' => false,
102 'hierarchical' => true,
103 'show_ui' => true,
104 'show_in_menu' => false,
105 '_builtin' => false,
106 'capability_type' => 'post',
107 'capabilities' => array(
108 'edit_post' => $cap,
109 'delete_post' => $cap,
110 'edit_posts' => $cap,
111 'delete_posts' => $cap,
112 ),
113 'supports' => false,
114 'rewrite' => false,
115 'query_var' => false,
116 )
117 );
118 }
119
120 /**
121 * Register activated taxonomies with WordPress
122 *
123 * @since ACF 6.1
124 */
125 public function register_taxonomies() {
126 $taxonomies = $this->get_posts( array( 'active' => true ) );
127 foreach ( $taxonomies as $taxonomy ) {
128 $args = $this->get_taxonomy_args( $taxonomy );
129 if ( ! taxonomy_exists( $taxonomy['taxonomy'] ) ) {
130 register_taxonomy( $taxonomy['taxonomy'], (array) $taxonomy['object_type'], $args );
131 } else {
132 // Flag on the store we bailed on registering this as it already exists.
133 $store = acf_get_store( $this->store );
134 $store_value = $store->get( $taxonomy['key'] );
135 $store_value['not_registered'] = true;
136 $store->set( $taxonomy['key'], $store_value );
137 }
138 }
139 }
140
141 /**
142 * Gets the default settings array for an ACF taxonomy.
143 *
144 * @return array
145 */
146 public function get_settings_array() {
147 return array(
148 // ACF-specific settings.
149 'ID' => 0,
150 'key' => '',
151 'title' => '',
152 'menu_order' => 0,
153 'active' => true,
154 'taxonomy' => '', // Taxonomy key passed as first param to register_taxonomy().
155 'object_type' => array(), // Converted to objects array passed as second parameter.
156 'advanced_configuration' => 0,
157 'import_source' => '',
158 'import_date' => '',
159 // Settings passed to register_taxonomy().
160 'labels' => array(
161 'singular_name' => '',
162 'name' => '',
163 'menu_name' => '',
164 'search_items' => '',
165 'popular_items' => '',
166 'all_items' => '',
167 'parent_item' => '',
168 'parent_item_colon' => '',
169 'name_field_description' => '',
170 'slug_field_description' => '',
171 'parent_field_description' => '',
172 'desc_field_description' => '',
173 'edit_item' => '',
174 'view_item' => '',
175 'update_item' => '',
176 'add_new_item' => '',
177 'new_item_name' => '',
178 'separate_items_with_commas' => '',
179 'add_or_remove_items' => '',
180 'choose_from_most_used' => '',
181 'not_found' => '',
182 'no_terms' => '',
183 'filter_by_item' => '',
184 'items_list_navigation' => '',
185 'items_list' => '',
186 'most_used' => '',
187 'back_to_items' => '',
188 'item_link' => '',
189 'item_link_description' => '',
190 ),
191 'description' => '',
192 'capabilities' => array(
193 'manage_terms' => 'manage_categories',
194 'edit_terms' => 'manage_categories',
195 'delete_terms' => 'manage_categories',
196 'assign_terms' => 'edit_posts',
197 ),
198 'public' => true,
199 'publicly_queryable' => true,
200 'hierarchical' => false,
201 'show_ui' => true,
202 'show_in_menu' => true,
203 'show_in_nav_menus' => true,
204 'show_in_rest' => true,
205 'rest_base' => '',
206 'rest_namespace' => 'wp/v2',
207 'rest_controller_class' => 'WP_REST_Terms_Controller',
208 'show_tagcloud' => true,
209 'show_in_quick_edit' => true,
210 'show_admin_column' => false,
211 'rewrite' => array(
212 'permalink_rewrite' => 'taxonomy_key', // ACF-specific option.
213 'slug' => '',
214 'with_front' => true,
215 'rewrite_hierarchical' => false,
216 ),
217 'query_var' => 'taxonomy_key',
218 'query_var_name' => '',
219 'default_term' => array(
220 'default_term_enabled' => false,
221 'default_term_name' => '',
222 'default_term_slug' => '',
223 'default_term_description' => '',
224 ),
225 'sort' => null,
226 'meta_box' => 'default',
227 'meta_box_cb' => '',
228 'meta_box_sanitize_cb' => '',
229 );
230 }
231
232 /**
233 * Validates post type values before allowing save from the global $_POST object.
234 * Errors are added to the form using acf_add_internal_post_type_validation_error().
235 *
236 * @since ACF 6.1
237 *
238 * @return boolean validity status
239 */
240 public function ajax_validate_values() {
241 if ( empty( $_POST['acf_taxonomy'] ) || empty( $_POST['acf_taxonomy']['taxonomy'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Verified elsewhere.
242 return false;
243 }
244
245 $taxonomy_key = acf_sanitize_request_args( wp_unslash( $_POST['acf_taxonomy']['taxonomy'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Verified elsewhere.
246 $taxonomy_key = is_string( $taxonomy_key ) ? $taxonomy_key : '';
247 $valid = true;
248
249 if ( strlen( $taxonomy_key ) > 32 ) {
250 $valid = false;
251 acf_add_internal_post_type_validation_error( 'taxonomy', __( 'The taxonomy key must be under 32 characters.', 'secure-custom-fields' ) );
252 }
253
254 if ( preg_match( '/^[a-z0-9_-]*$/', $taxonomy_key ) !== 1 ) {
255 $valid = false;
256 acf_add_internal_post_type_validation_error( 'taxonomy', __( 'The taxonomy key must only contain lower case alphanumeric characters, underscores or dashes.', 'secure-custom-fields' ) );
257 }
258
259 if ( in_array( $taxonomy_key, acf_get_wp_reserved_terms(), true ) ) {
260 $valid = false;
261 /* translators: %s a link to WordPress.org's Reserved Terms page */
262 $message = sprintf( __( 'This field must not be a WordPress <a href="%s" target="_blank">reserved term</a>.', 'secure-custom-fields' ), 'https://codex.wordpress.org/Reserved_Terms' );
263 acf_add_internal_post_type_validation_error( 'taxonomy', $message );
264 } else {
265 // Check if this post key exists in the ACF store for registered post types, excluding those which failed registration.
266 $store = acf_get_store( $this->store );
267 $post_id = (int) acf_maybe_get_POST( 'post_id', 0 );
268
269 $matches = array_filter(
270 $store->get_data(),
271 function ( $item ) use ( $taxonomy_key ) {
272 return $item['taxonomy'] === $taxonomy_key && empty( $item['not_registered'] );
273 }
274 );
275 $duplicates = array_filter(
276 $matches,
277 function ( $item ) use ( $post_id ) {
278 return $item['ID'] !== $post_id;
279 }
280 );
281
282 if ( $duplicates ) {
283 $valid = false;
284 acf_add_internal_post_type_validation_error( 'taxonomy', __( 'This taxonomy key is already in use by another taxonomy in ACF and cannot be used.', 'secure-custom-fields' ) );
285 // If we're not already in use with another ACF taxonomy, check if we're registered, but not by ACF.
286 } elseif ( empty( $matches ) && taxonomy_exists( $taxonomy_key ) ) {
287 $valid = false;
288 acf_add_internal_post_type_validation_error( 'taxonomy', __( 'This taxonomy key is already in use by another taxonomy registered outside of ACF and cannot be used.', 'secure-custom-fields' ) );
289 }
290 }
291
292 $valid = apply_filters( "acf/{$this->hook_name}/ajax_validate_values", $valid, $_POST['acf_taxonomy'] ); // phpcs:ignore WordPress.Security -- Raw input send to hook for validation.
293
294 return $valid;
295 }
296
297 /**
298 * Parses ACF taxonomy settings and returns an array of taxonomy
299 * args that can be easily handled by `register_taxonomy()`.
300 *
301 * Omits settings that line up with the WordPress defaults to reduce the size
302 * of the array passed to `register_taxonomy()`, which might be exported.
303 *
304 * @since ACF 6.1
305 *
306 * @param array $post The main ACF taxonomy settings array.
307 * @param boolean $escape_labels Determines if the label values should be escaped.
308 * @return array
309 */
310 public function get_taxonomy_args( $post, $escape_labels = true ) {
311 $args = array();
312
313 // Make sure any provided labels are escaped strings and not empty.
314 $labels = array_filter( $post['labels'] );
315 $labels = array_map( 'strval', $labels );
316 if ( $escape_labels ) {
317 $labels = array_map( 'esc_html', $labels );
318 }
319 if ( ! empty( $labels ) ) {
320 $args['labels'] = $labels;
321 }
322
323 // Description is an optional string.
324 if ( ! empty( $post['description'] ) ) {
325 $args['description'] = (string) $post['description'];
326 }
327
328 // ACF requires the public setting to decide other settings.
329 $args['public'] = ! empty( $post['public'] );
330
331 // WordPress and ACF both default to false, so this can be omitted if still false.
332 if ( ! empty( $post['hierarchical'] ) ) {
333 $args['hierarchical'] = true;
334 }
335
336 // WordPress defaults to the same as $args['public'].
337 $publicly_queryable = (bool) $post['publicly_queryable'];
338 if ( $publicly_queryable !== $args['public'] ) {
339 $args['publicly_queryable'] = $publicly_queryable;
340 }
341
342 // WordPress defaults to the same as $args['public'].
343 $show_ui = (bool) $post['show_ui'];
344 if ( $show_ui !== $args['public'] ) {
345 $args['show_ui'] = $show_ui;
346 }
347
348 // WordPress defaults to the same as $args['show_ui'].
349 $show_in_menu = $post['show_in_menu'];
350 if ( $show_in_menu !== $show_ui ) {
351 $args['show_in_menu'] = (bool) $show_in_menu;
352 }
353
354 // WordPress defaults to the same as $args['public'].
355 $show_in_nav_menus = (bool) $post['show_in_nav_menus'];
356 if ( $show_in_nav_menus !== $args['public'] ) {
357 $args['show_in_nav_menus'] = $show_in_nav_menus;
358 }
359
360 // ACF defaults to true, but can be overridden.
361 $show_in_rest = (bool) $post['show_in_rest'];
362 $args['show_in_rest'] = $show_in_rest;
363
364 // WordPress defaults to `$taxonomy`.
365 $rest_base = (string) $post['rest_base'];
366 if ( ! empty( $rest_base ) && $rest_base !== $post['taxonomy'] ) {
367 $args['rest_base'] = $rest_base;
368 }
369
370 // WordPress defaults to "wp/v2".
371 $rest_namespace = (string) $post['rest_namespace'];
372 if ( ! empty( $rest_namespace ) && 'wp/v2' !== $rest_namespace ) {
373 $args['rest_namespace'] = $post['rest_namespace'];
374 }
375
376 // WordPress defaults to `WP_REST_Terms_Controller`.
377 $rest_controller_class = (string) $post['rest_controller_class'];
378 if ( ! empty( $rest_controller_class ) && 'WP_REST_Terms_Controller' !== $rest_controller_class ) {
379 $args['rest_controller_class'] = $rest_controller_class;
380 }
381
382 // WordPress defaults to the same as `$args['show_ui']`.
383 $show_tagcloud = (bool) $post['show_tagcloud'];
384 if ( $show_tagcloud !== $show_ui ) {
385 $args['show_tagcloud'] = $show_tagcloud;
386 }
387
388 // WordPress defaults to the same as `$args['show_ui']`.
389 $show_in_quick_edit = (bool) $post['show_in_quick_edit'];
390 if ( $show_in_quick_edit !== $show_ui ) {
391 $args['show_in_quick_edit'] = $show_tagcloud;
392 }
393
394 // WordPress defaults to false.
395 $show_admin_column = (bool) $post['show_admin_column'];
396 if ( $show_admin_column ) {
397 $args['show_admin_column'] = true;
398 }
399
400 $capabilities = array();
401
402 if ( ! empty( $post['capabilities']['manage_terms'] ) && 'manage_categories' !== $post['capabilities']['manage_terms'] ) {
403 $capabilities['manage_terms'] = (string) $post['capabilities']['manage_terms'];
404 }
405
406 if ( ! empty( $post['capabilities']['edit_terms'] ) && 'manage_categories' !== $post['capabilities']['edit_terms'] ) {
407 $capabilities['edit_terms'] = (string) $post['capabilities']['edit_terms'];
408 }
409
410 if ( ! empty( $post['capabilities']['delete_terms'] ) && 'manage_categories' !== $post['capabilities']['delete_terms'] ) {
411 $capabilities['delete_terms'] = (string) $post['capabilities']['delete_terms'];
412 }
413
414 if ( ! empty( $post['capabilities']['assign_terms'] ) && 'edit_posts' !== $post['capabilities']['assign_terms'] ) {
415 $capabilities['assign_terms'] = (string) $post['capabilities']['assign_terms'];
416 }
417
418 if ( ! empty( $capabilities ) ) {
419 $args['capabilities'] = $capabilities;
420 }
421
422 // WordPress defaults to the tags/categories metabox, but a custom callback or `false` is also supported.
423 $meta_box = isset( $post['meta_box'] ) ? (string) $post['meta_box'] : 'default';
424
425 if ( 'custom' === $meta_box && ! empty( $post['meta_box_cb'] ) ) {
426 $args['meta_box_cb'] = array( $this, 'build_safe_context_for_metabox_cb' );
427
428 if ( ! empty( $post['meta_box_sanitize_cb'] ) ) {
429 $args['meta_box_sanitize_cb'] = (string) $post['meta_box_sanitize_cb'];
430 }
431 } elseif ( 'disabled' === $meta_box ) {
432 $args['meta_box_cb'] = false;
433 }
434
435 // The rewrite arg can be a boolean or array of further settings. WordPress and ACF default to true.
436 $rewrite = (array) $post['rewrite'];
437 $rewrite_enabled = true;
438 $rewrite_args = array();
439
440 // Value of ACF select (not passed to `register_taxonomy()`).
441 $rewrite['permalink_rewrite'] = isset( $rewrite['permalink_rewrite'] ) ? (string) $rewrite['permalink_rewrite'] : 'taxonomy_key';
442
443 if ( 'no_permalink' === $rewrite['permalink_rewrite'] ) {
444 $rewrite_enabled = false;
445 }
446
447 // Rewrite slug defaults to $taxonomy key.
448 if ( ! empty( $rewrite['slug'] ) && $rewrite['slug'] !== $post['taxonomy'] && 'custom_permalink' === $rewrite['permalink_rewrite'] ) {
449 $rewrite_args['slug'] = (string) $rewrite['slug'];
450 }
451
452 // WordPress defaults to true.
453 if ( isset( $rewrite['with_front'] ) && ! $rewrite['with_front'] && $rewrite_enabled ) {
454 $rewrite_args['with_front'] = false;
455 }
456
457 // WordPress defaults to false.
458 if ( isset( $rewrite['rewrite_hierarchical'] ) && $rewrite['rewrite_hierarchical'] && $rewrite_enabled ) {
459 $rewrite_args['hierarchical'] = true;
460 }
461
462 if ( $rewrite_enabled && ! empty( $rewrite_args ) ) {
463 $args['rewrite'] = $rewrite_args;
464 } elseif ( ! $rewrite_enabled ) {
465 $args['rewrite'] = false;
466 }
467
468 // WordPress and ACF default to $taxonomy key, a boolean can also be used.
469 $query_var = (string) $post['query_var'];
470 if ( 'custom_query_var' === $query_var ) {
471 $query_var_name = (string) $post['query_var_name'];
472
473 if ( ! empty( $query_var_name ) && $query_var_name !== $post['taxonomy'] ) {
474 $args['query_var'] = $query_var_name;
475 }
476 } elseif ( 'none' === $query_var ) {
477 $args['query_var'] = false;
478 }
479
480 // WordPress accepts a string or an array of term info, but always converts into an array.
481 $default_term = (array) $post['default_term'];
482 if ( isset( $default_term['default_term_enabled'] ) && $default_term['default_term_enabled'] ) {
483 $args['default_term'] = array();
484
485 if ( isset( $default_term['default_term_name'] ) && ! empty( $default_term['default_term_name'] ) ) {
486 $args['default_term']['name'] = (string) $default_term['default_term_name'];
487 }
488
489 if ( isset( $default_term['default_term_slug'] ) && ! empty( $default_term['default_term_slug'] ) ) {
490 $args['default_term']['slug'] = (string) $default_term['default_term_slug'];
491 }
492
493 if ( isset( $default_term['default_term_description'] ) && ! empty( $default_term['default_term_description'] ) ) {
494 $args['default_term']['description'] = (string) $default_term['default_term_description'];
495 }
496 }
497
498 // WordPress defaults to null, equivalent to false.
499 $sort = (bool) $post['sort'];
500 if ( $sort ) {
501 $args['sort'] = true;
502 }
503
504 return apply_filters( 'acf/taxonomy/registration_args', $args, $post );
505 }
506
507 /**
508 * Ensure the metabox being called does not perform any unsafe operations.
509 *
510 * @since ACF 6.3.8
511 *
512 * @param WP_Post $post The post being rendered.
513 * @param array $tax The provided taxonomy information required for callback render.
514 * @return mixed The callback result.
515 */
516 public function build_safe_context_for_metabox_cb( $post, $tax ) {
517 $taxonomies = $this->get_posts();
518 $this_tax = array_filter(
519 $taxonomies,
520 function ( $taxonomy ) use ( $tax ) {
521 return $taxonomy['taxonomy'] === $tax['args']['taxonomy'];
522 }
523 );
524 if ( empty( $this_tax ) || ! is_array( $this_tax ) ) {
525 // Unable to find the ACF taxonomy. Don't do anything.
526 return;
527 }
528 $acf_taxonomy = array_shift( $this_tax );
529 $original_cb = isset( $acf_taxonomy['meta_box_cb'] ) ? $acf_taxonomy['meta_box_cb'] : false;
530
531 // Prevent access to any wp_ prefixed functions in a callback.
532 if ( apply_filters( 'acf/taxonomy/prevent_access_to_wp_functions_in_meta_box_cb', true ) && substr( strtolower( $original_cb ), 0, 3 ) === 'wp_' ) {
533 // Don't execute register meta box callbacks if an internal wp function by default.
534 return;
535 }
536
537 $unset = array( '_POST', '_GET', '_REQUEST', '_COOKIE', '_SESSION', '_FILES', '_ENV', '_SERVER' );
538 $originals = array();
539
540 foreach ( $unset as $var ) {
541 if ( isset( $GLOBALS[ $var ] ) ) {
542 $originals[ $var ] = $GLOBALS[ $var ];
543 $GLOBALS[ $var ] = array(); //phpcs:ignore -- used for building a safe context
544 }
545 }
546
547 $return = false;
548 if ( is_callable( $original_cb ) ) {
549 $return = call_user_func( $original_cb, $post, $tax );
550 }
551
552 foreach ( $unset as $var ) {
553 if ( isset( $originals[ $var ] ) ) {
554 $GLOBALS[ $var ] = $originals[ $var ]; //phpcs:ignore -- used for restoring the original context
555 }
556 }
557
558 return $return;
559 }
560
561 /**
562 * Returns a string that can be used to create a taxonomy in PHP.
563 *
564 * @since ACF 6.1
565 *
566 * @param array $post The main taxonomy array.
567 * @return string
568 */
569 public function export_post_as_php( $post = array() ) {
570 $return = '';
571 if ( empty( $post ) ) {
572 return $return;
573 }
574
575 $post = $this->validate_post( $post );
576 $taxonomy_key = $post['taxonomy'];
577 $objects = (array) $post['object_type'];
578 $objects = var_export( $objects, true ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions -- Used for PHP export.
579 $args = $this->get_taxonomy_args( $post, false );
580 $args = var_export( $args, true ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions -- Used for PHP export.
581
582 if ( ! $args ) {
583 return $return;
584 }
585
586 $args = $this->format_code_for_export( $args );
587 $objects = $this->format_code_for_export( $objects );
588
589 $return .= "register_taxonomy( '{$taxonomy_key}', {$objects}, {$args} );\r\n";
590
591 return esc_textarea( $return );
592 }
593
594 /**
595 * Flush rewrite rules whenever anything changes about a taxonomy.
596 *
597 * @since ACF 6.1
598 *
599 * @param array $post The main post type array.
600 */
601 public function flush_post_cache( $post ) {
602 // Bail early if we won't be able to register/unregister the taxonomy.
603 if ( ! isset( $post['taxonomy'] ) ) {
604 return;
605 }
606
607 // Temporarily unregister the taxonomy so that we can re-register with the latest args below.
608 if ( empty( $post['active'] ) || taxonomy_exists( $post['taxonomy'] ) ) {
609 unregister_taxonomy( $post['taxonomy'] );
610 }
611
612 // When this is being called, the post type may not have been registered yet, so we do it now.
613 if ( ! empty( $post['active'] ) ) {
614 $post['object_type'] = isset( $post['object_type'] ) ? (array) $post['object_type'] : array();
615 register_taxonomy( $post['taxonomy'], $post['object_type'], $this->get_taxonomy_args( $post ) );
616 }
617
618 parent::flush_post_cache( $post );
619 flush_rewrite_rules();
620 }
621
622 /**
623 * Translates an ACF post.
624 *
625 * @since ACF 6.1
626 *
627 * @param array $post The field group array.
628 * @return array
629 */
630 public function translate_post( $post = array() ) {
631 // Get settings.
632 $l10n = acf_get_setting( 'l10n' );
633 $l10n_textdomain = acf_get_setting( 'l10n_textdomain' );
634
635 // Translate field settings if textdomain is set.
636 if ( $l10n && $l10n_textdomain ) {
637 $post['title'] = acf_translate( $post['title'] );
638 $post['description'] = acf_translate( $post['description'] );
639 foreach ( $post['labels'] as $key => $label ) {
640 $post['labels'][ $key ] = acf_translate( $label );
641 }
642
643 /**
644 * Filters the post array to translate strings.
645 *
646 * @date 12/02/2014
647 * @since ACF 5.0.0
648 *
649 * @param array $post The post array.
650 */
651 $post = apply_filters( "acf/translate_{$this->hook_name}", $post );
652 }
653
654 return $post;
655 }
656
657 /**
658 * Imports a taxonomy from CPTUI.
659 *
660 * @since ACF 6.1
661 *
662 * @param array $args Arguments from CPTUI.
663 * @return array
664 */
665 public function import_cptui_taxonomy( $args ) {
666 $acf_args = $this->get_settings_array();
667
668 // Convert string boolean values to proper booleans.
669 foreach ( $args as $key => $value ) {
670 if ( in_array( $value, array( 'true', 'false' ), true ) ) {
671 $args[ $key ] = filter_var( $value, FILTER_VALIDATE_BOOLEAN );
672 }
673 }
674
675 if ( isset( $args['name'] ) ) {
676 $acf_args['taxonomy'] = (string) $args['name'];
677 unset( $args['name'] );
678 }
679
680 if ( isset( $args['labels'] ) ) {
681 $acf_args['labels'] = array_merge( $acf_args['labels'], $args['labels'] );
682 unset( $args['labels'] );
683 }
684
685 // ACF uses "name" as title, and stores in labels array.
686 if ( isset( $args['label'] ) ) {
687 $acf_args['title'] = (string) $args['label'];
688 $acf_args['labels']['name'] = (string) $args['label'];
689 unset( $args['label'] );
690 }
691
692 if ( isset( $args['singular_label'] ) ) {
693 $acf_args['labels']['singular_name'] = (string) $args['singular_label'];
694 unset( $args['singular_label'] );
695 }
696
697 // ACF handles the meta_box_cb with two different settings.
698 if ( isset( $args['meta_box_cb'] ) ) {
699 if ( false === $args['meta_box_cb'] ) {
700 $acf_args['meta_box'] = 'disabled';
701 } elseif ( ! empty( $args['meta_box_cb'] ) ) {
702 $acf_args['meta_box'] = 'custom';
703 $acf_args['meta_box_cb'] = $args['meta_box_cb'];
704 }
705
706 unset( $args['meta_box_cb'] );
707 }
708
709 // ACF handles the query var and query var slug/name differently.
710 if ( isset( $args['query_var'] ) ) {
711 if ( ! $args['query_var'] ) {
712 $acf_args['query_var'] = 'none';
713 } elseif ( ! empty( $args['query_var_slug'] ) ) {
714 $acf_args['query_var'] = 'custom_query_var';
715 } else {
716 $acf_args['query_var'] = 'taxonomy_key';
717 }
718
719 unset( $args['query_var'] );
720 }
721
722 if ( isset( $args['query_var_slug'] ) ) {
723 $acf_args['query_var_name'] = (string) $args['query_var_slug'];
724 unset( $args['query_var_slug'] );
725 }
726
727 if ( isset( $args['rewrite'] ) ) {
728 $rewrite = (bool) $args['rewrite'];
729
730 if ( ! $rewrite ) {
731 $acf_args['rewrite']['permalink_rewrite'] = 'no_permalink';
732 } elseif ( ! empty( $args['rewrite_slug'] ) ) {
733 $acf_args['rewrite']['permalink_rewrite'] = 'custom_permalink';
734 } else {
735 $acf_args['rewrite']['permalink_rewrite'] = 'taxonomy_key';
736 }
737
738 unset( $args['rewrite'] );
739 }
740
741 if ( isset( $args['rewrite_slug'] ) ) {
742 $acf_args['rewrite']['slug'] = (string) $args['rewrite_slug'];
743 unset( $args['rewrite_slug'] );
744 }
745
746 if ( isset( $args['rewrite_withfront'] ) ) {
747 $acf_args['rewrite']['with_front'] = $args['rewrite_withfront'] === '1';
748 unset( $args['rewrite_withfront'] );
749 }
750
751 if ( isset( $args['rewrite_hierarchical'] ) ) {
752 $acf_args['rewrite']['rewrite_hierarchical'] = $args['rewrite_hierarchical'] === '1';
753 unset( $args['rewrite_hierarchical'] );
754 }
755
756 // CPTUI stores all default_term settings as comma separate values.
757 if ( isset( $args['default_term'] ) ) {
758 if ( '' !== $args['default_term'] ) {
759 $default_term = explode( ',', $args['default_term'] );
760 $default_term = array_map( 'trim', $default_term );
761
762 if ( isset( $default_term[0] ) ) {
763 $acf_args['default_term']['default_term_enabled'] = true;
764 $acf_args['default_term']['default_term_name'] = (string) $default_term[0];
765 }
766
767 if ( isset( $default_term[1] ) ) {
768 $acf_args['default_term']['default_term_slug'] = (string) $default_term[1];
769 }
770
771 if ( isset( $default_term[2] ) ) {
772 $acf_args['default_term']['default_term_description'] = (string) $default_term[2];
773 }
774 }
775
776 unset( $args['default_term'] );
777 }
778
779 if ( isset( $args['object_types'] ) ) {
780 $acf_args['object_type'] = $args['object_types'];
781 unset( $args['object_types'] );
782 }
783
784 $acf_args = wp_parse_args( $args, $acf_args );
785 $acf_args['key'] = uniqid( 'taxonomy_' );
786 $acf_args['advanced_configuration'] = true;
787 $acf_args['import_source'] = 'cptui';
788 $acf_args['import_date'] = time();
789
790 $existing_taxonomies = acf_get_acf_taxonomies();
791
792 foreach ( $existing_taxonomies as $existing_taxonomy ) {
793 // Taxonomy already exists, so we need to update rather than import.
794 if ( $acf_args['taxonomy'] === $existing_taxonomy['taxonomy'] ) {
795 $acf_args = $this->prepare_post_for_import( $acf_args );
796 $acf_args['ID'] = $existing_taxonomy['ID'];
797 $acf_args['key'] = $existing_taxonomy['key'];
798 return $this->update_post( $acf_args );
799 }
800 }
801
802 return $this->import_post( $acf_args );
803 }
804 }
805
806 }
807
808 acf_new_instance( 'ACF_Taxonomy' );
809