class-wp-taxonomy.php (13344B)
1 <?php 2 /** 3 * Taxonomy API: WP_Taxonomy class 4 * 5 * @package WordPress 6 * @subpackage Taxonomy 7 * @since 4.7.0 8 */ 9 10 /** 11 * Core class used for interacting with taxonomies. 12 * 13 * @since 4.7.0 14 */ 15 final class WP_Taxonomy { 16 /** 17 * Taxonomy key. 18 * 19 * @since 4.7.0 20 * @var string 21 */ 22 public $name; 23 24 /** 25 * Name of the taxonomy shown in the menu. Usually plural. 26 * 27 * @since 4.7.0 28 * @var string 29 */ 30 public $label; 31 32 /** 33 * Labels object for this taxonomy. 34 * 35 * If not set, tag labels are inherited for non-hierarchical types 36 * and category labels for hierarchical ones. 37 * 38 * @see get_taxonomy_labels() 39 * 40 * @since 4.7.0 41 * @var stdClass 42 */ 43 public $labels; 44 45 /** 46 * A short descriptive summary of what the taxonomy is for. 47 * 48 * @since 4.7.0 49 * @var string 50 */ 51 public $description = ''; 52 53 /** 54 * Whether a taxonomy is intended for use publicly either via the admin interface or by front-end users. 55 * 56 * @since 4.7.0 57 * @var bool 58 */ 59 public $public = true; 60 61 /** 62 * Whether the taxonomy is publicly queryable. 63 * 64 * @since 4.7.0 65 * @var bool 66 */ 67 public $publicly_queryable = true; 68 69 /** 70 * Whether the taxonomy is hierarchical. 71 * 72 * @since 4.7.0 73 * @var bool 74 */ 75 public $hierarchical = false; 76 77 /** 78 * Whether to generate and allow a UI for managing terms in this taxonomy in the admin. 79 * 80 * @since 4.7.0 81 * @var bool 82 */ 83 public $show_ui = true; 84 85 /** 86 * Whether to show the taxonomy in the admin menu. 87 * 88 * If true, the taxonomy is shown as a submenu of the object type menu. If false, no menu is shown. 89 * 90 * @since 4.7.0 91 * @var bool 92 */ 93 public $show_in_menu = true; 94 95 /** 96 * Whether the taxonomy is available for selection in navigation menus. 97 * 98 * @since 4.7.0 99 * @var bool 100 */ 101 public $show_in_nav_menus = true; 102 103 /** 104 * Whether to list the taxonomy in the tag cloud widget controls. 105 * 106 * @since 4.7.0 107 * @var bool 108 */ 109 public $show_tagcloud = true; 110 111 /** 112 * Whether to show the taxonomy in the quick/bulk edit panel. 113 * 114 * @since 4.7.0 115 * @var bool 116 */ 117 public $show_in_quick_edit = true; 118 119 /** 120 * Whether to display a column for the taxonomy on its post type listing screens. 121 * 122 * @since 4.7.0 123 * @var bool 124 */ 125 public $show_admin_column = false; 126 127 /** 128 * The callback function for the meta box display. 129 * 130 * @since 4.7.0 131 * @var bool|callable 132 */ 133 public $meta_box_cb = null; 134 135 /** 136 * The callback function for sanitizing taxonomy data saved from a meta box. 137 * 138 * @since 5.1.0 139 * @var callable 140 */ 141 public $meta_box_sanitize_cb = null; 142 143 /** 144 * An array of object types this taxonomy is registered for. 145 * 146 * @since 4.7.0 147 * @var array 148 */ 149 public $object_type = null; 150 151 /** 152 * Capabilities for this taxonomy. 153 * 154 * @since 4.7.0 155 * @var stdClass 156 */ 157 public $cap; 158 159 /** 160 * Rewrites information for this taxonomy. 161 * 162 * @since 4.7.0 163 * @var array|false 164 */ 165 public $rewrite; 166 167 /** 168 * Query var string for this taxonomy. 169 * 170 * @since 4.7.0 171 * @var string|false 172 */ 173 public $query_var; 174 175 /** 176 * Function that will be called when the count is updated. 177 * 178 * @since 4.7.0 179 * @var callable 180 */ 181 public $update_count_callback; 182 183 /** 184 * Whether this taxonomy should appear in the REST API. 185 * 186 * Default false. If true, standard endpoints will be registered with 187 * respect to $rest_base and $rest_controller_class. 188 * 189 * @since 4.7.4 190 * @var bool $show_in_rest 191 */ 192 public $show_in_rest; 193 194 /** 195 * The base path for this taxonomy's REST API endpoints. 196 * 197 * @since 4.7.4 198 * @var string|bool $rest_base 199 */ 200 public $rest_base; 201 202 /** 203 * The controller for this taxonomy's REST API endpoints. 204 * 205 * Custom controllers must extend WP_REST_Controller. 206 * 207 * @since 4.7.4 208 * @var string|bool $rest_controller_class 209 */ 210 public $rest_controller_class; 211 212 /** 213 * The controller instance for this taxonomy's REST API endpoints. 214 * 215 * Lazily computed. Should be accessed using {@see WP_Taxonomy::get_rest_controller()}. 216 * 217 * @since 5.5.0 218 * @var WP_REST_Controller $rest_controller 219 */ 220 public $rest_controller; 221 222 /** 223 * The default term name for this taxonomy. If you pass an array you have 224 * to set 'name' and optionally 'slug' and 'description'. 225 * 226 * @since 5.5.0 227 * @var array|string 228 */ 229 public $default_term; 230 231 /** 232 * Whether terms in this taxonomy should be sorted in the order they are provided to `wp_set_object_terms()`. 233 * 234 * Use this in combination with `'orderby' => 'term_order'` when fetching terms. 235 * 236 * @since 2.5.0 237 * @var bool|null 238 */ 239 public $sort = null; 240 241 /** 242 * Array of arguments to automatically use inside `wp_get_object_terms()` for this taxonomy. 243 * 244 * @since 2.6.0 245 * @var array|null 246 */ 247 public $args = null; 248 249 /** 250 * Whether it is a built-in taxonomy. 251 * 252 * @since 4.7.0 253 * @var bool 254 */ 255 public $_builtin; 256 257 /** 258 * Constructor. 259 * 260 * See the register_taxonomy() function for accepted arguments for `$args`. 261 * 262 * @since 4.7.0 263 * 264 * @global WP $wp Current WordPress environment instance. 265 * 266 * @param string $taxonomy Taxonomy key, must not exceed 32 characters. 267 * @param array|string $object_type Name of the object type for the taxonomy object. 268 * @param array|string $args Optional. Array or query string of arguments for registering a taxonomy. 269 * Default empty array. 270 */ 271 public function __construct( $taxonomy, $object_type, $args = array() ) { 272 $this->name = $taxonomy; 273 274 $this->set_props( $object_type, $args ); 275 } 276 277 /** 278 * Sets taxonomy properties. 279 * 280 * See the register_taxonomy() function for accepted arguments for `$args`. 281 * 282 * @since 4.7.0 283 * 284 * @param array|string $object_type Name of the object type for the taxonomy object. 285 * @param array|string $args Array or query string of arguments for registering a taxonomy. 286 */ 287 public function set_props( $object_type, $args ) { 288 $args = wp_parse_args( $args ); 289 290 /** 291 * Filters the arguments for registering a taxonomy. 292 * 293 * @since 4.4.0 294 * 295 * @param array $args Array of arguments for registering a taxonomy. 296 * See the register_taxonomy() function for accepted arguments. 297 * @param string $taxonomy Taxonomy key. 298 * @param string[] $object_type Array of names of object types for the taxonomy. 299 */ 300 $args = apply_filters( 'register_taxonomy_args', $args, $this->name, (array) $object_type ); 301 302 $defaults = array( 303 'labels' => array(), 304 'description' => '', 305 'public' => true, 306 'publicly_queryable' => null, 307 'hierarchical' => false, 308 'show_ui' => null, 309 'show_in_menu' => null, 310 'show_in_nav_menus' => null, 311 'show_tagcloud' => null, 312 'show_in_quick_edit' => null, 313 'show_admin_column' => false, 314 'meta_box_cb' => null, 315 'meta_box_sanitize_cb' => null, 316 'capabilities' => array(), 317 'rewrite' => true, 318 'query_var' => $this->name, 319 'update_count_callback' => '', 320 'show_in_rest' => false, 321 'rest_base' => false, 322 'rest_controller_class' => false, 323 'default_term' => null, 324 'sort' => null, 325 'args' => null, 326 '_builtin' => false, 327 ); 328 329 $args = array_merge( $defaults, $args ); 330 331 // If not set, default to the setting for 'public'. 332 if ( null === $args['publicly_queryable'] ) { 333 $args['publicly_queryable'] = $args['public']; 334 } 335 336 if ( false !== $args['query_var'] && ( is_admin() || false !== $args['publicly_queryable'] ) ) { 337 if ( true === $args['query_var'] ) { 338 $args['query_var'] = $this->name; 339 } else { 340 $args['query_var'] = sanitize_title_with_dashes( $args['query_var'] ); 341 } 342 } else { 343 // Force 'query_var' to false for non-public taxonomies. 344 $args['query_var'] = false; 345 } 346 347 if ( false !== $args['rewrite'] && ( is_admin() || get_option( 'permalink_structure' ) ) ) { 348 $args['rewrite'] = wp_parse_args( 349 $args['rewrite'], 350 array( 351 'with_front' => true, 352 'hierarchical' => false, 353 'ep_mask' => EP_NONE, 354 ) 355 ); 356 357 if ( empty( $args['rewrite']['slug'] ) ) { 358 $args['rewrite']['slug'] = sanitize_title_with_dashes( $this->name ); 359 } 360 } 361 362 // If not set, default to the setting for 'public'. 363 if ( null === $args['show_ui'] ) { 364 $args['show_ui'] = $args['public']; 365 } 366 367 // If not set, default to the setting for 'show_ui'. 368 if ( null === $args['show_in_menu'] || ! $args['show_ui'] ) { 369 $args['show_in_menu'] = $args['show_ui']; 370 } 371 372 // If not set, default to the setting for 'public'. 373 if ( null === $args['show_in_nav_menus'] ) { 374 $args['show_in_nav_menus'] = $args['public']; 375 } 376 377 // If not set, default to the setting for 'show_ui'. 378 if ( null === $args['show_tagcloud'] ) { 379 $args['show_tagcloud'] = $args['show_ui']; 380 } 381 382 // If not set, default to the setting for 'show_ui'. 383 if ( null === $args['show_in_quick_edit'] ) { 384 $args['show_in_quick_edit'] = $args['show_ui']; 385 } 386 387 $default_caps = array( 388 'manage_terms' => 'manage_categories', 389 'edit_terms' => 'manage_categories', 390 'delete_terms' => 'manage_categories', 391 'assign_terms' => 'edit_posts', 392 ); 393 394 $args['cap'] = (object) array_merge( $default_caps, $args['capabilities'] ); 395 unset( $args['capabilities'] ); 396 397 $args['object_type'] = array_unique( (array) $object_type ); 398 399 // If not set, use the default meta box. 400 if ( null === $args['meta_box_cb'] ) { 401 if ( $args['hierarchical'] ) { 402 $args['meta_box_cb'] = 'post_categories_meta_box'; 403 } else { 404 $args['meta_box_cb'] = 'post_tags_meta_box'; 405 } 406 } 407 408 $args['name'] = $this->name; 409 410 // Default meta box sanitization callback depends on the value of 'meta_box_cb'. 411 if ( null === $args['meta_box_sanitize_cb'] ) { 412 switch ( $args['meta_box_cb'] ) { 413 case 'post_categories_meta_box': 414 $args['meta_box_sanitize_cb'] = 'taxonomy_meta_box_sanitize_cb_checkboxes'; 415 break; 416 417 case 'post_tags_meta_box': 418 default: 419 $args['meta_box_sanitize_cb'] = 'taxonomy_meta_box_sanitize_cb_input'; 420 break; 421 } 422 } 423 424 // Default taxonomy term. 425 if ( ! empty( $args['default_term'] ) ) { 426 if ( ! is_array( $args['default_term'] ) ) { 427 $args['default_term'] = array( 'name' => $args['default_term'] ); 428 } 429 $args['default_term'] = wp_parse_args( 430 $args['default_term'], 431 array( 432 'name' => '', 433 'slug' => '', 434 'description' => '', 435 ) 436 ); 437 } 438 439 foreach ( $args as $property_name => $property_value ) { 440 $this->$property_name = $property_value; 441 } 442 443 $this->labels = get_taxonomy_labels( $this ); 444 $this->label = $this->labels->name; 445 } 446 447 /** 448 * Adds the necessary rewrite rules for the taxonomy. 449 * 450 * @since 4.7.0 451 * 452 * @global WP $wp Current WordPress environment instance. 453 */ 454 public function add_rewrite_rules() { 455 /* @var WP $wp */ 456 global $wp; 457 458 // Non-publicly queryable taxonomies should not register query vars, except in the admin. 459 if ( false !== $this->query_var && $wp ) { 460 $wp->add_query_var( $this->query_var ); 461 } 462 463 if ( false !== $this->rewrite && ( is_admin() || get_option( 'permalink_structure' ) ) ) { 464 if ( $this->hierarchical && $this->rewrite['hierarchical'] ) { 465 $tag = '(.+?)'; 466 } else { 467 $tag = '([^/]+)'; 468 } 469 470 add_rewrite_tag( "%$this->name%", $tag, $this->query_var ? "{$this->query_var}=" : "taxonomy=$this->name&term=" ); 471 add_permastruct( $this->name, "{$this->rewrite['slug']}/%$this->name%", $this->rewrite ); 472 } 473 } 474 475 /** 476 * Removes any rewrite rules, permastructs, and rules for the taxonomy. 477 * 478 * @since 4.7.0 479 * 480 * @global WP $wp Current WordPress environment instance. 481 */ 482 public function remove_rewrite_rules() { 483 /* @var WP $wp */ 484 global $wp; 485 486 // Remove query var. 487 if ( false !== $this->query_var ) { 488 $wp->remove_query_var( $this->query_var ); 489 } 490 491 // Remove rewrite tags and permastructs. 492 if ( false !== $this->rewrite ) { 493 remove_rewrite_tag( "%$this->name%" ); 494 remove_permastruct( $this->name ); 495 } 496 } 497 498 /** 499 * Registers the ajax callback for the meta box. 500 * 501 * @since 4.7.0 502 */ 503 public function add_hooks() { 504 add_filter( 'wp_ajax_add-' . $this->name, '_wp_ajax_add_hierarchical_term' ); 505 } 506 507 /** 508 * Removes the ajax callback for the meta box. 509 * 510 * @since 4.7.0 511 */ 512 public function remove_hooks() { 513 remove_filter( 'wp_ajax_add-' . $this->name, '_wp_ajax_add_hierarchical_term' ); 514 } 515 516 /** 517 * Gets the REST API controller for this taxonomy. 518 * 519 * Will only instantiate the controller class once per request. 520 * 521 * @since 5.5.0 522 * 523 * @return WP_REST_Controller|null The controller instance, or null if the taxonomy 524 * is set not to show in rest. 525 */ 526 public function get_rest_controller() { 527 if ( ! $this->show_in_rest ) { 528 return null; 529 } 530 531 $class = $this->rest_controller_class ? $this->rest_controller_class : WP_REST_Terms_Controller::class; 532 533 if ( ! class_exists( $class ) ) { 534 return null; 535 } 536 537 if ( ! is_subclass_of( $class, WP_REST_Controller::class ) ) { 538 return null; 539 } 540 541 if ( ! $this->rest_controller ) { 542 $this->rest_controller = new $class( $this->name ); 543 } 544 545 if ( ! ( $this->rest_controller instanceof $class ) ) { 546 return null; 547 } 548 549 return $this->rest_controller; 550 } 551 }