8 */ |
8 */ |
9 |
9 |
10 /** |
10 /** |
11 * Base Global Styles REST API Controller. |
11 * Base Global Styles REST API Controller. |
12 */ |
12 */ |
13 class WP_REST_Global_Styles_Controller extends WP_REST_Controller { |
13 class WP_REST_Global_Styles_Controller extends WP_REST_Posts_Controller { |
14 |
14 /** |
15 /** |
15 * Whether the controller supports batching. |
16 * Post type. |
16 * |
17 * |
17 * @since 6.6.0 |
18 * @since 5.9.0 |
18 * @var array |
19 * @var string |
19 */ |
20 */ |
20 protected $allow_batch = array( 'v1' => false ); |
21 protected $post_type; |
|
22 |
21 |
23 /** |
22 /** |
24 * Constructor. |
23 * Constructor. |
25 * @since 5.9.0 |
24 * |
26 */ |
25 * @since 6.6.0 |
27 public function __construct() { |
26 * |
28 $this->namespace = 'wp/v2'; |
27 * @param string $post_type Post type. |
29 $this->rest_base = 'global-styles'; |
28 */ |
30 $this->post_type = 'wp_global_styles'; |
29 public function __construct( $post_type = 'wp_global_styles' ) { |
|
30 parent::__construct( $post_type ); |
31 } |
31 } |
32 |
32 |
33 /** |
33 /** |
34 * Registers the controllers routes. |
34 * Registers the controllers routes. |
35 * |
35 * |
36 * @since 5.9.0 |
36 * @since 5.9.0 |
37 * |
|
38 * @return void |
|
39 */ |
37 */ |
40 public function register_routes() { |
38 public function register_routes() { |
41 register_rest_route( |
39 register_rest_route( |
42 $this->namespace, |
40 $this->namespace, |
43 '/' . $this->rest_base . '/themes/(?P<stylesheet>[\/\s%\w\.\(\)\[\]\@_\-]+)/variations', |
41 '/' . $this->rest_base . '/themes/(?P<stylesheet>[\/\s%\w\.\(\)\[\]\@_\-]+)/variations', |
121 * @param string $id_or_stylesheet Global styles ID or stylesheet. |
124 * @param string $id_or_stylesheet Global styles ID or stylesheet. |
122 * @return string Sanitized global styles ID or stylesheet. |
125 * @return string Sanitized global styles ID or stylesheet. |
123 */ |
126 */ |
124 public function _sanitize_global_styles_callback( $id_or_stylesheet ) { |
127 public function _sanitize_global_styles_callback( $id_or_stylesheet ) { |
125 return urldecode( $id_or_stylesheet ); |
128 return urldecode( $id_or_stylesheet ); |
|
129 } |
|
130 |
|
131 /** |
|
132 * Get the post, if the ID is valid. |
|
133 * |
|
134 * @since 5.9.0 |
|
135 * |
|
136 * @param int $id Supplied ID. |
|
137 * @return WP_Post|WP_Error Post object if ID is valid, WP_Error otherwise. |
|
138 */ |
|
139 protected function get_post( $id ) { |
|
140 $error = new WP_Error( |
|
141 'rest_global_styles_not_found', |
|
142 __( 'No global styles config exist with that id.' ), |
|
143 array( 'status' => 404 ) |
|
144 ); |
|
145 |
|
146 $id = (int) $id; |
|
147 if ( $id <= 0 ) { |
|
148 return $error; |
|
149 } |
|
150 |
|
151 $post = get_post( $id ); |
|
152 if ( empty( $post ) || empty( $post->ID ) || $this->post_type !== $post->post_type ) { |
|
153 return $error; |
|
154 } |
|
155 |
|
156 return $post; |
126 } |
157 } |
127 |
158 |
128 /** |
159 /** |
129 * Checks if a given request has access to read a single global style. |
160 * Checks if a given request has access to read a single global style. |
130 * |
161 * |
212 |
225 |
213 return true; |
226 return true; |
214 } |
227 } |
215 |
228 |
216 /** |
229 /** |
217 * Checks if a global style can be edited. |
|
218 * |
|
219 * @since 5.9.0 |
|
220 * |
|
221 * @param WP_Post $post Post object. |
|
222 * @return bool Whether the post can be edited. |
|
223 */ |
|
224 protected function check_update_permission( $post ) { |
|
225 return current_user_can( 'edit_post', $post->ID ); |
|
226 } |
|
227 |
|
228 /** |
|
229 * Updates a single global style config. |
|
230 * |
|
231 * @since 5.9.0 |
|
232 * |
|
233 * @param WP_REST_Request $request Full details about the request. |
|
234 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. |
|
235 */ |
|
236 public function update_item( $request ) { |
|
237 $post_before = $this->get_post( $request['id'] ); |
|
238 if ( is_wp_error( $post_before ) ) { |
|
239 return $post_before; |
|
240 } |
|
241 |
|
242 $changes = $this->prepare_item_for_database( $request ); |
|
243 $result = wp_update_post( wp_slash( (array) $changes ), true, false ); |
|
244 if ( is_wp_error( $result ) ) { |
|
245 return $result; |
|
246 } |
|
247 |
|
248 $post = get_post( $request['id'] ); |
|
249 $fields_update = $this->update_additional_fields_for_object( $post, $request ); |
|
250 if ( is_wp_error( $fields_update ) ) { |
|
251 return $fields_update; |
|
252 } |
|
253 |
|
254 wp_after_insert_post( $post, true, $post_before ); |
|
255 |
|
256 $response = $this->prepare_item_for_response( $post, $request ); |
|
257 |
|
258 return rest_ensure_response( $response ); |
|
259 } |
|
260 |
|
261 /** |
|
262 * Prepares a single global styles config for update. |
230 * Prepares a single global styles config for update. |
263 * |
231 * |
264 * @since 5.9.0 |
232 * @since 5.9.0 |
|
233 * @since 6.2.0 Added validation of styles.css property. |
|
234 * @since 6.6.0 Added registration of block style variations from theme.json sources (theme.json, user theme.json, partials). |
265 * |
235 * |
266 * @param WP_REST_Request $request Request object. |
236 * @param WP_REST_Request $request Request object. |
267 * @return stdClass Changes to pass to wp_update_post. |
237 * @return stdClass|WP_Error Prepared item on success. WP_Error on when the custom CSS is not valid. |
268 */ |
238 */ |
269 protected function prepare_item_for_database( $request ) { |
239 protected function prepare_item_for_database( $request ) { |
270 $changes = new stdClass(); |
240 $changes = new stdClass(); |
271 $changes->ID = $request['id']; |
241 $changes->ID = $request['id']; |
272 |
242 |
282 } |
252 } |
283 |
253 |
284 if ( isset( $request['styles'] ) || isset( $request['settings'] ) ) { |
254 if ( isset( $request['styles'] ) || isset( $request['settings'] ) ) { |
285 $config = array(); |
255 $config = array(); |
286 if ( isset( $request['styles'] ) ) { |
256 if ( isset( $request['styles'] ) ) { |
|
257 if ( isset( $request['styles']['css'] ) ) { |
|
258 $css_validation_result = $this->validate_custom_css( $request['styles']['css'] ); |
|
259 if ( is_wp_error( $css_validation_result ) ) { |
|
260 return $css_validation_result; |
|
261 } |
|
262 } |
287 $config['styles'] = $request['styles']; |
263 $config['styles'] = $request['styles']; |
288 } elseif ( isset( $existing_config['styles'] ) ) { |
264 } elseif ( isset( $existing_config['styles'] ) ) { |
289 $config['styles'] = $existing_config['styles']; |
265 $config['styles'] = $existing_config['styles']; |
290 } |
266 } |
|
267 |
|
268 // Register theme-defined variations e.g. from block style variation partials under `/styles`. |
|
269 $variations = WP_Theme_JSON_Resolver::get_style_variations( 'block' ); |
|
270 wp_register_block_style_variations_from_theme_json_partials( $variations ); |
|
271 |
291 if ( isset( $request['settings'] ) ) { |
272 if ( isset( $request['settings'] ) ) { |
292 $config['settings'] = $request['settings']; |
273 $config['settings'] = $request['settings']; |
293 } elseif ( isset( $existing_config['settings'] ) ) { |
274 } elseif ( isset( $existing_config['settings'] ) ) { |
294 $config['settings'] = $existing_config['settings']; |
275 $config['settings'] = $existing_config['settings']; |
295 } |
276 } |
312 |
293 |
313 /** |
294 /** |
314 * Prepare a global styles config output for response. |
295 * Prepare a global styles config output for response. |
315 * |
296 * |
316 * @since 5.9.0 |
297 * @since 5.9.0 |
|
298 * @since 6.6.0 Added custom relative theme file URIs to `_links`. |
317 * |
299 * |
318 * @param WP_Post $post Global Styles post object. |
300 * @param WP_Post $post Global Styles post object. |
319 * @param WP_REST_Request $request Request object. |
301 * @param WP_REST_Request $request Request object. |
320 * @return WP_REST_Response Response object. |
302 * @return WP_REST_Response Response object. |
321 */ |
303 */ |
322 public function prepare_item_for_response( $post, $request ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable |
304 public function prepare_item_for_response( $post, $request ) { |
323 $raw_config = json_decode( $post->post_content, true ); |
305 $raw_config = json_decode( $post->post_content, true ); |
324 $is_global_styles_user_theme_json = isset( $raw_config['isGlobalStylesUserThemeJSON'] ) && true === $raw_config['isGlobalStylesUserThemeJSON']; |
306 $is_global_styles_user_theme_json = isset( $raw_config['isGlobalStylesUserThemeJSON'] ) && true === $raw_config['isGlobalStylesUserThemeJSON']; |
325 $config = array(); |
307 $config = array(); |
|
308 $theme_json = null; |
326 if ( $is_global_styles_user_theme_json ) { |
309 if ( $is_global_styles_user_theme_json ) { |
327 $config = ( new WP_Theme_JSON( $raw_config, 'custom' ) )->get_raw_data(); |
310 $theme_json = new WP_Theme_JSON( $raw_config, 'custom' ); |
|
311 $config = $theme_json->get_raw_data(); |
328 } |
312 } |
329 |
313 |
330 // Base fields for every post. |
314 // Base fields for every post. |
|
315 $fields = $this->get_fields_for_response( $request ); |
331 $data = array(); |
316 $data = array(); |
332 $fields = $this->get_fields_for_response( $request ); |
|
333 |
317 |
334 if ( rest_is_field_included( 'id', $fields ) ) { |
318 if ( rest_is_field_included( 'id', $fields ) ) { |
335 $data['id'] = $post->ID; |
319 $data['id'] = $post->ID; |
336 } |
320 } |
337 |
321 |
362 $data = $this->filter_response_by_context( $data, $context ); |
346 $data = $this->filter_response_by_context( $data, $context ); |
363 |
347 |
364 // Wrap the data in a response object. |
348 // Wrap the data in a response object. |
365 $response = rest_ensure_response( $data ); |
349 $response = rest_ensure_response( $data ); |
366 |
350 |
367 $links = $this->prepare_links( $post->ID ); |
351 if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) { |
368 $response->add_links( $links ); |
352 $links = $this->prepare_links( $post->ID ); |
369 if ( ! empty( $links['self']['href'] ) ) { |
353 |
370 $actions = $this->get_available_actions(); |
354 // Only return resolved URIs for get requests to user theme JSON. |
371 $self = $links['self']['href']; |
355 if ( $theme_json ) { |
372 foreach ( $actions as $rel ) { |
356 $resolved_theme_uris = WP_Theme_JSON_Resolver::get_resolved_theme_uris( $theme_json ); |
373 $response->add_link( $rel, $self ); |
357 if ( ! empty( $resolved_theme_uris ) ) { |
|
358 $links['https://api.w.org/theme-file'] = $resolved_theme_uris; |
|
359 } |
|
360 } |
|
361 |
|
362 $response->add_links( $links ); |
|
363 if ( ! empty( $links['self']['href'] ) ) { |
|
364 $actions = $this->get_available_actions( $post, $request ); |
|
365 $self = $links['self']['href']; |
|
366 foreach ( $actions as $rel ) { |
|
367 $response->add_link( $rel, $self ); |
|
368 } |
374 } |
369 } |
375 } |
370 } |
376 |
371 |
377 return $response; |
372 return $response; |
378 } |
373 } |
379 |
374 |
380 /** |
375 /** |
381 * Get the post, if the ID is valid. |
|
382 * |
|
383 * @since 5.9.0 |
|
384 * |
|
385 * @param int $id Supplied ID. |
|
386 * @return WP_Post|WP_Error Post object if ID is valid, WP_Error otherwise. |
|
387 */ |
|
388 protected function get_post( $id ) { |
|
389 $error = new WP_Error( |
|
390 'rest_global_styles_not_found', |
|
391 __( 'No global styles config exist with that id.' ), |
|
392 array( 'status' => 404 ) |
|
393 ); |
|
394 |
|
395 $id = (int) $id; |
|
396 if ( $id <= 0 ) { |
|
397 return $error; |
|
398 } |
|
399 |
|
400 $post = get_post( $id ); |
|
401 if ( empty( $post ) || empty( $post->ID ) || $this->post_type !== $post->post_type ) { |
|
402 return $error; |
|
403 } |
|
404 |
|
405 return $post; |
|
406 } |
|
407 |
|
408 |
|
409 /** |
|
410 * Prepares links for the request. |
376 * Prepares links for the request. |
411 * |
377 * |
412 * @since 5.9.0 |
378 * @since 5.9.0 |
|
379 * @since 6.3.0 Adds revisions count and rest URL href to version-history. |
413 * |
380 * |
414 * @param integer $id ID. |
381 * @param integer $id ID. |
415 * @return array Links for the given post. |
382 * @return array Links for the given post. |
416 */ |
383 */ |
417 protected function prepare_links( $id ) { |
384 protected function prepare_links( $id ) { |
418 $base = sprintf( '%s/%s', $this->namespace, $this->rest_base ); |
385 $base = sprintf( '%s/%s', $this->namespace, $this->rest_base ); |
419 |
386 |
420 $links = array( |
387 $links = array( |
421 'self' => array( |
388 'self' => array( |
422 'href' => rest_url( trailingslashit( $base ) . $id ), |
389 'href' => rest_url( trailingslashit( $base ) . $id ), |
423 ), |
390 ), |
|
391 'about' => array( |
|
392 'href' => rest_url( 'wp/v2/types/' . $this->post_type ), |
|
393 ), |
424 ); |
394 ); |
425 |
395 |
|
396 if ( post_type_supports( $this->post_type, 'revisions' ) ) { |
|
397 $revisions = wp_get_latest_revision_id_and_total_count( $id ); |
|
398 $revisions_count = ! is_wp_error( $revisions ) ? $revisions['count'] : 0; |
|
399 $revisions_base = sprintf( '/%s/%d/revisions', $base, $id ); |
|
400 $links['version-history'] = array( |
|
401 'href' => rest_url( $revisions_base ), |
|
402 'count' => $revisions_count, |
|
403 ); |
|
404 } |
|
405 |
426 return $links; |
406 return $links; |
427 } |
407 } |
428 |
408 |
429 /** |
409 /** |
430 * Get the link relations available for the post and current user. |
410 * Get the link relations available for the post and current user. |
431 * |
411 * |
432 * @since 5.9.0 |
412 * @since 5.9.0 |
433 * |
413 * @since 6.2.0 Added 'edit-css' action. |
|
414 * @since 6.6.0 Added $post and $request parameters. |
|
415 * |
|
416 * @param WP_Post $post Post object. |
|
417 * @param WP_REST_Request $request Request object. |
434 * @return array List of link relations. |
418 * @return array List of link relations. |
435 */ |
419 */ |
436 protected function get_available_actions() { |
420 protected function get_available_actions( $post, $request ) { |
437 $rels = array(); |
421 $rels = array(); |
438 |
422 |
439 $post_type = get_post_type_object( $this->post_type ); |
423 $post_type = get_post_type_object( $post->post_type ); |
440 if ( current_user_can( $post_type->cap->publish_posts ) ) { |
424 if ( current_user_can( $post_type->cap->publish_posts ) ) { |
441 $rels[] = 'https://api.w.org/action-publish'; |
425 $rels[] = 'https://api.w.org/action-publish'; |
442 } |
426 } |
443 |
427 |
|
428 if ( current_user_can( 'edit_css' ) ) { |
|
429 $rels[] = 'https://api.w.org/action-edit-css'; |
|
430 } |
|
431 |
444 return $rels; |
432 return $rels; |
445 } |
|
446 |
|
447 /** |
|
448 * Overwrites the default protected title format. |
|
449 * |
|
450 * By default, WordPress will show password protected posts with a title of |
|
451 * "Protected: %s", as the REST API communicates the protected status of a post |
|
452 * in a machine readable format, we remove the "Protected: " prefix. |
|
453 * |
|
454 * @since 5.9.0 |
|
455 * |
|
456 * @return string Protected title format. |
|
457 */ |
|
458 public function protected_title_format() { |
|
459 return '%s'; |
|
460 } |
433 } |
461 |
434 |
462 /** |
435 /** |
463 * Retrieves the query params for the global styles collection. |
436 * Retrieves the query params for the global styles collection. |
464 * |
437 * |
537 * |
510 * |
538 * @param WP_REST_Request $request Full details about the request. |
511 * @param WP_REST_Request $request Full details about the request. |
539 * @return true|WP_Error True if the request has read access for the item, WP_Error object otherwise. |
512 * @return true|WP_Error True if the request has read access for the item, WP_Error object otherwise. |
540 */ |
513 */ |
541 public function get_theme_item_permissions_check( $request ) { |
514 public function get_theme_item_permissions_check( $request ) { |
542 // Verify if the current user has edit_theme_options capability. |
515 /* |
543 // This capability is required to edit/view/delete templates. |
516 * Verify if the current user has edit_theme_options capability. |
|
517 * This capability is required to edit/view/delete templates. |
|
518 */ |
544 if ( ! current_user_can( 'edit_theme_options' ) ) { |
519 if ( ! current_user_can( 'edit_theme_options' ) ) { |
545 return new WP_Error( |
520 return new WP_Error( |
546 'rest_cannot_manage_global_styles', |
521 'rest_cannot_manage_global_styles', |
547 __( 'Sorry, you are not allowed to access the global styles on this site.' ), |
522 __( 'Sorry, you are not allowed to access the global styles on this site.' ), |
548 array( |
523 array( |
556 |
531 |
557 /** |
532 /** |
558 * Returns the given theme global styles config. |
533 * Returns the given theme global styles config. |
559 * |
534 * |
560 * @since 5.9.0 |
535 * @since 5.9.0 |
|
536 * @since 6.6.0 Added custom relative theme file URIs to `_links`. |
561 * |
537 * |
562 * @param WP_REST_Request $request The request instance. |
538 * @param WP_REST_Request $request The request instance. |
563 * @return WP_REST_Response|WP_Error |
539 * @return WP_REST_Response|WP_Error |
564 */ |
540 */ |
565 public function get_theme_item( $request ) { |
541 public function get_theme_item( $request ) { |
566 if ( wp_get_theme()->get_stylesheet() !== $request['stylesheet'] ) { |
542 if ( get_stylesheet() !== $request['stylesheet'] ) { |
567 // This endpoint only supports the active theme for now. |
543 // This endpoint only supports the active theme for now. |
568 return new WP_Error( |
544 return new WP_Error( |
569 'rest_theme_not_found', |
545 'rest_theme_not_found', |
570 __( 'Theme not found.' ), |
546 __( 'Theme not found.' ), |
571 array( 'status' => 404 ) |
547 array( 'status' => 404 ) |
572 ); |
548 ); |
573 } |
549 } |
574 |
550 |
575 $theme = WP_Theme_JSON_Resolver::get_merged_data( 'theme' ); |
551 $theme = WP_Theme_JSON_Resolver::get_merged_data( 'theme' ); |
|
552 $fields = $this->get_fields_for_response( $request ); |
576 $data = array(); |
553 $data = array(); |
577 $fields = $this->get_fields_for_response( $request ); |
|
578 |
554 |
579 if ( rest_is_field_included( 'settings', $fields ) ) { |
555 if ( rest_is_field_included( 'settings', $fields ) ) { |
580 $data['settings'] = $theme->get_settings(); |
556 $data['settings'] = $theme->get_settings(); |
581 } |
557 } |
582 |
558 |
589 $data = $this->add_additional_fields_to_object( $data, $request ); |
565 $data = $this->add_additional_fields_to_object( $data, $request ); |
590 $data = $this->filter_response_by_context( $data, $context ); |
566 $data = $this->filter_response_by_context( $data, $context ); |
591 |
567 |
592 $response = rest_ensure_response( $data ); |
568 $response = rest_ensure_response( $data ); |
593 |
569 |
594 $links = array( |
570 if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) { |
595 'self' => array( |
571 $links = array( |
596 'href' => rest_url( sprintf( '%s/%s/themes/%s', $this->namespace, $this->rest_base, $request['stylesheet'] ) ), |
572 'self' => array( |
597 ), |
573 'href' => rest_url( sprintf( '%s/%s/themes/%s', $this->namespace, $this->rest_base, $request['stylesheet'] ) ), |
598 ); |
574 ), |
599 |
575 ); |
600 $response->add_links( $links ); |
576 $resolved_theme_uris = WP_Theme_JSON_Resolver::get_resolved_theme_uris( $theme ); |
|
577 if ( ! empty( $resolved_theme_uris ) ) { |
|
578 $links['https://api.w.org/theme-file'] = $resolved_theme_uris; |
|
579 } |
|
580 $response->add_links( $links ); |
|
581 } |
601 |
582 |
602 return $response; |
583 return $response; |
603 } |
584 } |
604 |
585 |
605 /** |
586 /** |
608 * @since 6.0.0 |
589 * @since 6.0.0 |
609 * |
590 * |
610 * @param WP_REST_Request $request Full details about the request. |
591 * @param WP_REST_Request $request Full details about the request. |
611 * @return true|WP_Error True if the request has read access for the item, WP_Error object otherwise. |
592 * @return true|WP_Error True if the request has read access for the item, WP_Error object otherwise. |
612 */ |
593 */ |
613 public function get_theme_items_permissions_check( $request ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable |
594 public function get_theme_items_permissions_check( $request ) { |
614 // Verify if the current user has edit_theme_options capability. |
595 /* |
615 // This capability is required to edit/view/delete templates. |
596 * Verify if the current user has edit_theme_options capability. |
|
597 * This capability is required to edit/view/delete templates. |
|
598 */ |
616 if ( ! current_user_can( 'edit_theme_options' ) ) { |
599 if ( ! current_user_can( 'edit_theme_options' ) ) { |
617 return new WP_Error( |
600 return new WP_Error( |
618 'rest_cannot_manage_global_styles', |
601 'rest_cannot_manage_global_styles', |
619 __( 'Sorry, you are not allowed to access the global styles on this site.' ), |
602 __( 'Sorry, you are not allowed to access the global styles on this site.' ), |
620 array( |
603 array( |
628 |
611 |
629 /** |
612 /** |
630 * Returns the given theme global styles variations. |
613 * Returns the given theme global styles variations. |
631 * |
614 * |
632 * @since 6.0.0 |
615 * @since 6.0.0 |
|
616 * @since 6.2.0 Returns parent theme variations, if they exist. |
|
617 * @since 6.6.0 Added custom relative theme file URIs to `_links` for each item. |
633 * |
618 * |
634 * @param WP_REST_Request $request The request instance. |
619 * @param WP_REST_Request $request The request instance. |
635 * |
620 * |
636 * @return WP_REST_Response|WP_Error |
621 * @return WP_REST_Response|WP_Error |
637 */ |
622 */ |
638 public function get_theme_items( $request ) { |
623 public function get_theme_items( $request ) { |
639 if ( wp_get_theme()->get_stylesheet() !== $request['stylesheet'] ) { |
624 if ( get_stylesheet() !== $request['stylesheet'] ) { |
640 // This endpoint only supports the active theme for now. |
625 // This endpoint only supports the active theme for now. |
641 return new WP_Error( |
626 return new WP_Error( |
642 'rest_theme_not_found', |
627 'rest_theme_not_found', |
643 __( 'Theme not found.' ), |
628 __( 'Theme not found.' ), |
644 array( 'status' => 404 ) |
629 array( 'status' => 404 ) |
645 ); |
630 ); |
646 } |
631 } |
647 |
632 |
|
633 $response = array(); |
|
634 |
|
635 // Register theme-defined variations e.g. from block style variation partials under `/styles`. |
|
636 $partials = WP_Theme_JSON_Resolver::get_style_variations( 'block' ); |
|
637 wp_register_block_style_variations_from_theme_json_partials( $partials ); |
|
638 |
648 $variations = WP_Theme_JSON_Resolver::get_style_variations(); |
639 $variations = WP_Theme_JSON_Resolver::get_style_variations(); |
649 $response = rest_ensure_response( $variations ); |
640 foreach ( $variations as $variation ) { |
650 |
641 $variation_theme_json = new WP_Theme_JSON( $variation ); |
651 return $response; |
642 $resolved_theme_uris = WP_Theme_JSON_Resolver::get_resolved_theme_uris( $variation_theme_json ); |
|
643 $data = rest_ensure_response( $variation ); |
|
644 if ( ! empty( $resolved_theme_uris ) ) { |
|
645 $data->add_links( |
|
646 array( |
|
647 'https://api.w.org/theme-file' => $resolved_theme_uris, |
|
648 ) |
|
649 ); |
|
650 } |
|
651 $response[] = $this->prepare_response_for_collection( $data ); |
|
652 } |
|
653 |
|
654 return rest_ensure_response( $response ); |
|
655 } |
|
656 |
|
657 /** |
|
658 * Validate style.css as valid CSS. |
|
659 * |
|
660 * Currently just checks for invalid markup. |
|
661 * |
|
662 * @since 6.2.0 |
|
663 * @since 6.4.0 Changed method visibility to protected. |
|
664 * |
|
665 * @param string $css CSS to validate. |
|
666 * @return true|WP_Error True if the input was validated, otherwise WP_Error. |
|
667 */ |
|
668 protected function validate_custom_css( $css ) { |
|
669 if ( preg_match( '#</?\w+#', $css ) ) { |
|
670 return new WP_Error( |
|
671 'rest_custom_css_illegal_markup', |
|
672 __( 'Markup is not allowed in CSS.' ), |
|
673 array( 'status' => 400 ) |
|
674 ); |
|
675 } |
|
676 return true; |
652 } |
677 } |
653 } |
678 } |