[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

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


Generated : Wed Apr 1 08:20:01 2020 Cross-referenced by PHPXref