[ Index ] |
PHP Cross Reference of WordPress |
[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 // Verify if the current user has edit_theme_options capability. 265 // This capability is required to access the widgets screen. 266 if ( ! current_user_can( 'edit_theme_options' ) ) { 267 return new WP_Error( 268 'rest_cannot_manage_widgets', 269 __( 'Sorry, you are not allowed to manage widgets on this site.' ), 270 array( 'status' => rest_authorization_required_code() ) 271 ); 272 } 273 274 return true; 275 } 276 277 /** 278 * Retrieves the registered sidebar with the given id. 279 * 280 * @since 5.8.0 281 * 282 * @param string|int $id ID of the sidebar. 283 * @return array|null The discovered sidebar, or null if it is not registered. 284 */ 285 protected function get_sidebar( $id ) { 286 return wp_get_sidebar( $id ); 287 } 288 289 /** 290 * Looks for "lost" widgets once per request. 291 * 292 * @since 5.9.0 293 * 294 * @see retrieve_widgets() 295 */ 296 protected function retrieve_widgets() { 297 if ( ! $this->widgets_retrieved ) { 298 retrieve_widgets(); 299 $this->widgets_retrieved = true; 300 } 301 } 302 303 /** 304 * Prepares a single sidebar output for response. 305 * 306 * @since 5.8.0 307 * @since 5.9.0 Renamed `$raw_sidebar` to `$item` to match parent class for PHP 8 named parameter support. 308 * 309 * @global array $wp_registered_sidebars The registered sidebars. 310 * @global array $wp_registered_widgets The registered widgets. 311 * 312 * @param array $item Sidebar instance. 313 * @param WP_REST_Request $request Full details about the request. 314 * @return WP_REST_Response Prepared response object. 315 */ 316 public function prepare_item_for_response( $item, $request ) { 317 global $wp_registered_sidebars, $wp_registered_widgets; 318 319 // Restores the more descriptive, specific name for use within this method. 320 $raw_sidebar = $item; 321 $id = $raw_sidebar['id']; 322 $sidebar = array( 'id' => $id ); 323 324 if ( isset( $wp_registered_sidebars[ $id ] ) ) { 325 $registered_sidebar = $wp_registered_sidebars[ $id ]; 326 327 $sidebar['status'] = 'active'; 328 $sidebar['name'] = isset( $registered_sidebar['name'] ) ? $registered_sidebar['name'] : ''; 329 $sidebar['description'] = isset( $registered_sidebar['description'] ) ? wp_sidebar_description( $id ) : ''; 330 $sidebar['class'] = isset( $registered_sidebar['class'] ) ? $registered_sidebar['class'] : ''; 331 $sidebar['before_widget'] = isset( $registered_sidebar['before_widget'] ) ? $registered_sidebar['before_widget'] : ''; 332 $sidebar['after_widget'] = isset( $registered_sidebar['after_widget'] ) ? $registered_sidebar['after_widget'] : ''; 333 $sidebar['before_title'] = isset( $registered_sidebar['before_title'] ) ? $registered_sidebar['before_title'] : ''; 334 $sidebar['after_title'] = isset( $registered_sidebar['after_title'] ) ? $registered_sidebar['after_title'] : ''; 335 } else { 336 $sidebar['status'] = 'inactive'; 337 $sidebar['name'] = $raw_sidebar['name']; 338 $sidebar['description'] = ''; 339 $sidebar['class'] = ''; 340 } 341 342 $fields = $this->get_fields_for_response( $request ); 343 if ( rest_is_field_included( 'widgets', $fields ) ) { 344 $sidebars = wp_get_sidebars_widgets(); 345 $widgets = array_filter( 346 isset( $sidebars[ $sidebar['id'] ] ) ? $sidebars[ $sidebar['id'] ] : array(), 347 static function ( $widget_id ) use ( $wp_registered_widgets ) { 348 return isset( $wp_registered_widgets[ $widget_id ] ); 349 } 350 ); 351 352 $sidebar['widgets'] = array_values( $widgets ); 353 } 354 355 $schema = $this->get_item_schema(); 356 $data = array(); 357 foreach ( $schema['properties'] as $property_id => $property ) { 358 if ( isset( $sidebar[ $property_id ] ) && true === rest_validate_value_from_schema( $sidebar[ $property_id ], $property ) ) { 359 $data[ $property_id ] = $sidebar[ $property_id ]; 360 } elseif ( isset( $property['default'] ) ) { 361 $data[ $property_id ] = $property['default']; 362 } 363 } 364 365 $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; 366 $data = $this->add_additional_fields_to_object( $data, $request ); 367 $data = $this->filter_response_by_context( $data, $context ); 368 369 $response = rest_ensure_response( $data ); 370 371 $response->add_links( $this->prepare_links( $sidebar ) ); 372 373 /** 374 * Filters the REST API response for a sidebar. 375 * 376 * @since 5.8.0 377 * 378 * @param WP_REST_Response $response The response object. 379 * @param array $raw_sidebar The raw sidebar data. 380 * @param WP_REST_Request $request The request object. 381 */ 382 return apply_filters( 'rest_prepare_sidebar', $response, $raw_sidebar, $request ); 383 } 384 385 /** 386 * Prepares links for the sidebar. 387 * 388 * @since 5.8.0 389 * 390 * @param array $sidebar Sidebar. 391 * @return array Links for the given widget. 392 */ 393 protected function prepare_links( $sidebar ) { 394 return array( 395 'collection' => array( 396 'href' => rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ), 397 ), 398 'self' => array( 399 'href' => rest_url( sprintf( '%s/%s/%s', $this->namespace, $this->rest_base, $sidebar['id'] ) ), 400 ), 401 'https://api.w.org/widget' => array( 402 'href' => add_query_arg( 'sidebar', $sidebar['id'], rest_url( '/wp/v2/widgets' ) ), 403 'embeddable' => true, 404 ), 405 ); 406 } 407 408 /** 409 * Retrieves the block type' schema, conforming to JSON Schema. 410 * 411 * @since 5.8.0 412 * 413 * @return array Item schema data. 414 */ 415 public function get_item_schema() { 416 if ( $this->schema ) { 417 return $this->add_additional_fields_schema( $this->schema ); 418 } 419 420 $schema = array( 421 '$schema' => 'http://json-schema.org/draft-04/schema#', 422 'title' => 'sidebar', 423 'type' => 'object', 424 'properties' => array( 425 'id' => array( 426 'description' => __( 'ID of sidebar.' ), 427 'type' => 'string', 428 'context' => array( 'embed', 'view', 'edit' ), 429 'readonly' => true, 430 ), 431 'name' => array( 432 'description' => __( 'Unique name identifying the sidebar.' ), 433 'type' => 'string', 434 'context' => array( 'embed', 'view', 'edit' ), 435 'readonly' => true, 436 ), 437 'description' => array( 438 'description' => __( 'Description of sidebar.' ), 439 'type' => 'string', 440 'context' => array( 'embed', 'view', 'edit' ), 441 'readonly' => true, 442 ), 443 'class' => array( 444 'description' => __( 'Extra CSS class to assign to the sidebar in the Widgets interface.' ), 445 'type' => 'string', 446 'context' => array( 'embed', 'view', 'edit' ), 447 'readonly' => true, 448 ), 449 'before_widget' => array( 450 'description' => __( 'HTML content to prepend to each widget\'s HTML output when assigned to this sidebar. Default is an opening list item element.' ), 451 'type' => 'string', 452 'default' => '', 453 'context' => array( 'embed', 'view', 'edit' ), 454 'readonly' => true, 455 ), 456 'after_widget' => array( 457 'description' => __( 'HTML content to append to each widget\'s HTML output when assigned to this sidebar. Default is a closing list item element.' ), 458 'type' => 'string', 459 'default' => '', 460 'context' => array( 'embed', 'view', 'edit' ), 461 'readonly' => true, 462 ), 463 'before_title' => array( 464 'description' => __( 'HTML content to prepend to the sidebar title when displayed. Default is an opening h2 element.' ), 465 'type' => 'string', 466 'default' => '', 467 'context' => array( 'embed', 'view', 'edit' ), 468 'readonly' => true, 469 ), 470 'after_title' => array( 471 'description' => __( 'HTML content to append to the sidebar title when displayed. Default is a closing h2 element.' ), 472 'type' => 'string', 473 'default' => '', 474 'context' => array( 'embed', 'view', 'edit' ), 475 'readonly' => true, 476 ), 477 'status' => array( 478 'description' => __( 'Status of sidebar.' ), 479 'type' => 'string', 480 'enum' => array( 'active', 'inactive' ), 481 'context' => array( 'embed', 'view', 'edit' ), 482 'readonly' => true, 483 ), 484 'widgets' => array( 485 'description' => __( 'Nested widgets.' ), 486 'type' => 'array', 487 'items' => array( 488 'type' => array( 'object', 'string' ), 489 ), 490 'default' => array(), 491 'context' => array( 'embed', 'view', 'edit' ), 492 ), 493 ), 494 ); 495 496 $this->schema = $schema; 497 498 return $this->add_additional_fields_schema( $this->schema ); 499 } 500 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Tue Dec 24 01:00:02 2024 | Cross-referenced by PHPXref 0.7.1 |