[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

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

   1  <?php
   2  /**
   3   * REST API: WP_REST_Global_Styles_Controller class
   4   *
   5   * @package    WordPress
   6   * @subpackage REST_API
   7   * @since 5.9.0
   8   */
   9  
  10  /**
  11   * Base Global Styles REST API Controller.
  12   */
  13  class WP_REST_Global_Styles_Controller extends WP_REST_Posts_Controller {
  14      /**
  15       * Whether the controller supports batching.
  16       *
  17       * @since 6.6.0
  18       * @var array
  19       */
  20      protected $allow_batch = array( 'v1' => false );
  21  
  22      /**
  23       * Constructor.
  24       *
  25       * @since 6.6.0
  26       *
  27       * @param string $post_type Post type.
  28       */
  29  	public function __construct( $post_type = 'wp_global_styles' ) {
  30          parent::__construct( $post_type );
  31      }
  32  
  33      /**
  34       * Registers the controllers routes.
  35       *
  36       * @since 5.9.0
  37       */
  38  	public function register_routes() {
  39          register_rest_route(
  40              $this->namespace,
  41              '/' . $this->rest_base . '/themes/(?P<stylesheet>[\/\s%\w\.\(\)\[\]\@_\-]+)/variations',
  42              array(
  43                  array(
  44                      'methods'             => WP_REST_Server::READABLE,
  45                      'callback'            => array( $this, 'get_theme_items' ),
  46                      'permission_callback' => array( $this, 'get_theme_items_permissions_check' ),
  47                      'args'                => array(
  48                          'stylesheet' => array(
  49                              'description' => __( 'The theme identifier' ),
  50                              'type'        => 'string',
  51                          ),
  52                      ),
  53                      'allow_batch'         => $this->allow_batch,
  54                  ),
  55              )
  56          );
  57  
  58          // List themes global styles.
  59          register_rest_route(
  60              $this->namespace,
  61              // The route.
  62              sprintf(
  63                  '/%s/themes/(?P<stylesheet>%s)',
  64                  $this->rest_base,
  65                  /*
  66                   * Matches theme's directory: `/themes/<subdirectory>/<theme>/` or `/themes/<theme>/`.
  67                   * Excludes invalid directory name characters: `/:<>*?"|`.
  68                   */
  69                  '[^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?'
  70              ),
  71              array(
  72                  array(
  73                      'methods'             => WP_REST_Server::READABLE,
  74                      'callback'            => array( $this, 'get_theme_item' ),
  75                      'permission_callback' => array( $this, 'get_theme_item_permissions_check' ),
  76                      'args'                => array(
  77                          'stylesheet' => array(
  78                              'description'       => __( 'The theme identifier' ),
  79                              'type'              => 'string',
  80                              'sanitize_callback' => array( $this, '_sanitize_global_styles_callback' ),
  81                          ),
  82                      ),
  83                      'allow_batch'         => $this->allow_batch,
  84                  ),
  85              )
  86          );
  87  
  88          // Lists/updates a single global style variation based on the given id.
  89          register_rest_route(
  90              $this->namespace,
  91              '/' . $this->rest_base . '/(?P<id>[\/\w-]+)',
  92              array(
  93                  array(
  94                      'methods'             => WP_REST_Server::READABLE,
  95                      'callback'            => array( $this, 'get_item' ),
  96                      'permission_callback' => array( $this, 'get_item_permissions_check' ),
  97                      'args'                => array(
  98                          'id' => array(
  99                              'description'       => __( 'The id of a template' ),
 100                              'type'              => 'string',
 101                              'sanitize_callback' => array( $this, '_sanitize_global_styles_callback' ),
 102                          ),
 103                      ),
 104                  ),
 105                  array(
 106                      'methods'             => WP_REST_Server::EDITABLE,
 107                      'callback'            => array( $this, 'update_item' ),
 108                      'permission_callback' => array( $this, 'update_item_permissions_check' ),
 109                      'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
 110                  ),
 111                  'schema'      => array( $this, 'get_public_item_schema' ),
 112                  'allow_batch' => $this->allow_batch,
 113              )
 114          );
 115      }
 116  
 117      /**
 118       * Sanitize the global styles ID or stylesheet to decode endpoint.
 119       * For example, `wp/v2/global-styles/twentytwentytwo%200.4.0`
 120       * would be decoded to `twentytwentytwo 0.4.0`.
 121       *
 122       * @since 5.9.0
 123       *
 124       * @param string $id_or_stylesheet Global styles ID or stylesheet.
 125       * @return string Sanitized global styles ID or stylesheet.
 126       */
 127  	public function _sanitize_global_styles_callback( $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;
 157      }
 158  
 159      /**
 160       * Checks if a given request has access to read a single global style.
 161       *
 162       * @since 5.9.0
 163       *
 164       * @param WP_REST_Request $request Full details about the request.
 165       * @return true|WP_Error True if the request has read access, WP_Error object otherwise.
 166       */
 167  	public function get_item_permissions_check( $request ) {
 168          $post = $this->get_post( $request['id'] );
 169          if ( is_wp_error( $post ) ) {
 170              return $post;
 171          }
 172  
 173          if ( 'edit' === $request['context'] && $post && ! $this->check_update_permission( $post ) ) {
 174              return new WP_Error(
 175                  'rest_forbidden_context',
 176                  __( 'Sorry, you are not allowed to edit this global style.' ),
 177                  array( 'status' => rest_authorization_required_code() )
 178              );
 179          }
 180  
 181          if ( ! $this->check_read_permission( $post ) ) {
 182              return new WP_Error(
 183                  'rest_cannot_view',
 184                  __( 'Sorry, you are not allowed to view this global style.' ),
 185                  array( 'status' => rest_authorization_required_code() )
 186              );
 187          }
 188  
 189          return true;
 190      }
 191  
 192      /**
 193       * Checks if a global style can be read.
 194       *
 195       * @since 5.9.0
 196       *
 197       * @param WP_Post $post Post object.
 198       * @return bool Whether the post can be read.
 199       */
 200  	public function check_read_permission( $post ) {
 201          return current_user_can( 'read_post', $post->ID );
 202      }
 203  
 204      /**
 205       * Checks if a given request has access to write a single global styles config.
 206       *
 207       * @since 5.9.0
 208       *
 209       * @param WP_REST_Request $request Full details about the request.
 210       * @return true|WP_Error True if the request has write access for the item, WP_Error object otherwise.
 211       */
 212  	public function update_item_permissions_check( $request ) {
 213          $post = $this->get_post( $request['id'] );
 214          if ( is_wp_error( $post ) ) {
 215              return $post;
 216          }
 217  
 218          if ( $post && ! $this->check_update_permission( $post ) ) {
 219              return new WP_Error(
 220                  'rest_cannot_edit',
 221                  __( 'Sorry, you are not allowed to edit this global style.' ),
 222                  array( 'status' => rest_authorization_required_code() )
 223              );
 224          }
 225  
 226          return true;
 227      }
 228  
 229      /**
 230       * Prepares a single global styles config for update.
 231       *
 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).
 235       *
 236       * @param WP_REST_Request $request Request object.
 237       * @return stdClass|WP_Error Prepared item on success. WP_Error on when the custom CSS is not valid.
 238       */
 239  	protected function prepare_item_for_database( $request ) {
 240          $changes     = new stdClass();
 241          $changes->ID = $request['id'];
 242  
 243          $post            = get_post( $request['id'] );
 244          $existing_config = array();
 245          if ( $post ) {
 246              $existing_config     = json_decode( $post->post_content, true );
 247              $json_decoding_error = json_last_error();
 248              if ( JSON_ERROR_NONE !== $json_decoding_error || ! isset( $existing_config['isGlobalStylesUserThemeJSON'] ) ||
 249                  ! $existing_config['isGlobalStylesUserThemeJSON'] ) {
 250                  $existing_config = array();
 251              }
 252          }
 253  
 254          if ( isset( $request['styles'] ) || isset( $request['settings'] ) ) {
 255              $config = array();
 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                  }
 263                  $config['styles'] = $request['styles'];
 264              } elseif ( isset( $existing_config['styles'] ) ) {
 265                  $config['styles'] = $existing_config['styles'];
 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  
 272              if ( isset( $request['settings'] ) ) {
 273                  $config['settings'] = $request['settings'];
 274              } elseif ( isset( $existing_config['settings'] ) ) {
 275                  $config['settings'] = $existing_config['settings'];
 276              }
 277              $config['isGlobalStylesUserThemeJSON'] = true;
 278              $config['version']                     = WP_Theme_JSON::LATEST_SCHEMA;
 279              $changes->post_content                 = wp_json_encode( $config );
 280          }
 281  
 282          // Post title.
 283          if ( isset( $request['title'] ) ) {
 284              if ( is_string( $request['title'] ) ) {
 285                  $changes->post_title = $request['title'];
 286              } elseif ( ! empty( $request['title']['raw'] ) ) {
 287                  $changes->post_title = $request['title']['raw'];
 288              }
 289          }
 290  
 291          return $changes;
 292      }
 293  
 294      /**
 295       * Prepare a global styles config output for response.
 296       *
 297       * @since 5.9.0
 298       * @since 6.6.0 Added custom relative theme file URIs to `_links`.
 299       *
 300       * @param WP_Post         $post    Global Styles post object.
 301       * @param WP_REST_Request $request Request object.
 302       * @return WP_REST_Response Response object.
 303       */
 304  	public function prepare_item_for_response( $post, $request ) {
 305          $raw_config                       = json_decode( $post->post_content, true );
 306          $is_global_styles_user_theme_json = isset( $raw_config['isGlobalStylesUserThemeJSON'] ) && true === $raw_config['isGlobalStylesUserThemeJSON'];
 307          $config                           = array();
 308          $theme_json                       = null;
 309          if ( $is_global_styles_user_theme_json ) {
 310              $theme_json = new WP_Theme_JSON( $raw_config, 'custom' );
 311              $config     = $theme_json->get_raw_data();
 312          }
 313  
 314          // Base fields for every post.
 315          $fields = $this->get_fields_for_response( $request );
 316          $data   = array();
 317  
 318          if ( rest_is_field_included( 'id', $fields ) ) {
 319              $data['id'] = $post->ID;
 320          }
 321  
 322          if ( rest_is_field_included( 'title', $fields ) ) {
 323              $data['title'] = array();
 324          }
 325          if ( rest_is_field_included( 'title.raw', $fields ) ) {
 326              $data['title']['raw'] = $post->post_title;
 327          }
 328          if ( rest_is_field_included( 'title.rendered', $fields ) ) {
 329              add_filter( 'protected_title_format', array( $this, 'protected_title_format' ) );
 330              add_filter( 'private_title_format', array( $this, 'protected_title_format' ) );
 331  
 332              $data['title']['rendered'] = get_the_title( $post->ID );
 333  
 334              remove_filter( 'protected_title_format', array( $this, 'protected_title_format' ) );
 335              remove_filter( 'private_title_format', array( $this, 'protected_title_format' ) );
 336          }
 337  
 338          if ( rest_is_field_included( 'settings', $fields ) ) {
 339              $data['settings'] = ! empty( $config['settings'] ) && $is_global_styles_user_theme_json ? $config['settings'] : new stdClass();
 340          }
 341  
 342          if ( rest_is_field_included( 'styles', $fields ) ) {
 343              $data['styles'] = ! empty( $config['styles'] ) && $is_global_styles_user_theme_json ? $config['styles'] : new stdClass();
 344          }
 345  
 346          $context = ! empty( $request['context'] ) ? $request['context'] : 'view';
 347          $data    = $this->add_additional_fields_to_object( $data, $request );
 348          $data    = $this->filter_response_by_context( $data, $context );
 349  
 350          // Wrap the data in a response object.
 351          $response = rest_ensure_response( $data );
 352  
 353          if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) {
 354              $links = $this->prepare_links( $post->ID );
 355  
 356              // Only return resolved URIs for get requests to user theme JSON.
 357              if ( $theme_json ) {
 358                  $resolved_theme_uris = WP_Theme_JSON_Resolver::get_resolved_theme_uris( $theme_json );
 359                  if ( ! empty( $resolved_theme_uris ) ) {
 360                      $links['https://api.w.org/theme-file'] = $resolved_theme_uris;
 361                  }
 362              }
 363  
 364              $response->add_links( $links );
 365              if ( ! empty( $links['self']['href'] ) ) {
 366                  $actions = $this->get_available_actions( $post, $request );
 367                  $self    = $links['self']['href'];
 368                  foreach ( $actions as $rel ) {
 369                      $response->add_link( $rel, $self );
 370                  }
 371              }
 372          }
 373  
 374          return $response;
 375      }
 376  
 377      /**
 378       * Prepares links for the request.
 379       *
 380       * @since 5.9.0
 381       * @since 6.3.0 Adds revisions count and rest URL href to version-history.
 382       *
 383       * @param integer $id ID.
 384       * @return array Links for the given post.
 385       */
 386  	protected function prepare_links( $id ) {
 387          $base = sprintf( '%s/%s', $this->namespace, $this->rest_base );
 388  
 389          $links = array(
 390              'self'  => array(
 391                  'href' => rest_url( trailingslashit( $base ) . $id ),
 392              ),
 393              'about' => array(
 394                  'href' => rest_url( 'wp/v2/types/' . $this->post_type ),
 395              ),
 396          );
 397  
 398          if ( post_type_supports( $this->post_type, 'revisions' ) ) {
 399              $revisions                = wp_get_latest_revision_id_and_total_count( $id );
 400              $revisions_count          = ! is_wp_error( $revisions ) ? $revisions['count'] : 0;
 401              $revisions_base           = sprintf( '/%s/%d/revisions', $base, $id );
 402              $links['version-history'] = array(
 403                  'href'  => rest_url( $revisions_base ),
 404                  'count' => $revisions_count,
 405              );
 406          }
 407  
 408          return $links;
 409      }
 410  
 411      /**
 412       * Get the link relations available for the post and current user.
 413       *
 414       * @since 5.9.0
 415       * @since 6.2.0 Added 'edit-css' action.
 416       * @since 6.6.0 Added $post and $request parameters.
 417       *
 418       * @param WP_Post         $post    Post object.
 419       * @param WP_REST_Request $request Request object.
 420       * @return array List of link relations.
 421       */
 422  	protected function get_available_actions( $post, $request ) {
 423          $rels = array();
 424  
 425          $post_type = get_post_type_object( $post->post_type );
 426          if ( current_user_can( $post_type->cap->publish_posts ) ) {
 427              $rels[] = 'https://api.w.org/action-publish';
 428          }
 429  
 430          if ( current_user_can( 'edit_css' ) ) {
 431              $rels[] = 'https://api.w.org/action-edit-css';
 432          }
 433  
 434          return $rels;
 435      }
 436  
 437      /**
 438       * Retrieves the query params for the global styles collection.
 439       *
 440       * @since 5.9.0
 441       *
 442       * @return array Collection parameters.
 443       */
 444  	public function get_collection_params() {
 445          return array();
 446      }
 447  
 448      /**
 449       * Retrieves the global styles type' schema, conforming to JSON Schema.
 450       *
 451       * @since 5.9.0
 452       *
 453       * @return array Item schema data.
 454       */
 455  	public function get_item_schema() {
 456          if ( $this->schema ) {
 457              return $this->add_additional_fields_schema( $this->schema );
 458          }
 459  
 460          $schema = array(
 461              '$schema'    => 'http://json-schema.org/draft-04/schema#',
 462              'title'      => $this->post_type,
 463              'type'       => 'object',
 464              'properties' => array(
 465                  'id'       => array(
 466                      'description' => __( 'ID of global styles config.' ),
 467                      'type'        => 'string',
 468                      'context'     => array( 'embed', 'view', 'edit' ),
 469                      'readonly'    => true,
 470                  ),
 471                  'styles'   => array(
 472                      'description' => __( 'Global styles.' ),
 473                      'type'        => array( 'object' ),
 474                      'context'     => array( 'view', 'edit' ),
 475                  ),
 476                  'settings' => array(
 477                      'description' => __( 'Global settings.' ),
 478                      'type'        => array( 'object' ),
 479                      'context'     => array( 'view', 'edit' ),
 480                  ),
 481                  'title'    => array(
 482                      'description' => __( 'Title of the global styles variation.' ),
 483                      'type'        => array( 'object', 'string' ),
 484                      'default'     => '',
 485                      'context'     => array( 'embed', 'view', 'edit' ),
 486                      'properties'  => array(
 487                          'raw'      => array(
 488                              'description' => __( 'Title for the global styles variation, as it exists in the database.' ),
 489                              'type'        => 'string',
 490                              'context'     => array( 'view', 'edit', 'embed' ),
 491                          ),
 492                          'rendered' => array(
 493                              'description' => __( 'HTML title for the post, transformed for display.' ),
 494                              'type'        => 'string',
 495                              'context'     => array( 'view', 'edit', 'embed' ),
 496                              'readonly'    => true,
 497                          ),
 498                      ),
 499                  ),
 500              ),
 501          );
 502  
 503          $this->schema = $schema;
 504  
 505          return $this->add_additional_fields_schema( $this->schema );
 506      }
 507  
 508      /**
 509       * Checks if a given request has access to read a single theme global styles config.
 510       *
 511       * @since 5.9.0
 512       * @since 6.7.0 Allow users with edit post capabilities to view theme global styles.
 513       *
 514       * @param WP_REST_Request $request Full details about the request.
 515       * @return true|WP_Error True if the request has read access for the item, WP_Error object otherwise.
 516       */
 517  	public function get_theme_item_permissions_check( $request ) {
 518          /*
 519           * Verify if the current user has edit_posts capability.
 520           * This capability is required to view global styles.
 521           */
 522          if ( current_user_can( 'edit_posts' ) ) {
 523              return true;
 524          }
 525  
 526          foreach ( get_post_types( array( 'show_in_rest' => true ), 'objects' ) as $post_type ) {
 527              if ( current_user_can( $post_type->cap->edit_posts ) ) {
 528                  return true;
 529              }
 530          }
 531  
 532          /*
 533           * Verify if the current user has edit_theme_options capability.
 534           */
 535          if ( current_user_can( 'edit_theme_options' ) ) {
 536              return true;
 537          }
 538  
 539          return new WP_Error(
 540              'rest_cannot_read_global_styles',
 541              __( 'Sorry, you are not allowed to access the global styles on this site.' ),
 542              array(
 543                  'status' => rest_authorization_required_code(),
 544              )
 545          );
 546      }
 547  
 548      /**
 549       * Returns the given theme global styles config.
 550       *
 551       * @since 5.9.0
 552       * @since 6.6.0 Added custom relative theme file URIs to `_links`.
 553       *
 554       * @param WP_REST_Request $request The request instance.
 555       * @return WP_REST_Response|WP_Error
 556       */
 557  	public function get_theme_item( $request ) {
 558          if ( get_stylesheet() !== $request['stylesheet'] ) {
 559              // This endpoint only supports the active theme for now.
 560              return new WP_Error(
 561                  'rest_theme_not_found',
 562                  __( 'Theme not found.' ),
 563                  array( 'status' => 404 )
 564              );
 565          }
 566  
 567          $theme  = WP_Theme_JSON_Resolver::get_merged_data( 'theme' );
 568          $fields = $this->get_fields_for_response( $request );
 569          $data   = array();
 570  
 571          if ( rest_is_field_included( 'settings', $fields ) ) {
 572              $data['settings'] = $theme->get_settings();
 573          }
 574  
 575          if ( rest_is_field_included( 'styles', $fields ) ) {
 576              $raw_data       = $theme->get_raw_data();
 577              $data['styles'] = isset( $raw_data['styles'] ) ? $raw_data['styles'] : array();
 578          }
 579  
 580          $context = ! empty( $request['context'] ) ? $request['context'] : 'view';
 581          $data    = $this->add_additional_fields_to_object( $data, $request );
 582          $data    = $this->filter_response_by_context( $data, $context );
 583  
 584          $response = rest_ensure_response( $data );
 585  
 586          if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) {
 587              $links               = array(
 588                  'self' => array(
 589                      'href' => rest_url( sprintf( '%s/%s/themes/%s', $this->namespace, $this->rest_base, $request['stylesheet'] ) ),
 590                  ),
 591              );
 592              $resolved_theme_uris = WP_Theme_JSON_Resolver::get_resolved_theme_uris( $theme );
 593              if ( ! empty( $resolved_theme_uris ) ) {
 594                  $links['https://api.w.org/theme-file'] = $resolved_theme_uris;
 595              }
 596              $response->add_links( $links );
 597          }
 598  
 599          return $response;
 600      }
 601  
 602      /**
 603       * Checks if a given request has access to read a single theme global styles config.
 604       *
 605       * @since 6.0.0
 606       * @since 6.7.0 Allow users with edit post capabilities to view theme global styles.
 607       *
 608       * @param WP_REST_Request $request Full details about the request.
 609       * @return true|WP_Error True if the request has read access for the item, WP_Error object otherwise.
 610       */
 611  	public function get_theme_items_permissions_check( $request ) {
 612          return $this->get_theme_item_permissions_check( $request );
 613      }
 614  
 615      /**
 616       * Returns the given theme global styles variations.
 617       *
 618       * @since 6.0.0
 619       * @since 6.2.0 Returns parent theme variations, if they exist.
 620       * @since 6.6.0 Added custom relative theme file URIs to `_links` for each item.
 621       *
 622       * @param WP_REST_Request $request The request instance.
 623       *
 624       * @return WP_REST_Response|WP_Error
 625       */
 626  	public function get_theme_items( $request ) {
 627          if ( get_stylesheet() !== $request['stylesheet'] ) {
 628              // This endpoint only supports the active theme for now.
 629              return new WP_Error(
 630                  'rest_theme_not_found',
 631                  __( 'Theme not found.' ),
 632                  array( 'status' => 404 )
 633              );
 634          }
 635  
 636          $response = array();
 637  
 638          // Register theme-defined variations e.g. from block style variation partials under `/styles`.
 639          $partials = WP_Theme_JSON_Resolver::get_style_variations( 'block' );
 640          wp_register_block_style_variations_from_theme_json_partials( $partials );
 641  
 642          $variations = WP_Theme_JSON_Resolver::get_style_variations();
 643          foreach ( $variations as $variation ) {
 644              $variation_theme_json = new WP_Theme_JSON( $variation );
 645              $resolved_theme_uris  = WP_Theme_JSON_Resolver::get_resolved_theme_uris( $variation_theme_json );
 646              $data                 = rest_ensure_response( $variation );
 647              if ( ! empty( $resolved_theme_uris ) ) {
 648                  $data->add_links(
 649                      array(
 650                          'https://api.w.org/theme-file' => $resolved_theme_uris,
 651                      )
 652                  );
 653              }
 654              $response[] = $this->prepare_response_for_collection( $data );
 655          }
 656  
 657          return rest_ensure_response( $response );
 658      }
 659  
 660      /**
 661       * Validate style.css as valid CSS.
 662       *
 663       * Currently just checks for invalid markup.
 664       *
 665       * @since 6.2.0
 666       * @since 6.4.0 Changed method visibility to protected.
 667       *
 668       * @param string $css CSS to validate.
 669       * @return true|WP_Error True if the input was validated, otherwise WP_Error.
 670       */
 671  	protected function validate_custom_css( $css ) {
 672          if ( preg_match( '#</?\w+#', $css ) ) {
 673              return new WP_Error(
 674                  'rest_custom_css_illegal_markup',
 675                  __( 'Markup is not allowed in CSS.' ),
 676                  array( 'status' => 400 )
 677              );
 678          }
 679          return true;
 680      }
 681  }


Generated : Thu Oct 24 08:20:01 2024 Cross-referenced by PHPXref