WP_REST_Request

Core class used to implement a REST request object.

Defined (1)

The class is defined in the following location(s).

/wp-includes/rest-api/class-wp-rest-request.php  
  1. class WP_REST_Request implements ArrayAccess { 
  2.  
  3. /** 
  4. * HTTP method. 
  5. * @since 4.4.0 
  6. * @access protected 
  7. * @var string 
  8. */ 
  9. protected $method = ''; 
  10.  
  11. /** 
  12. * Parameters passed to the request. 
  13. * These typically come from the `$_GET`, `$_POST` and `$_FILES` 
  14. * superglobals when being created from the global scope. 
  15. * @since 4.4.0 
  16. * @access protected 
  17. * @var array Contains GET, POST and FILES keys mapping to arrays of data. 
  18. */ 
  19. protected $params; 
  20.  
  21. /** 
  22. * HTTP headers for the request. 
  23. * @since 4.4.0 
  24. * @access protected 
  25. * @var array Map of key to value. Key is always lowercase, as per HTTP specification. 
  26. */ 
  27. protected $headers = array(); 
  28.  
  29. /** 
  30. * Body data. 
  31. * @since 4.4.0 
  32. * @access protected 
  33. * @var string Binary data from the request. 
  34. */ 
  35. protected $body = null; 
  36.  
  37. /** 
  38. * Route matched for the request. 
  39. * @since 4.4.0 
  40. * @access protected 
  41. * @var string 
  42. */ 
  43. protected $route; 
  44.  
  45. /** 
  46. * Attributes (options) for the route that was matched. 
  47. * This is the options array used when the route was registered, typically 
  48. * containing the callback as well as the valid methods for the route. 
  49. * @since 4.4.0 
  50. * @access protected 
  51. * @var array Attributes for the request. 
  52. */ 
  53. protected $attributes = array(); 
  54.  
  55. /** 
  56. * Used to determine if the JSON data has been parsed yet. 
  57. * Allows lazy-parsing of JSON data where possible. 
  58. * @since 4.4.0 
  59. * @access protected 
  60. * @var bool 
  61. */ 
  62. protected $parsed_json = false; 
  63.  
  64. /** 
  65. * Used to determine if the body data has been parsed yet. 
  66. * @since 4.4.0 
  67. * @access protected 
  68. * @var bool 
  69. */ 
  70. protected $parsed_body = false; 
  71.  
  72. /** 
  73. * Constructor. 
  74. * @since 4.4.0 
  75. * @access public 
  76. * @param string $method Optional. Request method. Default empty. 
  77. * @param string $route Optional. Request route. Default empty. 
  78. * @param array $attributes Optional. Request attributes. Default empty array. 
  79. */ 
  80. public function __construct( $method = '', $route = '', $attributes = array() ) { 
  81. $this->params = array( 
  82. 'URL' => array(),  
  83. 'GET' => array(),  
  84. 'POST' => array(),  
  85. 'FILES' => array(),  
  86.  
  87. // See parse_json_params. 
  88. 'JSON' => null,  
  89.  
  90. 'defaults' => array(),  
  91. ); 
  92.  
  93. $this->set_method( $method ); 
  94. $this->set_route( $route ); 
  95. $this->set_attributes( $attributes ); 
  96.  
  97. /** 
  98. * Retrieves the HTTP method for the request. 
  99. * @since 4.4.0 
  100. * @access public 
  101. * @return string HTTP method. 
  102. */ 
  103. public function get_method() { 
  104. return $this->method; 
  105.  
  106. /** 
  107. * Sets HTTP method for the request. 
  108. * @since 4.4.0 
  109. * @access public 
  110. * @param string $method HTTP method. 
  111. */ 
  112. public function set_method( $method ) { 
  113. $this->method = strtoupper( $method ); 
  114.  
  115. /** 
  116. * Retrieves all headers from the request. 
  117. * @since 4.4.0 
  118. * @access public 
  119. * @return array Map of key to value. Key is always lowercase, as per HTTP specification. 
  120. */ 
  121. public function get_headers() { 
  122. return $this->headers; 
  123.  
  124. /** 
  125. * Canonicalizes the header name. 
  126. * Ensures that header names are always treated the same regardless of 
  127. * source. Header names are always case insensitive. 
  128. * Note that we treat `-` (dashes) and `_` (underscores) as the same 
  129. * character, as per header parsing rules in both Apache and nginx. 
  130. * @link http://stackoverflow.com/q/18185366 
  131. * @link http://wiki.nginx.org/Pitfalls#Missing_.28disappearing.29_HTTP_headers 
  132. * @link https://nginx.org/en/docs/http/ngx_http_core_module.html#underscores_in_headers 
  133. * @since 4.4.0 
  134. * @access public 
  135. * @static 
  136. * @param string $key Header name. 
  137. * @return string Canonicalized name. 
  138. */ 
  139. public static function canonicalize_header_name( $key ) { 
  140. $key = strtolower( $key ); 
  141. $key = str_replace( '-', '_', $key ); 
  142.  
  143. return $key; 
  144.  
  145. /** 
  146. * Retrieves the given header from the request. 
  147. * If the header has multiple values, they will be concatenated with a comma 
  148. * as per the HTTP specification. Be aware that some non-compliant headers 
  149. * (notably cookie headers) cannot be joined this way. 
  150. * @since 4.4.0 
  151. * @access public 
  152. * @param string $key Header name, will be canonicalized to lowercase. 
  153. * @return string|null String value if set, null otherwise. 
  154. */ 
  155. public function get_header( $key ) { 
  156. $key = $this->canonicalize_header_name( $key ); 
  157.  
  158. if ( ! isset( $this->headers[ $key ] ) ) { 
  159. return null; 
  160.  
  161. return implode( ', ', $this->headers[ $key ] ); 
  162.  
  163. /** 
  164. * Retrieves header values from the request. 
  165. * @since 4.4.0 
  166. * @access public 
  167. * @param string $key Header name, will be canonicalized to lowercase. 
  168. * @return array|null List of string values if set, null otherwise. 
  169. */ 
  170. public function get_header_as_array( $key ) { 
  171. $key = $this->canonicalize_header_name( $key ); 
  172.  
  173. if ( ! isset( $this->headers[ $key ] ) ) { 
  174. return null; 
  175.  
  176. return $this->headers[ $key ]; 
  177.  
  178. /** 
  179. * Sets the header on request. 
  180. * @since 4.4.0 
  181. * @access public 
  182. * @param string $key Header name. 
  183. * @param string $value Header value, or list of values. 
  184. */ 
  185. public function set_header( $key, $value ) { 
  186. $key = $this->canonicalize_header_name( $key ); 
  187. $value = (array) $value; 
  188.  
  189. $this->headers[ $key ] = $value; 
  190.  
  191. /** 
  192. * Appends a header value for the given header. 
  193. * @since 4.4.0 
  194. * @access public 
  195. * @param string $key Header name. 
  196. * @param string $value Header value, or list of values. 
  197. */ 
  198. public function add_header( $key, $value ) { 
  199. $key = $this->canonicalize_header_name( $key ); 
  200. $value = (array) $value; 
  201.  
  202. if ( ! isset( $this->headers[ $key ] ) ) { 
  203. $this->headers[ $key ] = array(); 
  204.  
  205. $this->headers[ $key ] = array_merge( $this->headers[ $key ], $value ); 
  206.  
  207. /** 
  208. * Removes all values for a header. 
  209. * @since 4.4.0 
  210. * @access public 
  211. * @param string $key Header name. 
  212. */ 
  213. public function remove_header( $key ) { 
  214. unset( $this->headers[ $key ] ); 
  215.  
  216. /** 
  217. * Sets headers on the request. 
  218. * @since 4.4.0 
  219. * @access public 
  220. * @param array $headers Map of header name to value. 
  221. * @param bool $override If true, replace the request's headers. Otherwise, merge with existing. 
  222. */ 
  223. public function set_headers( $headers, $override = true ) { 
  224. if ( true === $override ) { 
  225. $this->headers = array(); 
  226.  
  227. foreach ( $headers as $key => $value ) { 
  228. $this->set_header( $key, $value ); 
  229.  
  230. /** 
  231. * Retrieves the content-type of the request. 
  232. * @since 4.4.0 
  233. * @access public 
  234. * @return array Map containing 'value' and 'parameters' keys. 
  235. */ 
  236. public function get_content_type() { 
  237. $value = $this->get_header( 'content-type' ); 
  238. if ( empty( $value ) ) { 
  239. return null; 
  240.  
  241. $parameters = ''; 
  242. if ( strpos( $value, ';' ) ) { 
  243. list( $value, $parameters ) = explode( ';', $value, 2 ); 
  244.  
  245. $value = strtolower( $value ); 
  246. if ( strpos( $value, '/' ) === false ) { 
  247. return null; 
  248.  
  249. // Parse type and subtype out. 
  250. list( $type, $subtype ) = explode( '/', $value, 2 ); 
  251.  
  252. $data = compact( 'value', 'type', 'subtype', 'parameters' ); 
  253. $data = array_map( 'trim', $data ); 
  254.  
  255. return $data; 
  256.  
  257. /** 
  258. * Retrieves the parameter priority order. 
  259. * Used when checking parameters in get_param(). 
  260. * @since 4.4.0 
  261. * @access protected 
  262. * @return array List of types to check, in order of priority. 
  263. */ 
  264. protected function get_parameter_order() { 
  265. $order = array(); 
  266. $order[] = 'JSON'; 
  267.  
  268. $this->parse_json_params(); 
  269.  
  270. // Ensure we parse the body data. 
  271. $body = $this->get_body(); 
  272.  
  273. if ( 'POST' !== $this->method && ! empty( $body ) ) { 
  274. $this->parse_body_params(); 
  275.  
  276. $accepts_body_data = array( 'POST', 'PUT', 'PATCH', 'DELETE' ); 
  277. if ( in_array( $this->method, $accepts_body_data ) ) { 
  278. $order[] = 'POST'; 
  279.  
  280. $order[] = 'GET'; 
  281. $order[] = 'URL'; 
  282. $order[] = 'defaults'; 
  283.  
  284. /** 
  285. * Filters the parameter order. 
  286. * The order affects which parameters are checked when using get_param() and family. 
  287. * This acts similarly to PHP's `request_order` setting. 
  288. * @since 4.4.0 
  289. * @param array $order { 
  290. * An array of types to check, in order of priority. 
  291. * @param string $type The type to check. 
  292. * } 
  293. * @param WP_REST_Request $this The request object. 
  294. */ 
  295. return apply_filters( 'rest_request_parameter_order', $order, $this ); 
  296.  
  297. /** 
  298. * Retrieves a parameter from the request. 
  299. * @since 4.4.0 
  300. * @access public 
  301. * @param string $key Parameter name. 
  302. * @return mixed|null Value if set, null otherwise. 
  303. */ 
  304. public function get_param( $key ) { 
  305. $order = $this->get_parameter_order(); 
  306.  
  307. foreach ( $order as $type ) { 
  308. // Determine if we have the parameter for this type. 
  309. if ( isset( $this->params[ $type ][ $key ] ) ) { 
  310. return $this->params[ $type ][ $key ]; 
  311.  
  312. return null; 
  313.  
  314. /** 
  315. * Sets a parameter on the request. 
  316. * @since 4.4.0 
  317. * @access public 
  318. * @param string $key Parameter name. 
  319. * @param mixed $value Parameter value. 
  320. */ 
  321. public function set_param( $key, $value ) { 
  322. switch ( $this->method ) { 
  323. case 'POST': 
  324. $this->params['POST'][ $key ] = $value; 
  325. break; 
  326.  
  327. default: 
  328. $this->params['GET'][ $key ] = $value; 
  329. break; 
  330.  
  331. /** 
  332. * Retrieves merged parameters from the request. 
  333. * The equivalent of get_param(), but returns all parameters for the request. 
  334. * Handles merging all the available values into a single array. 
  335. * @since 4.4.0 
  336. * @access public 
  337. * @return array Map of key to value. 
  338. */ 
  339. public function get_params() { 
  340. $order = $this->get_parameter_order(); 
  341. $order = array_reverse( $order, true ); 
  342.  
  343. $params = array(); 
  344. foreach ( $order as $type ) { 
  345. // array_merge / the "+" operator will mess up 
  346. // numeric keys, so instead do a manual foreach. 
  347. foreach ( (array) $this->params[ $type ] as $key => $value ) { 
  348. $params[ $key ] = $value; 
  349.  
  350. return $params; 
  351.  
  352. /** 
  353. * Retrieves parameters from the route itself. 
  354. * These are parsed from the URL using the regex. 
  355. * @since 4.4.0 
  356. * @access public 
  357. * @return array Parameter map of key to value. 
  358. */ 
  359. public function get_url_params() { 
  360. return $this->params['URL']; 
  361.  
  362. /** 
  363. * Sets parameters from the route. 
  364. * Typically, this is set after parsing the URL. 
  365. * @since 4.4.0 
  366. * @access public 
  367. * @param array $params Parameter map of key to value. 
  368. */ 
  369. public function set_url_params( $params ) { 
  370. $this->params['URL'] = $params; 
  371.  
  372. /** 
  373. * Retrieves parameters from the query string. 
  374. * These are the parameters you'd typically find in `$_GET`. 
  375. * @since 4.4.0 
  376. * @access public 
  377. * @return array Parameter map of key to value 
  378. */ 
  379. public function get_query_params() { 
  380. return $this->params['GET']; 
  381.  
  382. /** 
  383. * Sets parameters from the query string. 
  384. * Typically, this is set from `$_GET`. 
  385. * @since 4.4.0 
  386. * @access public 
  387. * @param array $params Parameter map of key to value. 
  388. */ 
  389. public function set_query_params( $params ) { 
  390. $this->params['GET'] = $params; 
  391.  
  392. /** 
  393. * Retrieves parameters from the body. 
  394. * These are the parameters you'd typically find in `$_POST`. 
  395. * @since 4.4.0 
  396. * @access public 
  397. * @return array Parameter map of key to value. 
  398. */ 
  399. public function get_body_params() { 
  400. return $this->params['POST']; 
  401.  
  402. /** 
  403. * Sets parameters from the body. 
  404. * Typically, this is set from `$_POST`. 
  405. * @since 4.4.0 
  406. * @access public 
  407. * @param array $params Parameter map of key to value. 
  408. */ 
  409. public function set_body_params( $params ) { 
  410. $this->params['POST'] = $params; 
  411.  
  412. /** 
  413. * Retrieves multipart file parameters from the body. 
  414. * These are the parameters you'd typically find in `$_FILES`. 
  415. * @since 4.4.0 
  416. * @access public 
  417. * @return array Parameter map of key to value 
  418. */ 
  419. public function get_file_params() { 
  420. return $this->params['FILES']; 
  421.  
  422. /** 
  423. * Sets multipart file parameters from the body. 
  424. * Typically, this is set from `$_FILES`. 
  425. * @since 4.4.0 
  426. * @access public 
  427. * @param array $params Parameter map of key to value. 
  428. */ 
  429. public function set_file_params( $params ) { 
  430. $this->params['FILES'] = $params; 
  431.  
  432. /** 
  433. * Retrieves the default parameters. 
  434. * These are the parameters set in the route registration. 
  435. * @since 4.4.0 
  436. * @access public 
  437. * @return array Parameter map of key to value 
  438. */ 
  439. public function get_default_params() { 
  440. return $this->params['defaults']; 
  441.  
  442. /** 
  443. * Sets default parameters. 
  444. * These are the parameters set in the route registration. 
  445. * @since 4.4.0 
  446. * @access public 
  447. * @param array $params Parameter map of key to value. 
  448. */ 
  449. public function set_default_params( $params ) { 
  450. $this->params['defaults'] = $params; 
  451.  
  452. /** 
  453. * Retrieves the request body content. 
  454. * @since 4.4.0 
  455. * @access public 
  456. * @return string Binary data from the request body. 
  457. */ 
  458. public function get_body() { 
  459. return $this->body; 
  460.  
  461. /** 
  462. * Sets body content. 
  463. * @since 4.4.0 
  464. * @access public 
  465. * @param string $data Binary data from the request body. 
  466. */ 
  467. public function set_body( $data ) { 
  468. $this->body = $data; 
  469.  
  470. // Enable lazy parsing. 
  471. $this->parsed_json = false; 
  472. $this->parsed_body = false; 
  473. $this->params['JSON'] = null; 
  474.  
  475. /** 
  476. * Retrieves the parameters from a JSON-formatted body. 
  477. * @since 4.4.0 
  478. * @access public 
  479. * @return array Parameter map of key to value. 
  480. */ 
  481. public function get_json_params() { 
  482. // Ensure the parameters have been parsed out. 
  483. $this->parse_json_params(); 
  484.  
  485. return $this->params['JSON']; 
  486.  
  487. /** 
  488. * Parses the JSON parameters. 
  489. * Avoids parsing the JSON data until we need to access it. 
  490. * @since 4.4.0 
  491. * @since 4.7.0 Returns error instance if value cannot be decoded. 
  492. * @access protected 
  493. * @return true|WP_Error True if the JSON data was passed or no JSON data was provided, WP_Error if invalid JSON was passed. 
  494. */ 
  495. protected function parse_json_params() { 
  496. if ( $this->parsed_json ) { 
  497. return true; 
  498.  
  499. $this->parsed_json = true; 
  500.  
  501. // Check that we actually got JSON. 
  502. $content_type = $this->get_content_type(); 
  503.  
  504. if ( empty( $content_type ) || 'application/json' !== $content_type['value'] ) { 
  505. return true; 
  506.  
  507. $body = $this->get_body(); 
  508. if ( empty( $body ) ) { 
  509. return true; 
  510.  
  511. $params = json_decode( $body, true ); 
  512.  
  513. /** 
  514. * Check for a parsing error. 
  515. * Note that due to WP's JSON compatibility functions, json_last_error 
  516. * might not be defined: https://core.trac.wordpress.org/ticket/27799 
  517. */ 
  518. if ( null === $params && ( ! function_exists( 'json_last_error' ) || JSON_ERROR_NONE !== json_last_error() ) ) { 
  519. // Ensure subsequent calls receive error instance. 
  520. $this->parsed_json = false; 
  521.  
  522. $error_data = array( 
  523. 'status' => WP_Http::BAD_REQUEST,  
  524. ); 
  525. if ( function_exists( 'json_last_error' ) ) { 
  526. $error_data['json_error_code'] = json_last_error(); 
  527. $error_data['json_error_message'] = json_last_error_msg(); 
  528.  
  529. return new WP_Error( 'rest_invalid_json', __( 'Invalid JSON body passed.' ), $error_data ); 
  530.  
  531. $this->params['JSON'] = $params; 
  532. return true; 
  533.  
  534. /** 
  535. * Parses the request body parameters. 
  536. * Parses out URL-encoded bodies for request methods that aren't supported 
  537. * natively by PHP. In PHP 5.x, only POST has these parsed automatically. 
  538. * @since 4.4.0 
  539. * @access protected 
  540. */ 
  541. protected function parse_body_params() { 
  542. if ( $this->parsed_body ) { 
  543. return; 
  544.  
  545. $this->parsed_body = true; 
  546.  
  547. /** 
  548. * Check that we got URL-encoded. Treat a missing content-type as 
  549. * URL-encoded for maximum compatibility. 
  550. */ 
  551. $content_type = $this->get_content_type(); 
  552.  
  553. if ( ! empty( $content_type ) && 'application/x-www-form-urlencoded' !== $content_type['value'] ) { 
  554. return; 
  555.  
  556. parse_str( $this->get_body(), $params ); 
  557.  
  558. /** 
  559. * Amazingly, parse_str follows magic quote rules. Sigh. 
  560. * NOTE: Do not refactor to use `wp_unslash`. 
  561. */ 
  562. if ( get_magic_quotes_gpc() ) { 
  563. $params = stripslashes_deep( $params ); 
  564.  
  565. /** 
  566. * Add to the POST parameters stored internally. If a user has already 
  567. * set these manually (via `set_body_params`), don't override them. 
  568. */ 
  569. $this->params['POST'] = array_merge( $params, $this->params['POST'] ); 
  570.  
  571. /** 
  572. * Retrieves the route that matched the request. 
  573. * @since 4.4.0 
  574. * @access public 
  575. * @return string Route matching regex. 
  576. */ 
  577. public function get_route() { 
  578. return $this->route; 
  579.  
  580. /** 
  581. * Sets the route that matched the request. 
  582. * @since 4.4.0 
  583. * @access public 
  584. * @param string $route Route matching regex. 
  585. */ 
  586. public function set_route( $route ) { 
  587. $this->route = $route; 
  588.  
  589. /** 
  590. * Retrieves the attributes for the request. 
  591. * These are the options for the route that was matched. 
  592. * @since 4.4.0 
  593. * @access public 
  594. * @return array Attributes for the request. 
  595. */ 
  596. public function get_attributes() { 
  597. return $this->attributes; 
  598.  
  599. /** 
  600. * Sets the attributes for the request. 
  601. * @since 4.4.0 
  602. * @access public 
  603. * @param array $attributes Attributes for the request. 
  604. */ 
  605. public function set_attributes( $attributes ) { 
  606. $this->attributes = $attributes; 
  607.  
  608. /** 
  609. * Sanitizes (where possible) the params on the request. 
  610. * This is primarily based off the sanitize_callback param on each registered 
  611. * argument. 
  612. * @since 4.4.0 
  613. * @access public 
  614. * @return true|WP_Error True if parameters were sanitized, WP_Error if an error occurred during sanitization. 
  615. */ 
  616. public function sanitize_params() { 
  617. $attributes = $this->get_attributes(); 
  618.  
  619. // No arguments set, skip sanitizing. 
  620. if ( empty( $attributes['args'] ) ) { 
  621. return true; 
  622.  
  623. $order = $this->get_parameter_order(); 
  624.  
  625. $invalid_params = array(); 
  626.  
  627. foreach ( $order as $type ) { 
  628. if ( empty( $this->params[ $type ] ) ) { 
  629. continue; 
  630. foreach ( $this->params[ $type ] as $key => $value ) { 
  631. if ( ! isset( $attributes['args'][ $key ] ) ) { 
  632. continue; 
  633. $param_args = $attributes['args'][ $key ]; 
  634.  
  635. // If the arg has a type but no sanitize_callback attribute, default to rest_parse_request_arg. 
  636. if ( ! array_key_exists( 'sanitize_callback', $param_args ) && ! empty( $param_args['type'] ) ) { 
  637. $param_args['sanitize_callback'] = 'rest_parse_request_arg'; 
  638. // If there's still no sanitize_callback, nothing to do here. 
  639. if ( empty( $param_args['sanitize_callback'] ) ) { 
  640. continue; 
  641.  
  642. $sanitized_value = call_user_func( $param_args['sanitize_callback'], $value, $this, $key ); 
  643.  
  644. if ( is_wp_error( $sanitized_value ) ) { 
  645. $invalid_params[ $key ] = $sanitized_value->get_error_message(); 
  646. } else { 
  647. $this->params[ $type ][ $key ] = $sanitized_value; 
  648.  
  649. if ( $invalid_params ) { 
  650. return new WP_Error( 'rest_invalid_param', sprintf( __( 'Invalid parameter(s): %s' ), implode( ', ', array_keys( $invalid_params ) ) ), array( 'status' => 400, 'params' => $invalid_params ) ); 
  651.  
  652. return true; 
  653.  
  654. /** 
  655. * Checks whether this request is valid according to its attributes. 
  656. * @since 4.4.0 
  657. * @access public 
  658. * @return bool|WP_Error True if there are no parameters to validate or if all pass validation,  
  659. * WP_Error if required parameters are missing. 
  660. */ 
  661. public function has_valid_params() { 
  662. // If JSON data was passed, check for errors. 
  663. $json_error = $this->parse_json_params(); 
  664. if ( is_wp_error( $json_error ) ) { 
  665. return $json_error; 
  666.  
  667. $attributes = $this->get_attributes(); 
  668. $required = array(); 
  669.  
  670. // No arguments set, skip validation. 
  671. if ( empty( $attributes['args'] ) ) { 
  672. return true; 
  673.  
  674. foreach ( $attributes['args'] as $key => $arg ) { 
  675.  
  676. $param = $this->get_param( $key ); 
  677. if ( isset( $arg['required'] ) && true === $arg['required'] && null === $param ) { 
  678. $required[] = $key; 
  679.  
  680. if ( ! empty( $required ) ) { 
  681. return new WP_Error( 'rest_missing_callback_param', sprintf( __( 'Missing parameter(s): %s' ), implode( ', ', $required ) ), array( 'status' => 400, 'params' => $required ) ); 
  682.  
  683. /** 
  684. * Check the validation callbacks for each registered arg. 
  685. * This is done after required checking as required checking is cheaper. 
  686. */ 
  687. $invalid_params = array(); 
  688.  
  689. foreach ( $attributes['args'] as $key => $arg ) { 
  690.  
  691. $param = $this->get_param( $key ); 
  692.  
  693. if ( null !== $param && ! empty( $arg['validate_callback'] ) ) { 
  694. $valid_check = call_user_func( $arg['validate_callback'], $param, $this, $key ); 
  695.  
  696. if ( false === $valid_check ) { 
  697. $invalid_params[ $key ] = __( 'Invalid parameter.' ); 
  698.  
  699. if ( is_wp_error( $valid_check ) ) { 
  700. $invalid_params[ $key ] = $valid_check->get_error_message(); 
  701.  
  702. if ( $invalid_params ) { 
  703. return new WP_Error( 'rest_invalid_param', sprintf( __( 'Invalid parameter(s): %s' ), implode( ', ', array_keys( $invalid_params ) ) ), array( 'status' => 400, 'params' => $invalid_params ) ); 
  704.  
  705. return true; 
  706.  
  707.  
  708. /** 
  709. * Checks if a parameter is set. 
  710. * @since 4.4.0 
  711. * @access public 
  712. * @param string $offset Parameter name. 
  713. * @return bool Whether the parameter is set. 
  714. */ 
  715. public function offsetExists( $offset ) { 
  716. $order = $this->get_parameter_order(); 
  717.  
  718. foreach ( $order as $type ) { 
  719. if ( isset( $this->params[ $type ][ $offset ] ) ) { 
  720. return true; 
  721.  
  722. return false; 
  723.  
  724. /** 
  725. * Retrieves a parameter from the request. 
  726. * @since 4.4.0 
  727. * @access public 
  728. * @param string $offset Parameter name. 
  729. * @return mixed|null Value if set, null otherwise. 
  730. */ 
  731. public function offsetGet( $offset ) { 
  732. return $this->get_param( $offset ); 
  733.  
  734. /** 
  735. * Sets a parameter on the request. 
  736. * @since 4.4.0 
  737. * @access public 
  738. * @param string $offset Parameter name. 
  739. * @param mixed $value Parameter value. 
  740. */ 
  741. public function offsetSet( $offset, $value ) { 
  742. $this->set_param( $offset, $value ); 
  743.  
  744. /** 
  745. * Removes a parameter from the request. 
  746. * @since 4.4.0 
  747. * @access public 
  748. * @param string $offset Parameter name. 
  749. */ 
  750. public function offsetUnset( $offset ) { 
  751. $order = $this->get_parameter_order(); 
  752.  
  753. // Remove the offset from every group. 
  754. foreach ( $order as $type ) { 
  755. unset( $this->params[ $type ][ $offset ] ); 
  756.  
  757. /** 
  758. * Retrieves a WP_REST_Request object from a full URL. 
  759. * @static 
  760. * @since 4.5.0 
  761. * @access public 
  762. * @param string $url URL with protocol, domain, path and query args. 
  763. * @return WP_REST_Request|false WP_REST_Request object on success, false on failure. 
  764. */ 
  765. public static function from_url( $url ) { 
  766. $bits = parse_url( $url ); 
  767. $query_params = array(); 
  768.  
  769. if ( ! empty( $bits['query'] ) ) { 
  770. wp_parse_str( $bits['query'], $query_params ); 
  771.  
  772. $api_root = rest_url(); 
  773. if ( get_option( 'permalink_structure' ) && 0 === strpos( $url, $api_root ) ) { 
  774. // Pretty permalinks on, and URL is under the API root. 
  775. $api_url_part = substr( $url, strlen( untrailingslashit( $api_root ) ) ); 
  776. $route = parse_url( $api_url_part, PHP_URL_PATH ); 
  777. } elseif ( ! empty( $query_params['rest_route'] ) ) { 
  778. // ?rest_route=... set directly 
  779. $route = $query_params['rest_route']; 
  780. unset( $query_params['rest_route'] ); 
  781.  
  782. $request = false; 
  783. if ( ! empty( $route ) ) { 
  784. $request = new WP_REST_Request( 'GET', $route ); 
  785. $request->set_query_params( $query_params ); 
  786.  
  787. /** 
  788. * Filters the request generated from a URL. 
  789. * @since 4.5.0 
  790. * @param WP_REST_Request|false $request Generated request object, or false if URL 
  791. * could not be parsed. 
  792. * @param string $url URL the request was generated from. 
  793. */ 
  794. return apply_filters( 'rest_request_from_url', $request, $url );