| [ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * REST API: WP_REST_Themes_Controller class 4 * 5 * @package WordPress 6 * @subpackage REST_API 7 * @since 5.0.0 8 */ 9 10 /** 11 * Core class used to manage themes via the REST API. 12 * 13 * @since 5.0.0 14 * 15 * @see WP_REST_Controller 16 */ 17 class WP_REST_Themes_Controller extends WP_REST_Controller { 18 19 /** 20 * Matches theme's directory: `/themes/<subdirectory>/<theme>/` or `/themes/<theme>/`. 21 * Excludes invalid directory name characters: `/:<>*?"|`. 22 * 23 * @since 5.9.0 24 */ 25 const PATTERN = '[^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?'; 26 27 /** 28 * Constructor. 29 * 30 * @since 5.0.0 31 */ 32 public function __construct() { 33 $this->namespace = 'wp/v2'; 34 $this->rest_base = 'themes'; 35 } 36 37 /** 38 * Registers the routes for themes. 39 * 40 * @since 5.0.0 41 * 42 * @see register_rest_route() 43 */ 44 public function register_routes() { 45 register_rest_route( 46 $this->namespace, 47 '/' . $this->rest_base, 48 array( 49 array( 50 'methods' => WP_REST_Server::READABLE, 51 'callback' => array( $this, 'get_items' ), 52 'permission_callback' => array( $this, 'get_items_permissions_check' ), 53 'args' => $this->get_collection_params(), 54 ), 55 'schema' => array( $this, 'get_item_schema' ), 56 ) 57 ); 58 59 register_rest_route( 60 $this->namespace, 61 sprintf( '/%s/(?P<stylesheet>%s)', $this->rest_base, self::PATTERN ), 62 array( 63 'args' => array( 64 'stylesheet' => array( 65 'description' => __( "The theme's stylesheet. This uniquely identifies the theme." ), 66 'type' => 'string', 67 'sanitize_callback' => array( $this, '_sanitize_stylesheet_callback' ), 68 ), 69 ), 70 array( 71 'methods' => WP_REST_Server::READABLE, 72 'callback' => array( $this, 'get_item' ), 73 'permission_callback' => array( $this, 'get_item_permissions_check' ), 74 ), 75 'schema' => array( $this, 'get_public_item_schema' ), 76 ) 77 ); 78 } 79 80 /** 81 * Sanitize the stylesheet to decode endpoint. 82 * 83 * @since 5.9.0 84 * 85 * @param string $stylesheet The stylesheet name. 86 * @return string Sanitized stylesheet. 87 */ 88 public function _sanitize_stylesheet_callback( $stylesheet ) { 89 return urldecode( $stylesheet ); 90 } 91 92 /** 93 * Checks if a given request has access to read the theme. 94 * 95 * @since 5.0.0 96 * 97 * @param WP_REST_Request $request Full details about the request. 98 * @return true|WP_Error True if the request has read access for the item, otherwise WP_Error object. 99 */ 100 public function get_items_permissions_check( $request ) { 101 if ( current_user_can( 'switch_themes' ) || current_user_can( 'manage_network_themes' ) ) { 102 return true; 103 } 104 105 $registered = $this->get_collection_params(); 106 if ( isset( $registered['status'], $request['status'] ) && is_array( $request['status'] ) && array( 'active' ) === $request['status'] ) { 107 return $this->check_read_active_theme_permission(); 108 } 109 110 return new WP_Error( 111 'rest_cannot_view_themes', 112 __( 'Sorry, you are not allowed to view themes.' ), 113 array( 'status' => rest_authorization_required_code() ) 114 ); 115 } 116 117 /** 118 * Checks if a given request has access to read the theme. 119 * 120 * @since 5.7.0 121 * 122 * @param WP_REST_Request $request Full details about the request. 123 * @return true|WP_Error True if the request has read access for the item, otherwise WP_Error object. 124 */ 125 public function get_item_permissions_check( $request ) { 126 if ( current_user_can( 'switch_themes' ) || current_user_can( 'manage_network_themes' ) ) { 127 return true; 128 } 129 130 $wp_theme = wp_get_theme( $request['stylesheet'] ); 131 $current_theme = wp_get_theme(); 132 133 if ( $this->is_same_theme( $wp_theme, $current_theme ) ) { 134 return $this->check_read_active_theme_permission(); 135 } 136 137 return new WP_Error( 138 'rest_cannot_view_themes', 139 __( 'Sorry, you are not allowed to view themes.' ), 140 array( 'status' => rest_authorization_required_code() ) 141 ); 142 } 143 144 /** 145 * Checks if a theme can be read. 146 * 147 * @since 5.7.0 148 * 149 * @return true|WP_Error True if the theme can be read, WP_Error object otherwise. 150 */ 151 protected function check_read_active_theme_permission() { 152 if ( current_user_can( 'edit_posts' ) ) { 153 return true; 154 } 155 156 foreach ( get_post_types( array( 'show_in_rest' => true ), 'objects' ) as $post_type ) { 157 if ( current_user_can( $post_type->cap->edit_posts ) ) { 158 return true; 159 } 160 } 161 162 return new WP_Error( 163 'rest_cannot_view_active_theme', 164 __( 'Sorry, you are not allowed to view the active theme.' ), 165 array( 'status' => rest_authorization_required_code() ) 166 ); 167 } 168 169 /** 170 * Retrieves a single theme. 171 * 172 * @since 5.7.0 173 * 174 * @param WP_REST_Request $request Full details about the request. 175 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. 176 */ 177 public function get_item( $request ) { 178 $wp_theme = wp_get_theme( $request['stylesheet'] ); 179 if ( ! $wp_theme->exists() ) { 180 return new WP_Error( 181 'rest_theme_not_found', 182 __( 'Theme not found.' ), 183 array( 'status' => 404 ) 184 ); 185 } 186 $data = $this->prepare_item_for_response( $wp_theme, $request ); 187 188 return rest_ensure_response( $data ); 189 } 190 191 /** 192 * Retrieves a collection of themes. 193 * 194 * @since 5.0.0 195 * 196 * @param WP_REST_Request $request Full details about the request. 197 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. 198 */ 199 public function get_items( $request ) { 200 $themes = array(); 201 202 $current_theme = wp_get_theme(); 203 $status = $request['status']; 204 205 if ( array( 'active' ) === $status ) { 206 $prepared = $this->prepare_item_for_response( $current_theme, $request ); 207 $themes[] = $this->prepare_response_for_collection( $prepared ); 208 } else { 209 foreach ( wp_get_themes() as $theme ) { 210 $theme_status = ( $this->is_same_theme( $theme, $current_theme ) ) ? 'active' : 'inactive'; 211 if ( is_array( $status ) && ! in_array( $theme_status, $status, true ) ) { 212 continue; 213 } 214 215 $prepared = $this->prepare_item_for_response( $theme, $request ); 216 $themes[] = $this->prepare_response_for_collection( $prepared ); 217 } 218 } 219 220 $response = rest_ensure_response( $themes ); 221 222 $response->header( 'X-WP-Total', count( $themes ) ); 223 $response->header( 'X-WP-TotalPages', 1 ); 224 225 return $response; 226 } 227 228 /** 229 * Prepares a single theme output for response. 230 * 231 * @since 5.0.0 232 * @since 5.9.0 Renamed `$theme` to `$item` to match parent class for PHP 8 named parameter support. 233 * @since 6.6.0 Added `stylesheet_uri` and `template_uri` fields. 234 * 235 * @param WP_Theme $item Theme object. 236 * @param WP_REST_Request $request Request object. 237 * @return WP_REST_Response Response object. 238 */ 239 public function prepare_item_for_response( $item, $request ) { 240 // Restores the more descriptive, specific name for use within this method. 241 $theme = $item; 242 243 $fields = $this->get_fields_for_response( $request ); 244 $data = array(); 245 246 if ( rest_is_field_included( 'stylesheet', $fields ) ) { 247 $data['stylesheet'] = $theme->get_stylesheet(); 248 } 249 250 if ( rest_is_field_included( 'template', $fields ) ) { 251 /** 252 * Use the get_template() method, not the 'Template' header, for finding the template. 253 * The 'Template' header is only good for what was written in the style.css, while 254 * get_template() takes into account where WordPress actually located the theme and 255 * whether it is actually valid. 256 */ 257 $data['template'] = $theme->get_template(); 258 } 259 260 $plain_field_mappings = array( 261 'requires_php' => 'RequiresPHP', 262 'requires_wp' => 'RequiresWP', 263 'textdomain' => 'TextDomain', 264 'version' => 'Version', 265 ); 266 267 foreach ( $plain_field_mappings as $field => $header ) { 268 if ( rest_is_field_included( $field, $fields ) ) { 269 $data[ $field ] = $theme->get( $header ); 270 } 271 } 272 273 if ( rest_is_field_included( 'screenshot', $fields ) ) { 274 // Using $theme->get_screenshot() with no args to get absolute URL. 275 $data['screenshot'] = $theme->get_screenshot() ? $theme->get_screenshot() : ''; 276 } 277 278 $rich_field_mappings = array( 279 'author' => 'Author', 280 'author_uri' => 'AuthorURI', 281 'description' => 'Description', 282 'name' => 'Name', 283 'tags' => 'Tags', 284 'theme_uri' => 'ThemeURI', 285 ); 286 287 foreach ( $rich_field_mappings as $field => $header ) { 288 if ( rest_is_field_included( "{$field}.raw", $fields ) ) { 289 $data[ $field ]['raw'] = $theme->display( $header, false, true ); 290 } 291 292 if ( rest_is_field_included( "{$field}.rendered", $fields ) ) { 293 $data[ $field ]['rendered'] = $theme->display( $header ); 294 } 295 } 296 297 $current_theme = wp_get_theme(); 298 if ( rest_is_field_included( 'status', $fields ) ) { 299 $data['status'] = ( $this->is_same_theme( $theme, $current_theme ) ) ? 'active' : 'inactive'; 300 } 301 302 if ( rest_is_field_included( 'theme_supports', $fields ) && $this->is_same_theme( $theme, $current_theme ) ) { 303 foreach ( get_registered_theme_features() as $feature => $config ) { 304 if ( ! is_array( $config['show_in_rest'] ) ) { 305 continue; 306 } 307 308 $name = $config['show_in_rest']['name']; 309 310 if ( ! rest_is_field_included( "theme_supports.{$name}", $fields ) ) { 311 continue; 312 } 313 314 if ( ! current_theme_supports( $feature ) ) { 315 $data['theme_supports'][ $name ] = $config['show_in_rest']['schema']['default']; 316 continue; 317 } 318 319 $support = get_theme_support( $feature ); 320 321 if ( isset( $config['show_in_rest']['prepare_callback'] ) ) { 322 $prepare = $config['show_in_rest']['prepare_callback']; 323 } else { 324 $prepare = array( $this, 'prepare_theme_support' ); 325 } 326 327 $prepared = $prepare( $support, $config, $feature, $request ); 328 329 if ( is_wp_error( $prepared ) ) { 330 continue; 331 } 332 333 $data['theme_supports'][ $name ] = $prepared; 334 } 335 } 336 337 if ( rest_is_field_included( 'is_block_theme', $fields ) ) { 338 $data['is_block_theme'] = $theme->is_block_theme(); 339 } 340 341 if ( rest_is_field_included( 'stylesheet_uri', $fields ) ) { 342 if ( $this->is_same_theme( $theme, $current_theme ) ) { 343 $data['stylesheet_uri'] = get_stylesheet_directory_uri(); 344 } else { 345 $data['stylesheet_uri'] = $theme->get_stylesheet_directory_uri(); 346 } 347 } 348 349 if ( rest_is_field_included( 'template_uri', $fields ) ) { 350 if ( $this->is_same_theme( $theme, $current_theme ) ) { 351 $data['template_uri'] = get_template_directory_uri(); 352 } else { 353 $data['template_uri'] = $theme->get_template_directory_uri(); 354 } 355 } 356 357 if ( rest_is_field_included( 'default_template_types', $fields ) && $this->is_same_theme( $theme, $current_theme ) ) { 358 $default_template_types = array(); 359 foreach ( get_default_block_template_types() as $slug => $template_type ) { 360 $template_type['slug'] = (string) $slug; 361 $default_template_types[] = $template_type; 362 } 363 $data['default_template_types'] = $default_template_types; 364 } 365 366 if ( rest_is_field_included( 'default_template_part_areas', $fields ) && $this->is_same_theme( $theme, $current_theme ) ) { 367 $data['default_template_part_areas'] = get_allowed_block_template_part_areas(); 368 } 369 370 $data = $this->add_additional_fields_to_object( $data, $request ); 371 372 // Wrap the data in a response object. 373 $response = rest_ensure_response( $data ); 374 375 if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) { 376 $response->add_links( $this->prepare_links( $theme ) ); 377 } 378 379 /** 380 * Filters theme data returned from the REST API. 381 * 382 * @since 5.0.0 383 * 384 * @param WP_REST_Response $response The response object. 385 * @param WP_Theme $theme Theme object used to create response. 386 * @param WP_REST_Request $request Request object. 387 */ 388 return apply_filters( 'rest_prepare_theme', $response, $theme, $request ); 389 } 390 391 /** 392 * Prepares links for the request. 393 * 394 * @since 5.7.0 395 * 396 * @param WP_Theme $theme Theme data. 397 * @return array Links for the given block type. 398 */ 399 protected function prepare_links( $theme ) { 400 $links = array( 401 'self' => array( 402 'href' => rest_url( sprintf( '%s/%s/%s', $this->namespace, $this->rest_base, $theme->get_stylesheet() ) ), 403 ), 404 'collection' => array( 405 'href' => rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ), 406 ), 407 ); 408 409 if ( $this->is_same_theme( $theme, wp_get_theme() ) ) { 410 // This creates a record for the active theme if not existent. 411 $id = WP_Theme_JSON_Resolver::get_user_global_styles_post_id(); 412 } else { 413 $user_cpt = WP_Theme_JSON_Resolver::get_user_data_from_wp_global_styles( $theme ); 414 $id = $user_cpt['ID'] ?? null; 415 } 416 417 if ( $id ) { 418 $links['https://api.w.org/user-global-styles'] = array( 419 'href' => rest_url( 'wp/v2/global-styles/' . $id ), 420 ); 421 } 422 423 if ( $theme->is_block_theme() && $this->is_same_theme( $theme, wp_get_theme() ) ) { 424 $links['https://api.w.org/export-theme'] = array( 425 'href' => rest_url( 'wp-block-editor/v1/export' ), 426 'targetHints' => array( 427 'allow' => current_user_can( 'export' ) ? array( 'GET' ) : array(), 428 ), 429 ); 430 } 431 432 return $links; 433 } 434 435 /** 436 * Helper function to compare two themes. 437 * 438 * @since 5.7.0 439 * 440 * @param WP_Theme $theme_a First theme to compare. 441 * @param WP_Theme $theme_b Second theme to compare. 442 * @return bool 443 */ 444 protected function is_same_theme( $theme_a, $theme_b ) { 445 return $theme_a->get_stylesheet() === $theme_b->get_stylesheet(); 446 } 447 448 /** 449 * Prepares the theme support value for inclusion in the REST API response. 450 * 451 * @since 5.5.0 452 * 453 * @param mixed $support The raw value from get_theme_support(). 454 * @param array $args The feature's registration args. 455 * @param string $feature The feature name. 456 * @param WP_REST_Request $request The request object. 457 * @return mixed The prepared support value. 458 */ 459 protected function prepare_theme_support( $support, $args, $feature, $request ) { 460 $schema = $args['show_in_rest']['schema']; 461 462 if ( 'boolean' === $schema['type'] ) { 463 return true; 464 } 465 466 if ( is_array( $support ) && ! $args['variadic'] ) { 467 $support = $support[0]; 468 } 469 470 return rest_sanitize_value_from_schema( $support, $schema ); 471 } 472 473 /** 474 * Retrieves the theme's schema, conforming to JSON Schema. 475 * 476 * @since 5.0.0 477 * 478 * @return array Item schema data. 479 */ 480 public function get_item_schema() { 481 if ( $this->schema ) { 482 return $this->add_additional_fields_schema( $this->schema ); 483 } 484 485 $schema = array( 486 '$schema' => 'http://json-schema.org/draft-04/schema#', 487 'title' => 'theme', 488 'type' => 'object', 489 'properties' => array( 490 'stylesheet' => array( 491 'description' => __( 'The theme\'s stylesheet. This uniquely identifies the theme.' ), 492 'type' => 'string', 493 'readonly' => true, 494 ), 495 'stylesheet_uri' => array( 496 'description' => __( 'The uri for the theme\'s stylesheet directory.' ), 497 'type' => 'string', 498 'format' => 'uri', 499 'readonly' => true, 500 ), 501 'template' => array( 502 'description' => __( 'The theme\'s template. If this is a child theme, this refers to the parent theme, otherwise this is the same as the theme\'s stylesheet.' ), 503 'type' => 'string', 504 'readonly' => true, 505 ), 506 'template_uri' => array( 507 'description' => __( 'The uri for the theme\'s template directory. If this is a child theme, this refers to the parent theme, otherwise this is the same as the theme\'s stylesheet directory.' ), 508 'type' => 'string', 509 'format' => 'uri', 510 'readonly' => true, 511 ), 512 'author' => array( 513 'description' => __( 'The theme author.' ), 514 'type' => 'object', 515 'readonly' => true, 516 'properties' => array( 517 'raw' => array( 518 'description' => __( 'The theme author\'s name, as found in the theme header.' ), 519 'type' => 'string', 520 ), 521 'rendered' => array( 522 'description' => __( 'HTML for the theme author, transformed for display.' ), 523 'type' => 'string', 524 ), 525 ), 526 ), 527 'author_uri' => array( 528 'description' => __( 'The website of the theme author.' ), 529 'type' => 'object', 530 'readonly' => true, 531 'properties' => array( 532 'raw' => array( 533 'description' => __( 'The website of the theme author, as found in the theme header.' ), 534 'type' => 'string', 535 'format' => 'uri', 536 ), 537 'rendered' => array( 538 'description' => __( 'The website of the theme author, transformed for display.' ), 539 'type' => 'string', 540 'format' => 'uri', 541 ), 542 ), 543 ), 544 'description' => array( 545 'description' => __( 'A description of the theme.' ), 546 'type' => 'object', 547 'readonly' => true, 548 'properties' => array( 549 'raw' => array( 550 'description' => __( 'The theme description, as found in the theme header.' ), 551 'type' => 'string', 552 ), 553 'rendered' => array( 554 'description' => __( 'The theme description, transformed for display.' ), 555 'type' => 'string', 556 ), 557 ), 558 ), 559 'is_block_theme' => array( 560 'description' => __( 'Whether the theme is a block-based theme.' ), 561 'type' => 'boolean', 562 'readonly' => true, 563 ), 564 'name' => array( 565 'description' => __( 'The name of the theme.' ), 566 'type' => 'object', 567 'readonly' => true, 568 'properties' => array( 569 'raw' => array( 570 'description' => __( 'The theme name, as found in the theme header.' ), 571 'type' => 'string', 572 ), 573 'rendered' => array( 574 'description' => __( 'The theme name, transformed for display.' ), 575 'type' => 'string', 576 ), 577 ), 578 ), 579 'requires_php' => array( 580 'description' => __( 'The minimum PHP version required for the theme to work.' ), 581 'type' => 'string', 582 'readonly' => true, 583 ), 584 'requires_wp' => array( 585 'description' => __( 'The minimum WordPress version required for the theme to work.' ), 586 'type' => 'string', 587 'readonly' => true, 588 ), 589 'screenshot' => array( 590 'description' => __( 'The theme\'s screenshot URL.' ), 591 'type' => 'string', 592 'format' => 'uri', 593 'readonly' => true, 594 ), 595 'tags' => array( 596 'description' => __( 'Tags indicating styles and features of the theme.' ), 597 'type' => 'object', 598 'readonly' => true, 599 'properties' => array( 600 'raw' => array( 601 'description' => __( 'The theme tags, as found in the theme header.' ), 602 'type' => 'array', 603 'items' => array( 604 'type' => 'string', 605 ), 606 ), 607 'rendered' => array( 608 'description' => __( 'The theme tags, transformed for display.' ), 609 'type' => 'string', 610 ), 611 ), 612 ), 613 'textdomain' => array( 614 'description' => __( 'The theme\'s text domain.' ), 615 'type' => 'string', 616 'readonly' => true, 617 ), 618 'theme_supports' => array( 619 'description' => __( 'Features supported by this theme.' ), 620 'type' => 'object', 621 'readonly' => true, 622 'properties' => array(), 623 ), 624 'theme_uri' => array( 625 'description' => __( 'The URI of the theme\'s webpage.' ), 626 'type' => 'object', 627 'readonly' => true, 628 'properties' => array( 629 'raw' => array( 630 'description' => __( 'The URI of the theme\'s webpage, as found in the theme header.' ), 631 'type' => 'string', 632 'format' => 'uri', 633 ), 634 'rendered' => array( 635 'description' => __( 'The URI of the theme\'s webpage, transformed for display.' ), 636 'type' => 'string', 637 'format' => 'uri', 638 ), 639 ), 640 ), 641 'version' => array( 642 'description' => __( 'The theme\'s current version.' ), 643 'type' => 'string', 644 'readonly' => true, 645 ), 646 'status' => array( 647 'description' => __( 'A named status for the theme.' ), 648 'type' => 'string', 649 'enum' => array( 'inactive', 'active' ), 650 ), 651 'default_template_types' => array( 652 'description' => __( 'A list of default template types.' ), 653 'type' => 'array', 654 'readonly' => true, 655 'items' => array( 656 'type' => 'object', 657 'properties' => array( 658 'slug' => array( 659 'type' => 'string', 660 ), 661 'title' => array( 662 'type' => 'string', 663 ), 664 'description' => array( 665 'type' => 'string', 666 ), 667 ), 668 ), 669 ), 670 'default_template_part_areas' => array( 671 'description' => __( 'A list of allowed area values for template parts.' ), 672 'type' => 'array', 673 'readonly' => true, 674 'items' => array( 675 'type' => 'object', 676 'properties' => array( 677 'area' => array( 678 'type' => 'string', 679 ), 680 'label' => array( 681 'type' => 'string', 682 ), 683 'description' => array( 684 'type' => 'string', 685 ), 686 'icon' => array( 687 'type' => 'string', 688 ), 689 'area_tag' => array( 690 'type' => 'string', 691 ), 692 ), 693 ), 694 ), 695 ), 696 ); 697 698 foreach ( get_registered_theme_features() as $feature => $config ) { 699 if ( ! is_array( $config['show_in_rest'] ) ) { 700 continue; 701 } 702 703 $name = $config['show_in_rest']['name']; 704 705 $schema['properties']['theme_supports']['properties'][ $name ] = $config['show_in_rest']['schema']; 706 } 707 708 $this->schema = $schema; 709 710 return $this->add_additional_fields_schema( $this->schema ); 711 } 712 713 /** 714 * Retrieves the search params for the themes collection. 715 * 716 * @since 5.0.0 717 * 718 * @return array Collection parameters. 719 */ 720 public function get_collection_params() { 721 $query_params = array( 722 'status' => array( 723 'description' => __( 'Limit result set to themes assigned one or more statuses.' ), 724 'type' => 'array', 725 'items' => array( 726 'enum' => array( 'active', 'inactive' ), 727 'type' => 'string', 728 ), 729 ), 730 ); 731 732 /** 733 * Filters REST API collection parameters for the themes controller. 734 * 735 * @since 5.0.0 736 * 737 * @param array $query_params JSON Schema-formatted collection parameters. 738 */ 739 return apply_filters( 'rest_themes_collection_params', $query_params ); 740 } 741 742 /** 743 * Sanitizes and validates the list of theme status. 744 * 745 * @since 5.0.0 746 * @deprecated 5.7.0 747 * 748 * @param string|array $statuses One or more theme statuses. 749 * @param WP_REST_Request $request Full details about the request. 750 * @param string $parameter Additional parameter to pass to validation. 751 * @return array|WP_Error A list of valid statuses, otherwise WP_Error object. 752 */ 753 public function sanitize_theme_status( $statuses, $request, $parameter ) { 754 _deprecated_function( __METHOD__, '5.7.0' ); 755 756 $statuses = wp_parse_slug_list( $statuses ); 757 758 foreach ( $statuses as $status ) { 759 $result = rest_validate_request_arg( $status, $request, $parameter ); 760 761 if ( is_wp_error( $result ) ) { 762 return $result; 763 } 764 } 765 766 return $statuses; 767 } 768 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated : Thu Sep 24 08:20:34 2026 | Cross-referenced by PHPXref |