[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

title

Body

[close]

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

   1  <?php
   2  /**
   3   * REST API: WP_REST_Search_Controller class
   4   *
   5   * @package WordPress
   6   * @subpackage REST_API
   7   * @since 5.0.0
   8   */
   9  
  10  /**
  11   * Core class to search through all WordPress content via the REST API.
  12   *
  13   * @since 5.0.0
  14   *
  15   * @see WP_REST_Controller
  16   */
  17  class WP_REST_Search_Controller extends WP_REST_Controller {
  18  
  19      /**
  20       * ID property name.
  21       */
  22      const PROP_ID = 'id';
  23  
  24      /**
  25       * Title property name.
  26       */
  27      const PROP_TITLE = 'title';
  28  
  29      /**
  30       * URL property name.
  31       */
  32      const PROP_URL = 'url';
  33  
  34      /**
  35       * Type property name.
  36       */
  37      const PROP_TYPE = 'type';
  38  
  39      /**
  40       * Subtype property name.
  41       */
  42      const PROP_SUBTYPE = 'subtype';
  43  
  44      /**
  45       * Identifier for the 'any' type.
  46       */
  47      const TYPE_ANY = 'any';
  48  
  49      /**
  50       * Search handlers used by the controller.
  51       *
  52       * @since 5.0.0
  53       * @var array
  54       */
  55      protected $search_handlers = array();
  56  
  57      /**
  58       * Constructor.
  59       *
  60       * @since 5.0.0
  61       *
  62       * @param array $search_handlers List of search handlers to use in the controller. Each search
  63       *                               handler instance must extend the `WP_REST_Search_Handler` class.
  64       */
  65  	public function __construct( array $search_handlers ) {
  66          $this->namespace = 'wp/v2';
  67          $this->rest_base = 'search';
  68  
  69          foreach ( $search_handlers as $search_handler ) {
  70              if ( ! $search_handler instanceof WP_REST_Search_Handler ) {
  71  
  72                  /* translators: %s: PHP class name */
  73                  _doing_it_wrong( __METHOD__, sprintf( __( 'REST search handlers must extend the %s class.' ), 'WP_REST_Search_Handler' ), '5.0.0' );
  74                  continue;
  75              }
  76  
  77              $this->search_handlers[ $search_handler->get_type() ] = $search_handler;
  78          }
  79      }
  80  
  81      /**
  82       * Registers the routes for the objects of the controller.
  83       *
  84       * @since 5.0.0
  85       *
  86       * @see register_rest_route()
  87       */
  88  	public function register_routes() {
  89          register_rest_route(
  90              $this->namespace,
  91              '/' . $this->rest_base,
  92              array(
  93                  array(
  94                      'methods'             => WP_REST_Server::READABLE,
  95                      'callback'            => array( $this, 'get_items' ),
  96                      'permission_callback' => array( $this, 'get_items_permission_check' ),
  97                      'args'                => $this->get_collection_params(),
  98                  ),
  99                  'schema' => array( $this, 'get_public_item_schema' ),
 100              )
 101          );
 102      }
 103  
 104      /**
 105       * Checks if a given request has access to search content.
 106       *
 107       * @since 5.0.0
 108       *
 109       * @param WP_REST_Request $request Full details about the request.
 110       * @return true|WP_Error True if the request has search access, WP_Error object otherwise.
 111       */
 112  	public function get_items_permission_check( $request ) {
 113          return true;
 114      }
 115  
 116      /**
 117       * Retrieves a collection of search results.
 118       *
 119       * @since 5.0.0
 120       *
 121       * @param WP_REST_Request $request Full details about the request.
 122       * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
 123       */
 124  	public function get_items( $request ) {
 125          $handler = $this->get_search_handler( $request );
 126          if ( is_wp_error( $handler ) ) {
 127              return $handler;
 128          }
 129  
 130          $result = $handler->search_items( $request );
 131  
 132          if ( ! isset( $result[ WP_REST_Search_Handler::RESULT_IDS ] ) || ! is_array( $result[ WP_REST_Search_Handler::RESULT_IDS ] ) || ! isset( $result[ WP_REST_Search_Handler::RESULT_TOTAL ] ) ) {
 133              return new WP_Error( 'rest_search_handler_error', __( 'Internal search handler error.' ), array( 'status' => 500 ) );
 134          }
 135  
 136          $ids = array_map( 'absint', $result[ WP_REST_Search_Handler::RESULT_IDS ] );
 137  
 138          $results = array();
 139          foreach ( $ids as $id ) {
 140              $data      = $this->prepare_item_for_response( $id, $request );
 141              $results[] = $this->prepare_response_for_collection( $data );
 142          }
 143  
 144          $total     = (int) $result[ WP_REST_Search_Handler::RESULT_TOTAL ];
 145          $page      = (int) $request['page'];
 146          $per_page  = (int) $request['per_page'];
 147          $max_pages = ceil( $total / $per_page );
 148  
 149          if ( $page > $max_pages && $total > 0 ) {
 150              return new WP_Error( 'rest_search_invalid_page_number', __( 'The page number requested is larger than the number of pages available.' ), array( 'status' => 400 ) );
 151          }
 152  
 153          $response = rest_ensure_response( $results );
 154          $response->header( 'X-WP-Total', $total );
 155          $response->header( 'X-WP-TotalPages', $max_pages );
 156  
 157          $request_params = $request->get_query_params();
 158          $base           = add_query_arg( urlencode_deep( $request_params ), rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ) );
 159  
 160          if ( $page > 1 ) {
 161              $prev_link = add_query_arg( 'page', $page - 1, $base );
 162              $response->link_header( 'prev', $prev_link );
 163          }
 164          if ( $page < $max_pages ) {
 165              $next_link = add_query_arg( 'page', $page + 1, $base );
 166              $response->link_header( 'next', $next_link );
 167          }
 168  
 169          return $response;
 170      }
 171  
 172      /**
 173       * Prepares a single search result for response.
 174       *
 175       * @since 5.0.0
 176       *
 177       * @param int             $id      ID of the item to prepare.
 178       * @param WP_REST_Request $request Request object.
 179       * @return WP_REST_Response Response object.
 180       */
 181  	public function prepare_item_for_response( $id, $request ) {
 182          $handler = $this->get_search_handler( $request );
 183          if ( is_wp_error( $handler ) ) {
 184              return new WP_REST_Response();
 185          }
 186  
 187          $fields = $this->get_fields_for_response( $request );
 188  
 189          $data = $handler->prepare_item( $id, $fields );
 190          $data = $this->add_additional_fields_to_object( $data, $request );
 191  
 192          $context = ! empty( $request['context'] ) ? $request['context'] : 'view';
 193          $data    = $this->filter_response_by_context( $data, $context );
 194  
 195          $response = rest_ensure_response( $data );
 196  
 197          $links               = $handler->prepare_item_links( $id );
 198          $links['collection'] = array(
 199              'href' => rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ),
 200          );
 201          $response->add_links( $links );
 202  
 203          return $response;
 204      }
 205  
 206      /**
 207       * Retrieves the item schema, conforming to JSON Schema.
 208       *
 209       * @since 5.0.0
 210       *
 211       * @return array Item schema data.
 212       */
 213  	public function get_item_schema() {
 214          $types    = array();
 215          $subtypes = array();
 216          foreach ( $this->search_handlers as $search_handler ) {
 217              $types[]  = $search_handler->get_type();
 218              $subtypes = array_merge( $subtypes, $search_handler->get_subtypes() );
 219          }
 220  
 221          $types    = array_unique( $types );
 222          $subtypes = array_unique( $subtypes );
 223  
 224          $schema = array(
 225              '$schema'    => 'http://json-schema.org/draft-04/schema#',
 226              'title'      => 'search-result',
 227              'type'       => 'object',
 228              'properties' => array(
 229                  self::PROP_ID      => array(
 230                      'description' => __( 'Unique identifier for the object.' ),
 231                      'type'        => 'integer',
 232                      'context'     => array( 'view', 'embed' ),
 233                      'readonly'    => true,
 234                  ),
 235                  self::PROP_TITLE   => array(
 236                      'description' => __( 'The title for the object.' ),
 237                      'type'        => 'string',
 238                      'context'     => array( 'view', 'embed' ),
 239                      'readonly'    => true,
 240                  ),
 241                  self::PROP_URL     => array(
 242                      'description' => __( 'URL to the object.' ),
 243                      'type'        => 'string',
 244                      'format'      => 'uri',
 245                      'context'     => array( 'view', 'embed' ),
 246                      'readonly'    => true,
 247                  ),
 248                  self::PROP_TYPE    => array(
 249                      'description' => __( 'Object type.' ),
 250                      'type'        => 'string',
 251                      'enum'        => $types,
 252                      'context'     => array( 'view', 'embed' ),
 253                      'readonly'    => true,
 254                  ),
 255                  self::PROP_SUBTYPE => array(
 256                      'description' => __( 'Object subtype.' ),
 257                      'type'        => 'string',
 258                      'enum'        => $subtypes,
 259                      'context'     => array( 'view', 'embed' ),
 260                      'readonly'    => true,
 261                  ),
 262              ),
 263          );
 264  
 265          return $this->add_additional_fields_schema( $schema );
 266      }
 267  
 268      /**
 269       * Retrieves the query params for the search results collection.
 270       *
 271       * @since 5.0.0
 272       *
 273       * @return array Collection parameters.
 274       */
 275  	public function get_collection_params() {
 276          $types    = array();
 277          $subtypes = array();
 278          foreach ( $this->search_handlers as $search_handler ) {
 279              $types[]  = $search_handler->get_type();
 280              $subtypes = array_merge( $subtypes, $search_handler->get_subtypes() );
 281          }
 282  
 283          $types    = array_unique( $types );
 284          $subtypes = array_unique( $subtypes );
 285  
 286          $query_params = parent::get_collection_params();
 287  
 288          $query_params['context']['default'] = 'view';
 289  
 290          $query_params[ self::PROP_TYPE ] = array(
 291              'default'     => $types[0],
 292              'description' => __( 'Limit results to items of an object type.' ),
 293              'type'        => 'string',
 294              'enum'        => $types,
 295          );
 296  
 297          $query_params[ self::PROP_SUBTYPE ] = array(
 298              'default'           => self::TYPE_ANY,
 299              'description'       => __( 'Limit results to items of one or more object subtypes.' ),
 300              'type'              => 'array',
 301              'items'             => array(
 302                  'enum' => array_merge( $subtypes, array( self::TYPE_ANY ) ),
 303                  'type' => 'string',
 304              ),
 305              'sanitize_callback' => array( $this, 'sanitize_subtypes' ),
 306          );
 307  
 308          return $query_params;
 309      }
 310  
 311      /**
 312       * Sanitizes the list of subtypes, to ensure only subtypes of the passed type are included.
 313       *
 314       * @since 5.0.0
 315       *
 316       * @param string|array    $subtypes  One or more subtypes.
 317       * @param WP_REST_Request $request   Full details about the request.
 318       * @param string          $parameter Parameter name.
 319       * @return array|WP_Error List of valid subtypes, or WP_Error object on failure.
 320       */
 321  	public function sanitize_subtypes( $subtypes, $request, $parameter ) {
 322          $subtypes = wp_parse_slug_list( $subtypes );
 323  
 324          $subtypes = rest_parse_request_arg( $subtypes, $request, $parameter );
 325          if ( is_wp_error( $subtypes ) ) {
 326              return $subtypes;
 327          }
 328  
 329          // 'any' overrides any other subtype.
 330          if ( in_array( self::TYPE_ANY, $subtypes, true ) ) {
 331              return array( self::TYPE_ANY );
 332          }
 333  
 334          $handler = $this->get_search_handler( $request );
 335          if ( is_wp_error( $handler ) ) {
 336              return $handler;
 337          }
 338  
 339          return array_intersect( $subtypes, $handler->get_subtypes() );
 340      }
 341  
 342      /**
 343       * Gets the search handler to handle the current request.
 344       *
 345       * @since 5.0.0
 346       *
 347       * @param WP_REST_Request $request Full details about the request.
 348       * @return WP_REST_Search_Handler|WP_Error Search handler for the request type, or WP_Error object on failure.
 349       */
 350  	protected function get_search_handler( $request ) {
 351          $type = $request->get_param( self::PROP_TYPE );
 352  
 353          if ( ! $type || ! isset( $this->search_handlers[ $type ] ) ) {
 354              return new WP_Error( 'rest_search_invalid_type', __( 'Invalid type parameter.' ), array( 'status' => 400 ) );
 355          }
 356  
 357          return $this->search_handlers[ $type ];
 358      }
 359  }


Generated: Mon Jun 17 08:20:02 2019 Cross-referenced by PHPXref 0.7