[ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * REST API: WP_REST_Sidebars_Controller class 4 * 5 * Original code from {@link https://github.com/martin-pettersson/wp-rest-api-sidebars Martin Pettersson (martin_pettersson@outlook.com)}. 6 * 7 * @package WordPress 8 * @subpackage REST_API 9 * @since 5.8.0 10 */ 11 12 /** 13 * Core class used to manage a site's sidebars. 14 * 15 * @since 5.8.0 16 * 17 * @see WP_REST_Controller 18 */ 19 class WP_REST_Sidebars_Controller extends WP_REST_Controller { 20 21 /** 22 * Tracks whether {@see retrieve_widgets()} has been called in the current request. 23 * 24 * @since 5.9.0 25 * @var bool 26 */ 27 protected $widgets_retrieved = false; 28 29 /** 30 * Sidebars controller constructor. 31 * 32 * @since 5.8.0 33 */ 34 public function __construct() { 35 $this->namespace = 'wp/v2'; 36 $this->rest_base = 'sidebars'; 37 } 38 39 /** 40 * Registers the controllers routes. 41 * 42 * @since 5.8.0 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' => array( 54 'context' => $this->get_context_param( array( 'default' => 'view' ) ), 55 ), 56 ), 57 'schema' => array( $this, 'get_public_item_schema' ), 58 ) 59 ); 60 61 register_rest_route( 62 $this->namespace, 63 '/' . $this->rest_base . '/(?P<id>[\w-]+)', 64 array( 65 array( 66 'methods' => WP_REST_Server::READABLE, 67 'callback' => array( $this, 'get_item' ), 68 'permission_callback' => array( $this, 'get_item_permissions_check' ), 69 'args' => array( 70 'id' => array( 71 'description' => __( 'The id of a registered sidebar' ), 72 'type' => 'string', 73 ), 74 'context' => $this->get_context_param( array( 'default' => 'view' ) ), 75 ), 76 ), 77 array( 78 'methods' => WP_REST_Server::EDITABLE, 79 'callback' => array( $this, 'update_item' ), 80 'permission_callback' => array( $this, 'update_item_permissions_check' ), 81 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), 82 ), 83 'schema' => array( $this, 'get_public_item_schema' ), 84 ) 85 ); 86 } 87 88 /** 89 * Checks if a given request has access to get sidebars. 90 * 91 * @since 5.8.0 92 * 93 * @param WP_REST_Request $request Full details about the request. 94 * @return true|WP_Error True if the request has read access, WP_Error object otherwise. 95 */ 96 public function get_items_permissions_check( $request ) { 97 $this->retrieve_widgets(); 98 foreach ( wp_get_sidebars_widgets() as $id => $widgets ) { 99 $sidebar = $this->get_sidebar( $id ); 100 101 if ( ! $sidebar ) { 102 continue; 103 } 104 105 if ( $this->check_read_permission( $sidebar ) ) { 106 return true; 107 } 108 } 109 110 return $this->do_permissions_check(); 111 } 112 113 /** 114 * Retrieves the list of sidebars (active or inactive). 115 * 116 * @since 5.8.0 117 * 118 * @param WP_REST_Request $request Full details about the request. 119 * @return WP_REST_Response Response object on success. 120 */ 121 public function get_items( $request ) { 122 $this->retrieve_widgets(); 123 124 $data = array(); 125 $permissions_check = $this->do_permissions_check(); 126 127 foreach ( wp_get_sidebars_widgets() as $id => $widgets ) { 128 $sidebar = $this->get_sidebar( $id ); 129 130 if ( ! $sidebar ) { 131 continue; 132 } 133 134 if ( is_wp_error( $permissions_check ) && ! $this->check_read_permission( $sidebar ) ) { 135 continue; 136 } 137 138 $data[] = $this->prepare_response_for_collection( 139 $this->prepare_item_for_response( $sidebar, $request ) 140 ); 141 } 142 143 return rest_ensure_response( $data ); 144 } 145 146 /** 147 * Checks if a given request has access to get a single sidebar. 148 * 149 * @since 5.8.0 150 * 151 * @param WP_REST_Request $request Full details about the request. 152 * @return true|WP_Error True if the request has read access, WP_Error object otherwise. 153 */ 154 public function get_item_permissions_check( $request ) { 155 $this->retrieve_widgets(); 156 157 $sidebar = $this->get_sidebar( $request['id'] ); 158 if ( $sidebar && $this->check_read_permission( $sidebar ) ) { 159 return true; 160 } 161 162 return $this->do_permissions_check(); 163 } 164 165 /** 166 * Checks if a sidebar can be read publicly. 167 * 168 * @since 5.9.0 169 * 170 * @param array $sidebar The registered sidebar configuration. 171 * @return bool Whether the side can be read. 172 */ 173 protected function check_read_permission( $sidebar ) { 174 return ! empty( $sidebar['show_in_rest'] ); 175 } 176 177 /** 178 * Retrieves one sidebar from the collection. 179 * 180 * @since 5.8.0 181 * 182 * @param WP_REST_Request $request Full details about the request. 183 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. 184 */ 185 public function get_item( $request ) { 186 $this->retrieve_widgets(); 187 188 $sidebar = $this->get_sidebar( $request['id'] ); 189 if ( ! $sidebar ) { 190 return new WP_Error( 'rest_sidebar_not_found', __( 'No sidebar exists with that id.' ), array( 'status' => 404 ) ); 191 } 192 193 return $this->prepare_item_for_response( $sidebar, $request ); 194 } 195 196 /** 197 * Checks if a given request has access to update sidebars. 198 * 199 * @since 5.8.0 200 * 201 * @param WP_REST_Request $request Full details about the request. 202 * @return true|WP_Error True if the request has read access, WP_Error object otherwise. 203 */ 204 public function update_item_permissions_check( $request ) { 205 return $this->do_permissions_check(); 206 } 207 208 /** 209 * Updates a sidebar. 210 * 211 * @since 5.8.0 212 * 213 * @param WP_REST_Request $request Full details about the request. 214 * @return WP_REST_Response Response object on success, or WP_Error object on failure. 215 */ 216 public function update_item( $request ) { 217 if ( isset( $request['widgets'] ) ) { 218 $sidebars = wp_get_sidebars_widgets(); 219 220 foreach ( $sidebars as $sidebar_id => $widgets ) { 221 foreach ( $widgets as $i => $widget_id ) { 222 // This automatically removes the passed widget IDs from any other sidebars in use. 223 if ( $sidebar_id !== $request['id'] && in_array( $widget_id, $request['widgets'], true ) ) { 224 unset( $sidebars[ $sidebar_id ][ $i ] ); 225 } 226 227 // This automatically removes omitted widget IDs to the inactive sidebar. 228 if ( $sidebar_id === $request['id'] && ! in_array( $widget_id, $request['widgets'], true ) ) { 229 $sidebars['wp_inactive_widgets'][] = $widget_id; 230 } 231 } 232 } 233 234 $sidebars[ $request['id'] ] = $request['widgets']; 235 236 wp_set_sidebars_widgets( $sidebars ); 237 } 238 239 $request['context'] = 'edit'; 240 241 $sidebar = $this->get_sidebar( $request['id'] ); 242 243 /** 244 * Fires after a sidebar is updated via the REST API. 245 * 246 * @since 5.8.0 247 * 248 * @param array $sidebar The updated sidebar. 249 * @param WP_REST_Request $request Request object. 250 */ 251 do_action( 'rest_save_sidebar', $sidebar, $request ); 252 253 return $this->prepare_item_for_response( $sidebar, $request ); 254 } 255 256 /** 257 * Checks if the user has permissions to make the request. 258 * 259 * @since 5.8.0 260 * 261 * @return true|WP_Error True if the request has read access, WP_Error object otherwise. 262 */ 263 protected function do_permissions_check() { 264 /* 265 * Verify if the current user has edit_theme_options capability. 266 * This capability is required to access the widgets screen. 267 */ 268 if ( ! current_user_can( 'edit_theme_options' ) ) { 269 return new WP_Error( 270 'rest_cannot_manage_widgets', 271 __( 'Sorry, you are not allowed to manage widgets on this site.' ), 272 array( 'status' => rest_authorization_required_code() ) 273 ); 274 } 275 276 return true; 277 } 278 279 /** 280 * Retrieves the registered sidebar with the given id. 281 * 282 * @since 5.8.0 283 * 284 * @param string|int $id ID of the sidebar. 285 * @return array|null The discovered sidebar, or null if it is not registered. 286 */ 287 protected function get_sidebar( $id ) { 288 return wp_get_sidebar( $id ); 289 } 290 291 /** 292 * Looks for "lost" widgets once per request. 293 * 294 * @since 5.9.0 295 * 296 * @see retrieve_widgets() 297 */ 298 protected function retrieve_widgets() { 299 if ( ! $this->widgets_retrieved ) { 300 retrieve_widgets(); 301 $this->widgets_retrieved = true; 302 } 303 } 304 305 /** 306 * Prepares a single sidebar output for response. 307 * 308 * @since 5.8.0 309 * @since 5.9.0 Renamed `$raw_sidebar` to `$item` to match parent class for PHP 8 named parameter support. 310 * 311 * @global array $wp_registered_sidebars The registered sidebars. 312 * @global array $wp_registered_widgets The registered widgets. 313 * 314 * @param array $item Sidebar instance. 315 * @param WP_REST_Request $request Full details about the request. 316 * @return WP_REST_Response Prepared response object. 317 */ 318 public function prepare_item_for_response( $item, $request ) { 319 global $wp_registered_sidebars, $wp_registered_widgets; 320 321 // Restores the more descriptive, specific name for use within this method. 322 $raw_sidebar = $item; 323 324 $id = $raw_sidebar['id']; 325 $sidebar = array( 'id' => $id ); 326 327 if ( isset( $wp_registered_sidebars[ $id ] ) ) { 328 $registered_sidebar = $wp_registered_sidebars[ $id ]; 329 330 $sidebar['status'] = 'active'; 331 $sidebar['name'] = isset( $registered_sidebar['name'] ) ? $registered_sidebar['name'] : ''; 332 $sidebar['description'] = isset( $registered_sidebar['description'] ) ? wp_sidebar_description( $id ) : ''; 333 $sidebar['class'] = isset( $registered_sidebar['class'] ) ? $registered_sidebar['class'] : ''; 334 $sidebar['before_widget'] = isset( $registered_sidebar['before_widget'] ) ? $registered_sidebar['before_widget'] : ''; 335 $sidebar['after_widget'] = isset( $registered_sidebar['after_widget'] ) ? $registered_sidebar['after_widget'] : ''; 336 $sidebar['before_title'] = isset( $registered_sidebar['before_title'] ) ? $registered_sidebar['before_title'] : ''; 337 $sidebar['after_title'] = isset( $registered_sidebar['after_title'] ) ? $registered_sidebar['after_title'] : ''; 338 } else { 339 $sidebar['status'] = 'inactive'; 340 $sidebar['name'] = $raw_sidebar['name']; 341 $sidebar['description'] = ''; 342 $sidebar['class'] = ''; 343 } 344 345 if ( wp_is_block_theme() ) { 346 $sidebar['status'] = 'inactive'; 347 } 348 349 $fields = $this->get_fields_for_response( $request ); 350 if ( rest_is_field_included( 'widgets', $fields ) ) { 351 $sidebars = wp_get_sidebars_widgets(); 352 $widgets = array_filter( 353 isset( $sidebars[ $sidebar['id'] ] ) ? $sidebars[ $sidebar['id'] ] : array(), 354 static function ( $widget_id ) use ( $wp_registered_widgets ) { 355 return isset( $wp_registered_widgets[ $widget_id ] ); 356 } 357 ); 358 359 $sidebar['widgets'] = array_values( $widgets ); 360 } 361 362 $schema = $this->get_item_schema(); 363 $data = array(); 364 foreach ( $schema['properties'] as $property_id => $property ) { 365 if ( isset( $sidebar[ $property_id ] ) && true === rest_validate_value_from_schema( $sidebar[ $property_id ], $property ) ) { 366 $data[ $property_id ] = $sidebar[ $property_id ]; 367 } elseif ( isset( $property['default'] ) ) { 368 $data[ $property_id ] = $property['default']; 369 } 370 } 371 372 $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; 373 $data = $this->add_additional_fields_to_object( $data, $request ); 374 $data = $this->filter_response_by_context( $data, $context ); 375 376 $response = rest_ensure_response( $data ); 377 378 if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) { 379 $response->add_links( $this->prepare_links( $sidebar ) ); 380 } 381 382 /** 383 * Filters the REST API response for a sidebar. 384 * 385 * @since 5.8.0 386 * 387 * @param WP_REST_Response $response The response object. 388 * @param array $raw_sidebar The raw sidebar data. 389 * @param WP_REST_Request $request The request object. 390 */ 391 return apply_filters( 'rest_prepare_sidebar', $response, $raw_sidebar, $request ); 392 } 393 394 /** 395 * Prepares links for the sidebar. 396 * 397 * @since 5.8.0 398 * 399 * @param array $sidebar Sidebar. 400 * @return array Links for the given widget. 401 */ 402 protected function prepare_links( $sidebar ) { 403 return array( 404 'collection' => array( 405 'href' => rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ), 406 ), 407 'self' => array( 408 'href' => rest_url( sprintf( '%s/%s/%s', $this->namespace, $this->rest_base, $sidebar['id'] ) ), 409 ), 410 'https://api.w.org/widget' => array( 411 'href' => add_query_arg( 'sidebar', $sidebar['id'], rest_url( '/wp/v2/widgets' ) ), 412 'embeddable' => true, 413 ), 414 ); 415 } 416 417 /** 418 * Retrieves the block type' schema, conforming to JSON Schema. 419 * 420 * @since 5.8.0 421 * 422 * @return array Item schema data. 423 */ 424 public function get_item_schema() { 425 if ( $this->schema ) { 426 return $this->add_additional_fields_schema( $this->schema ); 427 } 428 429 $schema = array( 430 '$schema' => 'http://json-schema.org/draft-04/schema#', 431 'title' => 'sidebar', 432 'type' => 'object', 433 'properties' => array( 434 'id' => array( 435 'description' => __( 'ID of sidebar.' ), 436 'type' => 'string', 437 'context' => array( 'embed', 'view', 'edit' ), 438 'readonly' => true, 439 ), 440 'name' => array( 441 'description' => __( 'Unique name identifying the sidebar.' ), 442 'type' => 'string', 443 'context' => array( 'embed', 'view', 'edit' ), 444 'readonly' => true, 445 ), 446 'description' => array( 447 'description' => __( 'Description of sidebar.' ), 448 'type' => 'string', 449 'context' => array( 'embed', 'view', 'edit' ), 450 'readonly' => true, 451 ), 452 'class' => array( 453 'description' => __( 'Extra CSS class to assign to the sidebar in the Widgets interface.' ), 454 'type' => 'string', 455 'context' => array( 'embed', 'view', 'edit' ), 456 'readonly' => true, 457 ), 458 'before_widget' => array( 459 'description' => __( 'HTML content to prepend to each widget\'s HTML output when assigned to this sidebar. Default is an opening list item element.' ), 460 'type' => 'string', 461 'default' => '', 462 'context' => array( 'embed', 'view', 'edit' ), 463 'readonly' => true, 464 ), 465 'after_widget' => array( 466 'description' => __( 'HTML content to append to each widget\'s HTML output when assigned to this sidebar. Default is a closing list item element.' ), 467 'type' => 'string', 468 'default' => '', 469 'context' => array( 'embed', 'view', 'edit' ), 470 'readonly' => true, 471 ), 472 'before_title' => array( 473 'description' => __( 'HTML content to prepend to the sidebar title when displayed. Default is an opening h2 element.' ), 474 'type' => 'string', 475 'default' => '', 476 'context' => array( 'embed', 'view', 'edit' ), 477 'readonly' => true, 478 ), 479 'after_title' => array( 480 'description' => __( 'HTML content to append to the sidebar title when displayed. Default is a closing h2 element.' ), 481 'type' => 'string', 482 'default' => '', 483 'context' => array( 'embed', 'view', 'edit' ), 484 'readonly' => true, 485 ), 486 'status' => array( 487 'description' => __( 'Status of sidebar.' ), 488 'type' => 'string', 489 'enum' => array( 'active', 'inactive' ), 490 'context' => array( 'embed', 'view', 'edit' ), 491 'readonly' => true, 492 ), 493 'widgets' => array( 494 'description' => __( 'Nested widgets.' ), 495 'type' => 'array', 496 'items' => array( 497 'type' => array( 'object', 'string' ), 498 ), 499 'default' => array(), 500 'context' => array( 'embed', 'view', 'edit' ), 501 ), 502 ), 503 ); 504 505 $this->schema = $schema; 506 507 return $this->add_additional_fields_schema( $this->schema ); 508 } 509 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated : Thu Nov 21 08:20:01 2024 | Cross-referenced by PHPXref |