ru-se.com

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

class-wp-rest-sidebars-controller.php (14398B)


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