[ Index ]

PHP Cross Reference of WordPress

title

Body

[close]

/wp-includes/rest-api/endpoints/ -> class-wp-rest-terms-controller.php (source)

   1  <?php
   2  /**
   3   * REST API: WP_REST_Terms_Controller class
   4   *
   5   * @package WordPress
   6   * @subpackage REST_API
   7   * @since 4.7.0
   8   */
   9  
  10  /**
  11   * Core class used to managed terms associated with a taxonomy via the REST API.
  12   *
  13   * @since 4.7.0
  14   *
  15   * @see WP_REST_Controller
  16   */
  17  class WP_REST_Terms_Controller extends WP_REST_Controller {
  18  
  19      /**
  20       * Taxonomy key.
  21       *
  22       * @since 4.7.0
  23       * @var string
  24       */
  25      protected $taxonomy;
  26  
  27      /**
  28       * Instance of a term meta fields object.
  29       *
  30       * @since 4.7.0
  31       * @var WP_REST_Term_Meta_Fields
  32       */
  33      protected $meta;
  34  
  35      /**
  36       * Column to have the terms be sorted by.
  37       *
  38       * @since 4.7.0
  39       * @var string
  40       */
  41      protected $sort_column;
  42  
  43      /**
  44       * Number of terms that were found.
  45       *
  46       * @since 4.7.0
  47       * @var int
  48       */
  49      protected $total_terms;
  50  
  51      /**
  52       * Whether the controller supports batching.
  53       *
  54       * @since 5.9.0
  55       * @var array
  56       */
  57      protected $allow_batch = array( 'v1' => true );
  58  
  59      /**
  60       * Constructor.
  61       *
  62       * @since 4.7.0
  63       *
  64       * @param string $taxonomy Taxonomy key.
  65       */
  66  	public function __construct( $taxonomy ) {
  67          $this->taxonomy  = $taxonomy;
  68          $tax_obj         = get_taxonomy( $taxonomy );
  69          $this->rest_base = ! empty( $tax_obj->rest_base ) ? $tax_obj->rest_base : $tax_obj->name;
  70          $this->namespace = ! empty( $tax_obj->rest_namespace ) ? $tax_obj->rest_namespace : 'wp/v2';
  71  
  72          $this->meta = new WP_REST_Term_Meta_Fields( $taxonomy );
  73      }
  74  
  75      /**
  76       * Registers the routes for terms.
  77       *
  78       * @since 4.7.0
  79       *
  80       * @see register_rest_route()
  81       */
  82  	public function register_routes() {
  83  
  84          register_rest_route(
  85              $this->namespace,
  86              '/' . $this->rest_base,
  87              array(
  88                  array(
  89                      'methods'             => WP_REST_Server::READABLE,
  90                      'callback'            => array( $this, 'get_items' ),
  91                      'permission_callback' => array( $this, 'get_items_permissions_check' ),
  92                      'args'                => $this->get_collection_params(),
  93                  ),
  94                  array(
  95                      'methods'             => WP_REST_Server::CREATABLE,
  96                      'callback'            => array( $this, 'create_item' ),
  97                      'permission_callback' => array( $this, 'create_item_permissions_check' ),
  98                      'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),
  99                  ),
 100                  'allow_batch' => $this->allow_batch,
 101                  'schema'      => array( $this, 'get_public_item_schema' ),
 102              )
 103          );
 104  
 105          register_rest_route(
 106              $this->namespace,
 107              '/' . $this->rest_base . '/(?P<id>[\d]+)',
 108              array(
 109                  'args'        => array(
 110                      'id' => array(
 111                          'description' => __( 'Unique identifier for the term.' ),
 112                          'type'        => 'integer',
 113                      ),
 114                  ),
 115                  array(
 116                      'methods'             => WP_REST_Server::READABLE,
 117                      'callback'            => array( $this, 'get_item' ),
 118                      'permission_callback' => array( $this, 'get_item_permissions_check' ),
 119                      'args'                => array(
 120                          'context' => $this->get_context_param( array( 'default' => 'view' ) ),
 121                      ),
 122                  ),
 123                  array(
 124                      'methods'             => WP_REST_Server::EDITABLE,
 125                      'callback'            => array( $this, 'update_item' ),
 126                      'permission_callback' => array( $this, 'update_item_permissions_check' ),
 127                      'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
 128                  ),
 129                  array(
 130                      'methods'             => WP_REST_Server::DELETABLE,
 131                      'callback'            => array( $this, 'delete_item' ),
 132                      'permission_callback' => array( $this, 'delete_item_permissions_check' ),
 133                      'args'                => array(
 134                          'force' => array(
 135                              'type'        => 'boolean',
 136                              'default'     => false,
 137                              'description' => __( 'Required to be true, as terms do not support trashing.' ),
 138                          ),
 139                      ),
 140                  ),
 141                  'allow_batch' => $this->allow_batch,
 142                  'schema'      => array( $this, 'get_public_item_schema' ),
 143              )
 144          );
 145      }
 146  
 147      /**
 148       * Checks if a request has access to read terms in the specified taxonomy.
 149       *
 150       * @since 4.7.0
 151       *
 152       * @param WP_REST_Request $request Full details about the request.
 153       * @return true|WP_Error True if the request has read access, otherwise false or WP_Error object.
 154       */
 155  	public function get_items_permissions_check( $request ) {
 156          $tax_obj = get_taxonomy( $this->taxonomy );
 157  
 158          if ( ! $tax_obj || ! $this->check_is_taxonomy_allowed( $this->taxonomy ) ) {
 159              return false;
 160          }
 161  
 162          if ( 'edit' === $request['context'] && ! current_user_can( $tax_obj->cap->edit_terms ) ) {
 163              return new WP_Error(
 164                  'rest_forbidden_context',
 165                  __( 'Sorry, you are not allowed to edit terms in this taxonomy.' ),
 166                  array( 'status' => rest_authorization_required_code() )
 167              );
 168          }
 169  
 170          return true;
 171      }
 172  
 173      /**
 174       * Retrieves terms associated with a taxonomy.
 175       *
 176       * @since 4.7.0
 177       *
 178       * @param WP_REST_Request $request Full details about the request.
 179       * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
 180       */
 181  	public function get_items( $request ) {
 182  
 183          // Retrieve the list of registered collection query parameters.
 184          $registered = $this->get_collection_params();
 185  
 186          /*
 187           * This array defines mappings between public API query parameters whose
 188           * values are accepted as-passed, and their internal WP_Query parameter
 189           * name equivalents (some are the same). Only values which are also
 190           * present in $registered will be set.
 191           */
 192          $parameter_mappings = array(
 193              'exclude'    => 'exclude',
 194              'include'    => 'include',
 195              'order'      => 'order',
 196              'orderby'    => 'orderby',
 197              'post'       => 'post',
 198              'hide_empty' => 'hide_empty',
 199              'per_page'   => 'number',
 200              'search'     => 'search',
 201              'slug'       => 'slug',
 202          );
 203  
 204          $prepared_args = array( 'taxonomy' => $this->taxonomy );
 205  
 206          /*
 207           * For each known parameter which is both registered and present in the request,
 208           * set the parameter's value on the query $prepared_args.
 209           */
 210          foreach ( $parameter_mappings as $api_param => $wp_param ) {
 211              if ( isset( $registered[ $api_param ], $request[ $api_param ] ) ) {
 212                  $prepared_args[ $wp_param ] = $request[ $api_param ];
 213              }
 214          }
 215  
 216          if ( isset( $prepared_args['orderby'] ) && isset( $request['orderby'] ) ) {
 217              $orderby_mappings = array(
 218                  'include_slugs' => 'slug__in',
 219              );
 220  
 221              if ( isset( $orderby_mappings[ $request['orderby'] ] ) ) {
 222                  $prepared_args['orderby'] = $orderby_mappings[ $request['orderby'] ];
 223              }
 224          }
 225  
 226          if ( isset( $registered['offset'] ) && ! empty( $request['offset'] ) ) {
 227              $prepared_args['offset'] = $request['offset'];
 228          } else {
 229              $prepared_args['offset'] = ( $request['page'] - 1 ) * $prepared_args['number'];
 230          }
 231  
 232          $taxonomy_obj = get_taxonomy( $this->taxonomy );
 233  
 234          if ( $taxonomy_obj->hierarchical && isset( $registered['parent'], $request['parent'] ) ) {
 235              if ( 0 === $request['parent'] ) {
 236                  // Only query top-level terms.
 237                  $prepared_args['parent'] = 0;
 238              } else {
 239                  if ( $request['parent'] ) {
 240                      $prepared_args['parent'] = $request['parent'];
 241                  }
 242              }
 243          }
 244  
 245          /**
 246           * Filters get_terms() arguments when querying terms via the REST API.
 247           *
 248           * The dynamic portion of the hook name, `$this->taxonomy`, refers to the taxonomy slug.
 249           *
 250           * Possible hook names include:
 251           *
 252           *  - `rest_category_query`
 253           *  - `rest_post_tag_query`
 254           *
 255           * Enables adding extra arguments or setting defaults for a terms
 256           * collection request.
 257           *
 258           * @since 4.7.0
 259           *
 260           * @link https://developer.wordpress.org/reference/functions/get_terms/
 261           *
 262           * @param array           $prepared_args Array of arguments for get_terms().
 263           * @param WP_REST_Request $request       The REST API request.
 264           */
 265          $prepared_args = apply_filters( "rest_{$this->taxonomy}_query", $prepared_args, $request );
 266  
 267          if ( ! empty( $prepared_args['post'] ) ) {
 268              $query_result = wp_get_object_terms( $prepared_args['post'], $this->taxonomy, $prepared_args );
 269  
 270              // Used when calling wp_count_terms() below.
 271              $prepared_args['object_ids'] = $prepared_args['post'];
 272          } else {
 273              $query_result = get_terms( $prepared_args );
 274          }
 275  
 276          $count_args = $prepared_args;
 277  
 278          unset( $count_args['number'], $count_args['offset'] );
 279  
 280          $total_terms = wp_count_terms( $count_args );
 281  
 282          // wp_count_terms() can return a falsey value when the term has no children.
 283          if ( ! $total_terms ) {
 284              $total_terms = 0;
 285          }
 286  
 287          $response = array();
 288  
 289          foreach ( $query_result as $term ) {
 290              $data       = $this->prepare_item_for_response( $term, $request );
 291              $response[] = $this->prepare_response_for_collection( $data );
 292          }
 293  
 294          $response = rest_ensure_response( $response );
 295  
 296          // Store pagination values for headers.
 297          $per_page = (int) $prepared_args['number'];
 298          $page     = ceil( ( ( (int) $prepared_args['offset'] ) / $per_page ) + 1 );
 299  
 300          $response->header( 'X-WP-Total', (int) $total_terms );
 301  
 302          $max_pages = ceil( $total_terms / $per_page );
 303  
 304          $response->header( 'X-WP-TotalPages', (int) $max_pages );
 305  
 306          $base = add_query_arg( urlencode_deep( $request->get_query_params() ), rest_url( $this->namespace . '/' . $this->rest_base ) );
 307          if ( $page > 1 ) {
 308              $prev_page = $page - 1;
 309  
 310              if ( $prev_page > $max_pages ) {
 311                  $prev_page = $max_pages;
 312              }
 313  
 314              $prev_link = add_query_arg( 'page', $prev_page, $base );
 315              $response->link_header( 'prev', $prev_link );
 316          }
 317          if ( $max_pages > $page ) {
 318              $next_page = $page + 1;
 319              $next_link = add_query_arg( 'page', $next_page, $base );
 320  
 321              $response->link_header( 'next', $next_link );
 322          }
 323  
 324          return $response;
 325      }
 326  
 327      /**
 328       * Get the term, if the ID is valid.
 329       *
 330       * @since 4.7.2
 331       *
 332       * @param int $id Supplied ID.
 333       * @return WP_Term|WP_Error Term object if ID is valid, WP_Error otherwise.
 334       */
 335  	protected function get_term( $id ) {
 336          $error = new WP_Error(
 337              'rest_term_invalid',
 338              __( 'Term does not exist.' ),
 339              array( 'status' => 404 )
 340          );
 341  
 342          if ( ! $this->check_is_taxonomy_allowed( $this->taxonomy ) ) {
 343              return $error;
 344          }
 345  
 346          if ( (int) $id <= 0 ) {
 347              return $error;
 348          }
 349  
 350          $term = get_term( (int) $id, $this->taxonomy );
 351          if ( empty( $term ) || $term->taxonomy !== $this->taxonomy ) {
 352              return $error;
 353          }
 354  
 355          return $term;
 356      }
 357  
 358      /**
 359       * Checks if a request has access to read or edit the specified term.
 360       *
 361       * @since 4.7.0
 362       *
 363       * @param WP_REST_Request $request Full details about the request.
 364       * @return true|WP_Error True if the request has read access for the item, otherwise false or WP_Error object.
 365       */
 366  	public function get_item_permissions_check( $request ) {
 367          $term = $this->get_term( $request['id'] );
 368  
 369          if ( is_wp_error( $term ) ) {
 370              return $term;
 371          }
 372  
 373          if ( 'edit' === $request['context'] && ! current_user_can( 'edit_term', $term->term_id ) ) {
 374              return new WP_Error(
 375                  'rest_forbidden_context',
 376                  __( 'Sorry, you are not allowed to edit this term.' ),
 377                  array( 'status' => rest_authorization_required_code() )
 378              );
 379          }
 380  
 381          return true;
 382      }
 383  
 384      /**
 385       * Gets a single term from a taxonomy.
 386       *
 387       * @since 4.7.0
 388       *
 389       * @param WP_REST_Request $request Full details about the request.
 390       * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
 391       */
 392  	public function get_item( $request ) {
 393          $term = $this->get_term( $request['id'] );
 394          if ( is_wp_error( $term ) ) {
 395              return $term;
 396          }
 397  
 398          $response = $this->prepare_item_for_response( $term, $request );
 399  
 400          return rest_ensure_response( $response );
 401      }
 402  
 403      /**
 404       * Checks if a request has access to create a term.
 405       *
 406       * @since 4.7.0
 407       *
 408       * @param WP_REST_Request $request Full details about the request.
 409       * @return true|WP_Error True if the request has access to create items, false or WP_Error object otherwise.
 410       */
 411  	public function create_item_permissions_check( $request ) {
 412  
 413          if ( ! $this->check_is_taxonomy_allowed( $this->taxonomy ) ) {
 414              return false;
 415          }
 416  
 417          $taxonomy_obj = get_taxonomy( $this->taxonomy );
 418  
 419          if ( ( is_taxonomy_hierarchical( $this->taxonomy )
 420                  && ! current_user_can( $taxonomy_obj->cap->edit_terms ) )
 421              || ( ! is_taxonomy_hierarchical( $this->taxonomy )
 422                  && ! current_user_can( $taxonomy_obj->cap->assign_terms ) ) ) {
 423              return new WP_Error(
 424                  'rest_cannot_create',
 425                  __( 'Sorry, you are not allowed to create terms in this taxonomy.' ),
 426                  array( 'status' => rest_authorization_required_code() )
 427              );
 428          }
 429  
 430          return true;
 431      }
 432  
 433      /**
 434       * Creates a single term in a taxonomy.
 435       *
 436       * @since 4.7.0
 437       *
 438       * @param WP_REST_Request $request Full details about the request.
 439       * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
 440       */
 441  	public function create_item( $request ) {
 442          if ( isset( $request['parent'] ) ) {
 443              if ( ! is_taxonomy_hierarchical( $this->taxonomy ) ) {
 444                  return new WP_Error(
 445                      'rest_taxonomy_not_hierarchical',
 446                      __( 'Cannot set parent term, taxonomy is not hierarchical.' ),
 447                      array( 'status' => 400 )
 448                  );
 449              }
 450  
 451              $parent = get_term( (int) $request['parent'], $this->taxonomy );
 452  
 453              if ( ! $parent ) {
 454                  return new WP_Error(
 455                      'rest_term_invalid',
 456                      __( 'Parent term does not exist.' ),
 457                      array( 'status' => 400 )
 458                  );
 459              }
 460          }
 461  
 462          $prepared_term = $this->prepare_item_for_database( $request );
 463  
 464          $term = wp_insert_term( wp_slash( $prepared_term->name ), $this->taxonomy, wp_slash( (array) $prepared_term ) );
 465          if ( is_wp_error( $term ) ) {
 466              /*
 467               * If we're going to inform the client that the term already exists,
 468               * give them the identifier for future use.
 469               */
 470              $term_id = $term->get_error_data( 'term_exists' );
 471              if ( $term_id ) {
 472                  $existing_term = get_term( $term_id, $this->taxonomy );
 473                  $term->add_data( $existing_term->term_id, 'term_exists' );
 474                  $term->add_data(
 475                      array(
 476                          'status'  => 400,
 477                          'term_id' => $term_id,
 478                      )
 479                  );
 480              }
 481  
 482              return $term;
 483          }
 484  
 485          $term = get_term( $term['term_id'], $this->taxonomy );
 486  
 487          /**
 488           * Fires after a single term is created or updated via the REST API.
 489           *
 490           * The dynamic portion of the hook name, `$this->taxonomy`, refers to the taxonomy slug.
 491           *
 492           * Possible hook names include:
 493           *
 494           *  - `rest_insert_category`
 495           *  - `rest_insert_post_tag`
 496           *
 497           * @since 4.7.0
 498           *
 499           * @param WP_Term         $term     Inserted or updated term object.
 500           * @param WP_REST_Request $request  Request object.
 501           * @param bool            $creating True when creating a term, false when updating.
 502           */
 503          do_action( "rest_insert_{$this->taxonomy}", $term, $request, true );
 504  
 505          $schema = $this->get_item_schema();
 506          if ( ! empty( $schema['properties']['meta'] ) && isset( $request['meta'] ) ) {
 507              $meta_update = $this->meta->update_value( $request['meta'], $term->term_id );
 508  
 509              if ( is_wp_error( $meta_update ) ) {
 510                  return $meta_update;
 511              }
 512          }
 513  
 514          $fields_update = $this->update_additional_fields_for_object( $term, $request );
 515  
 516          if ( is_wp_error( $fields_update ) ) {
 517              return $fields_update;
 518          }
 519  
 520          $request->set_param( 'context', 'edit' );
 521  
 522          /**
 523           * Fires after a single term is completely created or updated via the REST API.
 524           *
 525           * The dynamic portion of the hook name, `$this->taxonomy`, refers to the taxonomy slug.
 526           *
 527           * Possible hook names include:
 528           *
 529           *  - `rest_after_insert_category`
 530           *  - `rest_after_insert_post_tag`
 531           *
 532           * @since 5.0.0
 533           *
 534           * @param WP_Term         $term     Inserted or updated term object.
 535           * @param WP_REST_Request $request  Request object.
 536           * @param bool            $creating True when creating a term, false when updating.
 537           */
 538          do_action( "rest_after_insert_{$this->taxonomy}", $term, $request, true );
 539  
 540          $response = $this->prepare_item_for_response( $term, $request );
 541          $response = rest_ensure_response( $response );
 542  
 543          $response->set_status( 201 );
 544          $response->header( 'Location', rest_url( $this->namespace . '/' . $this->rest_base . '/' . $term->term_id ) );
 545  
 546          return $response;
 547      }
 548  
 549      /**
 550       * Checks if a request has access to update the specified term.
 551       *
 552       * @since 4.7.0
 553       *
 554       * @param WP_REST_Request $request Full details about the request.
 555       * @return true|WP_Error True if the request has access to update the item, false or WP_Error object otherwise.
 556       */
 557  	public function update_item_permissions_check( $request ) {
 558          $term = $this->get_term( $request['id'] );
 559  
 560          if ( is_wp_error( $term ) ) {
 561              return $term;
 562          }
 563  
 564          if ( ! current_user_can( 'edit_term', $term->term_id ) ) {
 565              return new WP_Error(
 566                  'rest_cannot_update',
 567                  __( 'Sorry, you are not allowed to edit this term.' ),
 568                  array( 'status' => rest_authorization_required_code() )
 569              );
 570          }
 571  
 572          return true;
 573      }
 574  
 575      /**
 576       * Updates a single term from a taxonomy.
 577       *
 578       * @since 4.7.0
 579       *
 580       * @param WP_REST_Request $request Full details about the request.
 581       * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
 582       */
 583  	public function update_item( $request ) {
 584          $term = $this->get_term( $request['id'] );
 585          if ( is_wp_error( $term ) ) {
 586              return $term;
 587          }
 588  
 589          if ( isset( $request['parent'] ) ) {
 590              if ( ! is_taxonomy_hierarchical( $this->taxonomy ) ) {
 591                  return new WP_Error(
 592                      'rest_taxonomy_not_hierarchical',
 593                      __( 'Cannot set parent term, taxonomy is not hierarchical.' ),
 594                      array( 'status' => 400 )
 595                  );
 596              }
 597  
 598              $parent = get_term( (int) $request['parent'], $this->taxonomy );
 599  
 600              if ( ! $parent ) {
 601                  return new WP_Error(
 602                      'rest_term_invalid',
 603                      __( 'Parent term does not exist.' ),
 604                      array( 'status' => 400 )
 605                  );
 606              }
 607          }
 608  
 609          $prepared_term = $this->prepare_item_for_database( $request );
 610  
 611          // Only update the term if we have something to update.
 612          if ( ! empty( $prepared_term ) ) {
 613              $update = wp_update_term( $term->term_id, $term->taxonomy, wp_slash( (array) $prepared_term ) );
 614  
 615              if ( is_wp_error( $update ) ) {
 616                  return $update;
 617              }
 618          }
 619  
 620          $term = get_term( $term->term_id, $this->taxonomy );
 621  
 622          /** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php */
 623          do_action( "rest_insert_{$this->taxonomy}", $term, $request, false );
 624  
 625          $schema = $this->get_item_schema();
 626          if ( ! empty( $schema['properties']['meta'] ) && isset( $request['meta'] ) ) {
 627              $meta_update = $this->meta->update_value( $request['meta'], $term->term_id );
 628  
 629              if ( is_wp_error( $meta_update ) ) {
 630                  return $meta_update;
 631              }
 632          }
 633  
 634          $fields_update = $this->update_additional_fields_for_object( $term, $request );
 635  
 636          if ( is_wp_error( $fields_update ) ) {
 637              return $fields_update;
 638          }
 639  
 640          $request->set_param( 'context', 'edit' );
 641  
 642          /** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php */
 643          do_action( "rest_after_insert_{$this->taxonomy}", $term, $request, false );
 644  
 645          $response = $this->prepare_item_for_response( $term, $request );
 646  
 647          return rest_ensure_response( $response );
 648      }
 649  
 650      /**
 651       * Checks if a request has access to delete the specified term.
 652       *
 653       * @since 4.7.0
 654       *
 655       * @param WP_REST_Request $request Full details about the request.
 656       * @return true|WP_Error True if the request has access to delete the item, otherwise false or WP_Error object.
 657       */
 658  	public function delete_item_permissions_check( $request ) {
 659          $term = $this->get_term( $request['id'] );
 660  
 661          if ( is_wp_error( $term ) ) {
 662              return $term;
 663          }
 664  
 665          if ( ! current_user_can( 'delete_term', $term->term_id ) ) {
 666              return new WP_Error(
 667                  'rest_cannot_delete',
 668                  __( 'Sorry, you are not allowed to delete this term.' ),
 669                  array( 'status' => rest_authorization_required_code() )
 670              );
 671          }
 672  
 673          return true;
 674      }
 675  
 676      /**
 677       * Deletes a single term from a taxonomy.
 678       *
 679       * @since 4.7.0
 680       *
 681       * @param WP_REST_Request $request Full details about the request.
 682       * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
 683       */
 684  	public function delete_item( $request ) {
 685          $term = $this->get_term( $request['id'] );
 686          if ( is_wp_error( $term ) ) {
 687              return $term;
 688          }
 689  
 690          $force = isset( $request['force'] ) ? (bool) $request['force'] : false;
 691  
 692          // We don't support trashing for terms.
 693          if ( ! $force ) {
 694              return new WP_Error(
 695                  'rest_trash_not_supported',
 696                  /* translators: %s: force=true */
 697                  sprintf( __( "Terms do not support trashing. Set '%s' to delete." ), 'force=true' ),
 698                  array( 'status' => 501 )
 699              );
 700          }
 701  
 702          $request->set_param( 'context', 'view' );
 703  
 704          $previous = $this->prepare_item_for_response( $term, $request );
 705  
 706          $retval = wp_delete_term( $term->term_id, $term->taxonomy );
 707  
 708          if ( ! $retval ) {
 709              return new WP_Error(
 710                  'rest_cannot_delete',
 711                  __( 'The term cannot be deleted.' ),
 712                  array( 'status' => 500 )
 713              );
 714          }
 715  
 716          $response = new WP_REST_Response();
 717          $response->set_data(
 718              array(
 719                  'deleted'  => true,
 720                  'previous' => $previous->get_data(),
 721              )
 722          );
 723  
 724          /**
 725           * Fires after a single term is deleted via the REST API.
 726           *
 727           * The dynamic portion of the hook name, `$this->taxonomy`, refers to the taxonomy slug.
 728           *
 729           * Possible hook names include:
 730           *
 731           *  - `rest_delete_category`
 732           *  - `rest_delete_post_tag`
 733           *
 734           * @since 4.7.0
 735           *
 736           * @param WP_Term          $term     The deleted term.
 737           * @param WP_REST_Response $response The response data.
 738           * @param WP_REST_Request  $request  The request sent to the API.
 739           */
 740          do_action( "rest_delete_{$this->taxonomy}", $term, $response, $request );
 741  
 742          return $response;
 743      }
 744  
 745      /**
 746       * Prepares a single term for create or update.
 747       *
 748       * @since 4.7.0
 749       *
 750       * @param WP_REST_Request $request Request object.
 751       * @return object Term object.
 752       */
 753  	public function prepare_item_for_database( $request ) {
 754          $prepared_term = new stdClass;
 755  
 756          $schema = $this->get_item_schema();
 757          if ( isset( $request['name'] ) && ! empty( $schema['properties']['name'] ) ) {
 758              $prepared_term->name = $request['name'];
 759          }
 760  
 761          if ( isset( $request['slug'] ) && ! empty( $schema['properties']['slug'] ) ) {
 762              $prepared_term->slug = $request['slug'];
 763          }
 764  
 765          if ( isset( $request['taxonomy'] ) && ! empty( $schema['properties']['taxonomy'] ) ) {
 766              $prepared_term->taxonomy = $request['taxonomy'];
 767          }
 768  
 769          if ( isset( $request['description'] ) && ! empty( $schema['properties']['description'] ) ) {
 770              $prepared_term->description = $request['description'];
 771          }
 772  
 773          if ( isset( $request['parent'] ) && ! empty( $schema['properties']['parent'] ) ) {
 774              $parent_term_id   = 0;
 775              $requested_parent = (int) $request['parent'];
 776  
 777              if ( $requested_parent ) {
 778                  $parent_term = get_term( $requested_parent, $this->taxonomy );
 779  
 780                  if ( $parent_term instanceof WP_Term ) {
 781                      $parent_term_id = $parent_term->term_id;
 782                  }
 783              }
 784  
 785              $prepared_term->parent = $parent_term_id;
 786          }
 787  
 788          /**
 789           * Filters term data before inserting term via the REST API.
 790           *
 791           * The dynamic portion of the hook name, `$this->taxonomy`, refers to the taxonomy slug.
 792           *
 793           * Possible hook names include:
 794           *
 795           *  - `rest_pre_insert_category`
 796           *  - `rest_pre_insert_post_tag`
 797           *
 798           * @since 4.7.0
 799           *
 800           * @param object          $prepared_term Term object.
 801           * @param WP_REST_Request $request       Request object.
 802           */
 803          return apply_filters( "rest_pre_insert_{$this->taxonomy}", $prepared_term, $request );
 804      }
 805  
 806      /**
 807       * Prepares a single term output for response.
 808       *
 809       * @since 4.7.0
 810       *
 811       * @param WP_Term         $item    Term object.
 812       * @param WP_REST_Request $request Request object.
 813       * @return WP_REST_Response Response object.
 814       */
 815  	public function prepare_item_for_response( $item, $request ) {
 816  
 817          $fields = $this->get_fields_for_response( $request );
 818          $data   = array();
 819  
 820          if ( in_array( 'id', $fields, true ) ) {
 821              $data['id'] = (int) $item->term_id;
 822          }
 823  
 824          if ( in_array( 'count', $fields, true ) ) {
 825              $data['count'] = (int) $item->count;
 826          }
 827  
 828          if ( in_array( 'description', $fields, true ) ) {
 829              $data['description'] = $item->description;
 830          }
 831  
 832          if ( in_array( 'link', $fields, true ) ) {
 833              $data['link'] = get_term_link( $item );
 834          }
 835  
 836          if ( in_array( 'name', $fields, true ) ) {
 837              $data['name'] = $item->name;
 838          }
 839  
 840          if ( in_array( 'slug', $fields, true ) ) {
 841              $data['slug'] = $item->slug;
 842          }
 843  
 844          if ( in_array( 'taxonomy', $fields, true ) ) {
 845              $data['taxonomy'] = $item->taxonomy;
 846          }
 847  
 848          if ( in_array( 'parent', $fields, true ) ) {
 849              $data['parent'] = (int) $item->parent;
 850          }
 851  
 852          if ( in_array( 'meta', $fields, true ) ) {
 853              $data['meta'] = $this->meta->get_value( $item->term_id, $request );
 854          }
 855  
 856          $context = ! empty( $request['context'] ) ? $request['context'] : 'view';
 857          $data    = $this->add_additional_fields_to_object( $data, $request );
 858          $data    = $this->filter_response_by_context( $data, $context );
 859  
 860          $response = rest_ensure_response( $data );
 861  
 862          $response->add_links( $this->prepare_links( $item ) );
 863  
 864          /**
 865           * Filters the term data for a REST API response.
 866           *
 867           * The dynamic portion of the hook name, `$this->taxonomy`, refers to the taxonomy slug.
 868           *
 869           * Possible hook names include:
 870           *
 871           *  - `rest_prepare_category`
 872           *  - `rest_prepare_post_tag`
 873           *
 874           * Allows modification of the term data right before it is returned.
 875           *
 876           * @since 4.7.0
 877           *
 878           * @param WP_REST_Response  $response  The response object.
 879           * @param WP_Term           $item      The original term object.
 880           * @param WP_REST_Request   $request   Request used to generate the response.
 881           */
 882          return apply_filters( "rest_prepare_{$this->taxonomy}", $response, $item, $request );
 883      }
 884  
 885      /**
 886       * Prepares links for the request.
 887       *
 888       * @since 4.7.0
 889       *
 890       * @param WP_Term $term Term object.
 891       * @return array Links for the given term.
 892       */
 893  	protected function prepare_links( $term ) {
 894          $base  = $this->namespace . '/' . $this->rest_base;
 895          $links = array(
 896              'self'       => array(
 897                  'href' => rest_url( trailingslashit( $base ) . $term->term_id ),
 898              ),
 899              'collection' => array(
 900                  'href' => rest_url( $base ),
 901              ),
 902              'about'      => array(
 903                  'href' => rest_url( sprintf( 'wp/v2/taxonomies/%s', $this->taxonomy ) ),
 904              ),
 905          );
 906  
 907          if ( $term->parent ) {
 908              $parent_term = get_term( (int) $term->parent, $term->taxonomy );
 909  
 910              if ( $parent_term ) {
 911                  $links['up'] = array(
 912                      'href'       => rest_url( trailingslashit( $base ) . $parent_term->term_id ),
 913                      'embeddable' => true,
 914                  );
 915              }
 916          }
 917  
 918          $taxonomy_obj = get_taxonomy( $term->taxonomy );
 919  
 920          if ( empty( $taxonomy_obj->object_type ) ) {
 921              return $links;
 922          }
 923  
 924          $post_type_links = array();
 925  
 926          foreach ( $taxonomy_obj->object_type as $type ) {
 927              $rest_path = rest_get_route_for_post_type_items( $type );
 928  
 929              if ( empty( $rest_path ) ) {
 930                  continue;
 931              }
 932  
 933              $post_type_links[] = array(
 934                  'href' => add_query_arg( $this->rest_base, $term->term_id, rest_url( $rest_path ) ),
 935              );
 936          }
 937  
 938          if ( ! empty( $post_type_links ) ) {
 939              $links['https://api.w.org/post_type'] = $post_type_links;
 940          }
 941  
 942          return $links;
 943      }
 944  
 945      /**
 946       * Retrieves the term's schema, conforming to JSON Schema.
 947       *
 948       * @since 4.7.0
 949       *
 950       * @return array Item schema data.
 951       */
 952  	public function get_item_schema() {
 953          if ( $this->schema ) {
 954              return $this->add_additional_fields_schema( $this->schema );
 955          }
 956  
 957          $schema = array(
 958              '$schema'    => 'http://json-schema.org/draft-04/schema#',
 959              'title'      => 'post_tag' === $this->taxonomy ? 'tag' : $this->taxonomy,
 960              'type'       => 'object',
 961              'properties' => array(
 962                  'id'          => array(
 963                      'description' => __( 'Unique identifier for the term.' ),
 964                      'type'        => 'integer',
 965                      'context'     => array( 'view', 'embed', 'edit' ),
 966                      'readonly'    => true,
 967                  ),
 968                  'count'       => array(
 969                      'description' => __( 'Number of published posts for the term.' ),
 970                      'type'        => 'integer',
 971                      'context'     => array( 'view', 'edit' ),
 972                      'readonly'    => true,
 973                  ),
 974                  'description' => array(
 975                      'description' => __( 'HTML description of the term.' ),
 976                      'type'        => 'string',
 977                      'context'     => array( 'view', 'edit' ),
 978                  ),
 979                  'link'        => array(
 980                      'description' => __( 'URL of the term.' ),
 981                      'type'        => 'string',
 982                      'format'      => 'uri',
 983                      'context'     => array( 'view', 'embed', 'edit' ),
 984                      'readonly'    => true,
 985                  ),
 986                  'name'        => array(
 987                      'description' => __( 'HTML title for the term.' ),
 988                      'type'        => 'string',
 989                      'context'     => array( 'view', 'embed', 'edit' ),
 990                      'arg_options' => array(
 991                          'sanitize_callback' => 'sanitize_text_field',
 992                      ),
 993                      'required'    => true,
 994                  ),
 995                  'slug'        => array(
 996                      'description' => __( 'An alphanumeric identifier for the term unique to its type.' ),
 997                      'type'        => 'string',
 998                      'context'     => array( 'view', 'embed', 'edit' ),
 999                      'arg_options' => array(
1000                          'sanitize_callback' => array( $this, 'sanitize_slug' ),
1001                      ),
1002                  ),
1003                  'taxonomy'    => array(
1004                      'description' => __( 'Type attribution for the term.' ),
1005                      'type'        => 'string',
1006                      'enum'        => array( $this->taxonomy ),
1007                      'context'     => array( 'view', 'embed', 'edit' ),
1008                      'readonly'    => true,
1009                  ),
1010              ),
1011          );
1012  
1013          $taxonomy = get_taxonomy( $this->taxonomy );
1014  
1015          if ( $taxonomy->hierarchical ) {
1016              $schema['properties']['parent'] = array(
1017                  'description' => __( 'The parent term ID.' ),
1018                  'type'        => 'integer',
1019                  'context'     => array( 'view', 'edit' ),
1020              );
1021          }
1022  
1023          $schema['properties']['meta'] = $this->meta->get_field_schema();
1024  
1025          $this->schema = $schema;
1026  
1027          return $this->add_additional_fields_schema( $this->schema );
1028      }
1029  
1030      /**
1031       * Retrieves the query params for collections.
1032       *
1033       * @since 4.7.0
1034       *
1035       * @return array Collection parameters.
1036       */
1037  	public function get_collection_params() {
1038          $query_params = parent::get_collection_params();
1039          $taxonomy     = get_taxonomy( $this->taxonomy );
1040  
1041          $query_params['context']['default'] = 'view';
1042  
1043          $query_params['exclude'] = array(
1044              'description' => __( 'Ensure result set excludes specific IDs.' ),
1045              'type'        => 'array',
1046              'items'       => array(
1047                  'type' => 'integer',
1048              ),
1049              'default'     => array(),
1050          );
1051  
1052          $query_params['include'] = array(
1053              'description' => __( 'Limit result set to specific IDs.' ),
1054              'type'        => 'array',
1055              'items'       => array(
1056                  'type' => 'integer',
1057              ),
1058              'default'     => array(),
1059          );
1060  
1061          if ( ! $taxonomy->hierarchical ) {
1062              $query_params['offset'] = array(
1063                  'description' => __( 'Offset the result set by a specific number of items.' ),
1064                  'type'        => 'integer',
1065              );
1066          }
1067  
1068          $query_params['order'] = array(
1069              'description' => __( 'Order sort attribute ascending or descending.' ),
1070              'type'        => 'string',
1071              'default'     => 'asc',
1072              'enum'        => array(
1073                  'asc',
1074                  'desc',
1075              ),
1076          );
1077  
1078          $query_params['orderby'] = array(
1079              'description' => __( 'Sort collection by term attribute.' ),
1080              'type'        => 'string',
1081              'default'     => 'name',
1082              'enum'        => array(
1083                  'id',
1084                  'include',
1085                  'name',
1086                  'slug',
1087                  'include_slugs',
1088                  'term_group',
1089                  'description',
1090                  'count',
1091              ),
1092          );
1093  
1094          $query_params['hide_empty'] = array(
1095              'description' => __( 'Whether to hide terms not assigned to any posts.' ),
1096              'type'        => 'boolean',
1097              'default'     => false,
1098          );
1099  
1100          if ( $taxonomy->hierarchical ) {
1101              $query_params['parent'] = array(
1102                  'description' => __( 'Limit result set to terms assigned to a specific parent.' ),
1103                  'type'        => 'integer',
1104              );
1105          }
1106  
1107          $query_params['post'] = array(
1108              'description' => __( 'Limit result set to terms assigned to a specific post.' ),
1109              'type'        => 'integer',
1110              'default'     => null,
1111          );
1112  
1113          $query_params['slug'] = array(
1114              'description' => __( 'Limit result set to terms with one or more specific slugs.' ),
1115              'type'        => 'array',
1116              'items'       => array(
1117                  'type' => 'string',
1118              ),
1119          );
1120  
1121          /**
1122           * Filters collection parameters for the terms controller.
1123           *
1124           * The dynamic part of the filter `$this->taxonomy` refers to the taxonomy
1125           * slug for the controller.
1126           *
1127           * This filter registers the collection parameter, but does not map the
1128           * collection parameter to an internal WP_Term_Query parameter.  Use the
1129           * `rest_{$this->taxonomy}_query` filter to set WP_Term_Query parameters.
1130           *
1131           * @since 4.7.0
1132           *
1133           * @param array       $query_params JSON Schema-formatted collection parameters.
1134           * @param WP_Taxonomy $taxonomy     Taxonomy object.
1135           */
1136          return apply_filters( "rest_{$this->taxonomy}_collection_params", $query_params, $taxonomy );
1137      }
1138  
1139      /**
1140       * Checks that the taxonomy is valid.
1141       *
1142       * @since 4.7.0
1143       *
1144       * @param string $taxonomy Taxonomy to check.
1145       * @return bool Whether the taxonomy is allowed for REST management.
1146       */
1147  	protected function check_is_taxonomy_allowed( $taxonomy ) {
1148          $taxonomy_obj = get_taxonomy( $taxonomy );
1149          if ( $taxonomy_obj && ! empty( $taxonomy_obj->show_in_rest ) ) {
1150              return true;
1151          }
1152          return false;
1153      }
1154  }


Generated: Thu Nov 21 01:00:03 2024 Cross-referenced by PHPXref 0.7.1