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