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


Generated: Sat Sep 21 01:00:03 2019 Cross-referenced by PHPXref 0.7.1