WP_REST_Settings_Controller

Core class used to manage a site's settings via the REST API.

Defined (1)

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

/wp-includes/rest-api/endpoints/class-wp-rest-settings-controller.php  
  1. class WP_REST_Settings_Controller extends WP_REST_Controller { 
  2.  
  3. /** 
  4. * Constructor. 
  5. * @since 4.7.0 
  6. * @access public 
  7. */ 
  8. public function __construct() { 
  9. $this->namespace = 'wp/v2'; 
  10. $this->rest_base = 'settings'; 
  11.  
  12. /** 
  13. * Registers the routes for the objects of the controller. 
  14. * @since 4.7.0 
  15. * @access public 
  16. * @see register_rest_route() 
  17. */ 
  18. public function register_routes() { 
  19.  
  20. register_rest_route( $this->namespace, '/' . $this->rest_base, array( 
  21. array( 
  22. 'methods' => WP_REST_Server::READABLE,  
  23. 'callback' => array( $this, 'get_item' ),  
  24. 'args' => array(),  
  25. 'permission_callback' => array( $this, 'get_item_permissions_check' ),  
  26. ),  
  27. array( 
  28. 'methods' => WP_REST_Server::EDITABLE,  
  29. 'callback' => array( $this, 'update_item' ),  
  30. 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),  
  31. 'permission_callback' => array( $this, 'get_item_permissions_check' ),  
  32. ),  
  33. 'schema' => array( $this, 'get_public_item_schema' ),  
  34. ) ); 
  35.  
  36.  
  37. /** 
  38. * Checks if a given request has access to read and manage settings. 
  39. * @since 4.7.0 
  40. * @access public 
  41. * @param WP_REST_Request $request Full details about the request. 
  42. * @return bool True if the request has read access for the item, otherwise false. 
  43. */ 
  44. public function get_item_permissions_check( $request ) { 
  45. return current_user_can( 'manage_options' ); 
  46.  
  47. /** 
  48. * Retrieves the settings. 
  49. * @since 4.7.0 
  50. * @access public 
  51. * @param WP_REST_Request $request Full details about the request. 
  52. * @return array|WP_Error Array on success, or WP_Error object on failure. 
  53. */ 
  54. public function get_item( $request ) { 
  55. $options = $this->get_registered_options(); 
  56. $response = array(); 
  57.  
  58. foreach ( $options as $name => $args ) { 
  59. /** 
  60. * Filters the value of a setting recognized by the REST API. 
  61. * Allow hijacking the setting value and overriding the built-in behavior by returning a 
  62. * non-null value. The returned value will be presented as the setting value instead. 
  63. * @since 4.7.0 
  64. * @param mixed $result Value to use for the requested setting. Can be a scalar 
  65. * matching the registered schema for the setting, or null to 
  66. * follow the default get_option() behavior. 
  67. * @param string $name Setting name (as shown in REST API responses). 
  68. * @param array $args Arguments passed to register_setting() for this setting. 
  69. */ 
  70. $response[ $name ] = apply_filters( 'rest_pre_get_setting', null, $name, $args ); 
  71.  
  72. if ( is_null( $response[ $name ] ) ) { 
  73. // Default to a null value as "null" in the response means "not set". 
  74. $response[ $name ] = get_option( $args['option_name'], $args['schema']['default'] ); 
  75.  
  76. /** 
  77. * Because get_option() is lossy, we have to 
  78. * cast values to the type they are registered with. 
  79. */ 
  80. $response[ $name ] = $this->prepare_value( $response[ $name ], $args['schema'] ); 
  81.  
  82. return $response; 
  83.  
  84. /** 
  85. * Prepares a value for output based off a schema array. 
  86. * @since 4.7.0 
  87. * @access protected 
  88. * @param mixed $value Value to prepare. 
  89. * @param array $schema Schema to match. 
  90. * @return mixed The prepared value. 
  91. */ 
  92. protected function prepare_value( $value, $schema ) { 
  93. // If the value is not a scalar, it's not possible to cast it to anything. 
  94. if ( ! is_scalar( $value ) ) { 
  95. return null; 
  96.  
  97. switch ( $schema['type'] ) { 
  98. case 'string': 
  99. return (string) $value; 
  100. case 'integer': 
  101. return (int) $value; 
  102. case 'number': 
  103. return (float) $value; 
  104. case 'boolean': 
  105. return (bool) $value; 
  106. default: 
  107. return null; 
  108.  
  109. /** 
  110. * Updates settings for the settings object. 
  111. * @since 4.7.0 
  112. * @access public 
  113. * @param WP_REST_Request $request Full details about the request. 
  114. * @return array|WP_Error Array on success, or error object on failure. 
  115. */ 
  116. public function update_item( $request ) { 
  117. $options = $this->get_registered_options(); 
  118. $params = $request->get_params(); 
  119.  
  120. foreach ( $options as $name => $args ) { 
  121. if ( ! array_key_exists( $name, $params ) ) { 
  122. continue; 
  123.  
  124. /** 
  125. * Filters whether to preempt a setting value update. 
  126. * Allows hijacking the setting update logic and overriding the built-in behavior by 
  127. * returning true. 
  128. * @since 4.7.0 
  129. * @param bool $result Whether to override the default behavior for updating the 
  130. * value of a setting. 
  131. * @param string $name Setting name (as shown in REST API responses). 
  132. * @param mixed $value Updated setting value. 
  133. * @param array $args Arguments passed to register_setting() for this setting. 
  134. */ 
  135. $updated = apply_filters( 'rest_pre_update_setting', false, $name, $request[ $name ], $args ); 
  136.  
  137. if ( $updated ) { 
  138. continue; 
  139.  
  140. /** 
  141. * A null value for an option would have the same effect as 
  142. * deleting the option from the database, and relying on the 
  143. * default value. 
  144. */ 
  145. if ( is_null( $request[ $name ] ) ) { 
  146. /** 
  147. * A null value is returned in the response for any option 
  148. * that has a non-scalar value. 
  149. * To protect clients from accidentally including the null 
  150. * values from a response object in a request, we do not allow 
  151. * options with non-scalar values to be updated to null. 
  152. * Without this added protection a client could mistakenly 
  153. * delete all options that have non-scalar values from the 
  154. * database. 
  155. */ 
  156. if ( ! is_scalar( get_option( $args['option_name'], false ) ) ) { 
  157. return new WP_Error( 
  158. 'rest_invalid_stored_value', sprintf( __( 'The %s property has an invalid stored value, and cannot be updated to null.' ), $name ), array( 'status' => 500 ) 
  159. ); 
  160.  
  161. delete_option( $args['option_name'] ); 
  162. } else { 
  163. update_option( $args['option_name'], $request[ $name ] ); 
  164.  
  165. return $this->get_item( $request ); 
  166.  
  167. /** 
  168. * Retrieves all of the registered options for the Settings API. 
  169. * @since 4.7.0 
  170. * @access protected 
  171. * @return array Array of registered options. 
  172. */ 
  173. protected function get_registered_options() { 
  174. $rest_options = array(); 
  175.  
  176. foreach ( get_registered_settings() as $name => $args ) { 
  177. if ( empty( $args['show_in_rest'] ) ) { 
  178. continue; 
  179.  
  180. $rest_args = array(); 
  181.  
  182. if ( is_array( $args['show_in_rest'] ) ) { 
  183. $rest_args = $args['show_in_rest']; 
  184.  
  185. $defaults = array( 
  186. 'name' => ! empty( $rest_args['name'] ) ? $rest_args['name'] : $name,  
  187. 'schema' => array(),  
  188. ); 
  189.  
  190. $rest_args = array_merge( $defaults, $rest_args ); 
  191.  
  192. $default_schema = array( 
  193. 'type' => empty( $args['type'] ) ? null : $args['type'],  
  194. 'description' => empty( $args['description'] ) ? '' : $args['description'],  
  195. 'default' => isset( $args['default'] ) ? $args['default'] : null,  
  196. ); 
  197.  
  198. $rest_args['schema'] = array_merge( $default_schema, $rest_args['schema'] ); 
  199. $rest_args['option_name'] = $name; 
  200.  
  201. // Skip over settings that don't have a defined type in the schema. 
  202. if ( empty( $rest_args['schema']['type'] ) ) { 
  203. continue; 
  204.  
  205. /** 
  206. * Whitelist the supported types for settings, as we don't want invalid types 
  207. * to be updated with arbitrary values that we can't do decent sanitizing for. 
  208. */ 
  209. if ( ! in_array( $rest_args['schema']['type'], array( 'number', 'integer', 'string', 'boolean' ), true ) ) { 
  210. continue; 
  211.  
  212. $rest_options[ $rest_args['name'] ] = $rest_args; 
  213.  
  214. return $rest_options; 
  215.  
  216. /** 
  217. * Retrieves the site setting schema, conforming to JSON Schema. 
  218. * @since 4.7.0 
  219. * @access public 
  220. * @return array Item schema data. 
  221. */ 
  222. public function get_item_schema() { 
  223. $options = $this->get_registered_options(); 
  224.  
  225. $schema = array( 
  226. '$schema' => 'http://json-schema.org/schema#',  
  227. 'title' => 'settings',  
  228. 'type' => 'object',  
  229. 'properties' => array(),  
  230. ); 
  231.  
  232. foreach ( $options as $option_name => $option ) { 
  233. $schema['properties'][ $option_name ] = $option['schema']; 
  234. $schema['properties'][ $option_name ]['arg_options'] = array( 
  235. 'sanitize_callback' => array( $this, 'sanitize_callback' ),  
  236. ); 
  237.  
  238. return $this->add_additional_fields_schema( $schema ); 
  239.  
  240. /** 
  241. * Custom sanitize callback used for all options to allow the use of 'null'. 
  242. * By default, the schema of settings will throw an error if a value is set to 
  243. * `null` as it's not a valid value for something like "type => string". We 
  244. * provide a wrapper sanitizer to whitelist the use of `null`. 
  245. * @param mixed $value The value for the setting. 
  246. * @param WP_REST_Request $request The request object. 
  247. * @param string $param The parameter name. 
  248. * @return mixed|WP_Error 
  249. */ 
  250. public function sanitize_callback( $value, $request, $param ) { 
  251. if ( is_null( $value ) ) { 
  252. return $value; 
  253. return rest_parse_request_arg( $value, $request, $param );