PluginProbe
Gutenberg / 9.6.0
Gutenberg v9.6.0
23.9.1 23.9.0 23.8.0 23.7.2 23.7.1 23.7.0 23.6.1 23.6.2 23.6.0 23.5.3 23.5.2 23.5.1 23.5.0 23.4.0 23.3.2 23.3.1 23.3.0 23.2.0 23.2.1 23.2.2 23.1.1 23.1.0 23.0.1 12.6.0 7.4.0 All 402 releases
gutenberg / lib / class-wp-rest-sidebars-controller.php

class-wp-rest-sidebars-controller.php in Gutenberg 9.6.0, at lib/class-wp-rest-sidebars-controller.php

427 lines 13.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * An extension for the WP REST API that exposes endpoints for sidebars and widgets.
4 *
5 * PHP version 5.4.0
6 *
7 * Copyright (C) 2015 Martin Pettersson
8 *
9 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 *
22 * @author Martin Pettersson <martin_pettersson@outlook.com>
23 * @copyright 2015 Martin Pettersson
24 * @license GPLv2
25 * @link https://github.com/martin-pettersson/wp-rest-api-sidebars
26 * @package gutenberg
27 */
28
29 /**
30 * Class Sidebars_Controller
31 *
32 * @package WP_API_Sidebars\Controllers
33 */
34 class WP_REST_Sidebars_Controller extends WP_REST_Controller {
35
36 /**
37 * Sidebars controller constructor.
38 *
39 * @since 5.5.0
40 */
41 public function __construct() {
42 $this->namespace = 'wp/v2';
43 $this->rest_base = 'sidebars';
44 }
45
46 /**
47 * Registers the controllers routes.
48 *
49 * @return void
50 */
51 public function register_routes() {
52 // Lists all sidebars.
53 register_rest_route(
54 $this->namespace,
55 '/' . $this->rest_base,
56 array(
57 array(
58 'methods' => WP_REST_Server::READABLE,
59 'callback' => array( $this, 'get_items' ),
60 'permission_callback' => array( $this, 'permissions_check' ),
61 'args' => array(
62 'context' => $this->get_context_param( array( 'default' => 'view' ) ),
63 ),
64 ),
65 'schema' => array( $this, 'get_public_item_schema' ),
66 )
67 );
68
69 // Lists/updates a single sidebar based on the given id.
70 register_rest_route(
71 $this->namespace,
72 '/' . $this->rest_base . '/(?P<id>[\w-]+)',
73 array(
74 array(
75 'methods' => WP_REST_Server::READABLE,
76 'callback' => array( $this, 'get_item' ),
77 'permission_callback' => array( $this, 'permissions_check' ),
78 'args' => array(
79 'id' => array(
80 'description' => __( 'The id of a registered sidebar', 'gutenberg' ),
81 'type' => 'string',
82 ),
83 'context' => $this->get_context_param( array( 'default' => 'view' ) ),
84 ),
85 ),
86 array(
87 'methods' => WP_REST_Server::EDITABLE,
88 'callback' => array( $this, 'update_item' ),
89 'permission_callback' => array( $this, 'permissions_check' ),
90 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
91 ),
92 'schema' => array( $this, 'get_public_item_schema' ),
93 )
94 );
95 }
96
97 /**
98 * Checks if the user has permissions to make the request.
99 *
100 * @return true|WP_Error True if the request has read access, WP_Error object otherwise.
101 * @since 5.6.0
102 * @access public
103 */
104 public function permissions_check() {
105 // Verify if the current user has edit_theme_options capability.
106 // This capability is required to access the widgets screen.
107 if ( ! current_user_can( 'edit_theme_options' ) ) {
108 return new WP_Error(
109 'widgets_cannot_access',
110 __( 'Sorry, you are not allowed to access widgets on this site.', 'gutenberg' ),
111 array(
112 'status' => rest_authorization_required_code(),
113 )
114 );
115 }
116
117 return true;
118 }
119
120 /**
121 * Returns a list of sidebars (active or inactive)
122 *
123 * @param WP_REST_Request $request The request instance.
124 *
125 * @return WP_REST_Response
126 */
127 public function get_items( $request ) {
128 $data = array();
129 foreach ( (array) wp_get_sidebars_widgets() as $id => $widgets ) {
130 list( $exists, $sidebar ) = $this->get_sidebar( $id );
131
132 if ( ! $exists && 'wp_inactive_widgets' !== $id ) {
133 continue;
134 }
135
136 $data[] = $this->prepare_response_for_collection(
137 $this->prepare_item_for_response( $sidebar, $request )
138 );
139 }
140
141 return rest_ensure_response( $data );
142 }
143
144 /**
145 * Returns the given sidebar
146 *
147 * @param WP_REST_Request $request The request instance.
148 *
149 * @return WP_REST_Response|WP_Error
150 */
151 public function get_item( $request ) {
152 list( $exists, $sidebar ) = $this->get_sidebar( $request['id'] );
153
154 if ( ! $exists && 'wp_inactive_widgets' !== $request['id'] ) {
155 return new WP_Error( 'rest_sidebar_not_found', __( 'No sidebar exists with that id.', 'gutenberg' ), array( 'status' => 404 ) );
156 }
157
158 return $this->prepare_item_for_response( $sidebar, $request );
159 }
160
161 /**
162 * Updates the sidebar.
163 *
164 * @param WP_REST_Request $request The request instance.
165 *
166 * @return WP_REST_Response
167 */
168 public function update_item( $request ) {
169 if ( isset( $request['widgets'] ) ) {
170 $sidebars = wp_get_sidebars_widgets();
171
172 foreach ( $sidebars as $sidebar_id => $widgets ) {
173 foreach ( $widgets as $i => $widget_id ) {
174 // This automatically removes the passed widget ids from any other sidebars in use.
175 if ( $sidebar_id !== $request['id'] && in_array( $widget_id, $request['widgets'], true ) ) {
176 unset( $sidebars[ $sidebar_id ][ $i ] );
177 }
178
179 // This automatically removes omitted widget ids to the inactive sidebar.
180 if ( $sidebar_id === $request['id'] && ! in_array( $widget_id, $request['widgets'], true ) ) {
181 $sidebars['wp_inactive_widgets'][] = $widget_id;
182 }
183 }
184 }
185
186 $sidebars[ $request['id'] ] = $request['widgets'];
187
188 wp_set_sidebars_widgets( $sidebars );
189 }
190
191 $request['context'] = 'edit';
192
193 list( , $sidebar ) = $this->get_sidebar( $request['id'] );
194
195 return $this->prepare_item_for_response( $sidebar, $request );
196 }
197
198 /**
199 * Returns a sidebar for the given id or null if not found
200 *
201 * Note: The id can be either an index, the id or the name of a sidebar
202 *
203 * @param string|int $id ID of the sidebar.
204 *
205 * @return array|null
206 * @global array $wp_registered_sidebars
207 */
208 protected function get_sidebar( $id ) {
209 global $wp_registered_sidebars;
210
211 if ( is_int( $id ) ) {
212 $id = 'sidebar-' . $id;
213 } else {
214 $id = sanitize_title( $id );
215
216 foreach ( (array) $wp_registered_sidebars as $key => $sidebar ) {
217 if ( sanitize_title( $sidebar['name'] ) === $id ) {
218 return array( true, $sidebar );
219 }
220 }
221 }
222
223 foreach ( (array) $wp_registered_sidebars as $key => $sidebar ) {
224 if ( $key === $id ) {
225 return array( true, $sidebar );
226 }
227 }
228
229 return array( false, array( 'id' => $id ) );
230 }
231
232 /**
233 * Prepare a single sidebar output for response
234 *
235 * @param array $raw_sidebar Sidebar instance.
236 * @param WP_REST_Request $request Request object.
237 *
238 * @return WP_REST_Response $data
239 */
240 public function prepare_item_for_response( $raw_sidebar, $request ) {
241 global $wp_registered_sidebars, $wp_registered_widgets;
242
243 $id = $raw_sidebar['id'];
244 $sidebar = array( 'id' => $id );
245
246 if ( isset( $wp_registered_sidebars[ $id ] ) ) {
247 $registered_sidebar = $wp_registered_sidebars[ $id ];
248
249 $sidebar['status'] = 'active';
250 $sidebar['name'] = isset( $registered_sidebar['name'] ) ? $registered_sidebar['name'] : '';
251 $sidebar['description'] = isset( $registered_sidebar['description'] ) ? $registered_sidebar['description'] : '';
252 $sidebar['class'] = isset( $registered_sidebar['class'] ) ? $registered_sidebar['class'] : '';
253 $sidebar['before_widget'] = isset( $registered_sidebar['before_widget'] ) ? $registered_sidebar['before_widget'] : '';
254 $sidebar['after_widget'] = isset( $registered_sidebar['after_widget'] ) ? $registered_sidebar['after_widget'] : '';
255 $sidebar['before_title'] = isset( $registered_sidebar['before_title'] ) ? $registered_sidebar['before_title'] : '';
256 $sidebar['after_title'] = isset( $registered_sidebar['after_title'] ) ? $registered_sidebar['after_title'] : '';
257 } else {
258 $sidebar['status'] = 'inactive';
259 }
260
261 if ( 'wp_inactive_widgets' === $sidebar['id'] && empty( $sidebar['name'] ) ) {
262 $sidebar['name'] = __( 'Inactive widgets', 'gutenberg' );
263 }
264
265 $fields = $this->get_fields_for_response( $request );
266 if ( rest_is_field_included( 'widgets', $fields ) ) {
267 $sidebars = wp_get_sidebars_widgets();
268 $widgets = array_filter(
269 isset( $sidebars[ $sidebar['id'] ] ) ? $sidebars[ $sidebar['id'] ] : array(),
270 function ( $widget_id ) use ( $wp_registered_widgets ) {
271 return isset( $wp_registered_widgets[ $widget_id ] );
272 }
273 );
274
275 $sidebar['widgets'] = $widgets;
276 }
277
278 $schema = $this->get_item_schema();
279 $data = array();
280 foreach ( $schema['properties'] as $property_id => $property ) {
281 if ( isset( $sidebar[ $property_id ] ) && true === rest_validate_value_from_schema( $sidebar[ $property_id ], $property ) ) {
282 $data[ $property_id ] = $sidebar[ $property_id ];
283 } elseif ( isset( $property['default'] ) ) {
284 $data[ $property_id ] = $property['default'];
285 }
286 }
287
288 $context = ! empty( $request['context'] ) ? $request['context'] : 'view';
289 $data = $this->add_additional_fields_to_object( $data, $request );
290 $data = $this->filter_response_by_context( $data, $context );
291
292 $response = rest_ensure_response( $data );
293
294 $response->add_links( $this->prepare_links( $sidebar ) );
295
296 /**
297 * Filters a sidebar location returned from the REST API.
298 *
299 * Allows modification of the menu location data right before it is
300 * returned.
301 *
302 * @param WP_REST_Response $response The response object.
303 * @param object $sidebar The original status object.
304 * @param WP_REST_Request $request Request used to generate the response.
305 */
306 return apply_filters( 'rest_prepare_sidebar', $response, $sidebar, $request );
307 }
308
309 /**
310 * Prepares links for the request.
311 *
312 * @param array $sidebar Sidebar.
313 *
314 * @return array Links for the given widget.
315 */
316 protected function prepare_links( $sidebar ) {
317 return array(
318 'collection' => array(
319 'href' => rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ),
320 ),
321 'self' => array(
322 'href' => rest_url( sprintf( '%s/%s/%s', $this->namespace, $this->rest_base, $sidebar['id'] ) ),
323 ),
324 'https://api.w.org/widget' => array(
325 'href' => add_query_arg( 'sidebar', $sidebar['id'], rest_url( sprintf( '%s/%s', 'wp/v2', 'widgets' ) ) ),
326 'embeddable' => true,
327 ),
328 );
329 }
330
331 /**
332 * Retrieves the block type' schema, conforming to JSON Schema.
333 *
334 * @return array Item schema data.
335 */
336 public function get_item_schema() {
337 if ( $this->schema ) {
338 return $this->add_additional_fields_schema( $this->schema );
339 }
340
341 $schema = array(
342 '$schema' => 'http://json-schema.org/draft-04/schema#',
343 'title' => 'sidebar',
344 'type' => 'object',
345 'properties' => array(
346 'id' => array(
347 'description' => __( 'ID of sidebar.', 'gutenberg' ),
348 'type' => 'string',
349 'default' => '',
350 'context' => array( 'embed', 'view', 'edit' ),
351 'readonly' => true,
352 ),
353 'name' => array(
354 'description' => __( 'Unique name identifying the sidebar.', 'gutenberg' ),
355 'type' => 'string',
356 'default' => '',
357 'context' => array( 'embed', 'view', 'edit' ),
358 'readonly' => true,
359 ),
360 'description' => array(
361 'description' => __( 'Description of sidebar.', 'gutenberg' ),
362 'type' => 'string',
363 'default' => '',
364 'context' => array( 'embed', 'view', 'edit' ),
365 'readonly' => true,
366 ),
367 'class' => array(
368 'description' => __( 'Extra CSS class to assign to the sidebar in the Widgets interface.', 'gutenberg' ),
369 'type' => 'string',
370 'default' => '',
371 'context' => array( 'embed', 'view', 'edit' ),
372 'readonly' => true,
373 ),
374 'before_widget' => array(
375 'description' => __( 'HTML content to prepend to each widget\'s HTML output when assigned to this sidebar. Default is an opening list item element.', 'gutenberg' ),
376 'type' => 'string',
377 'default' => '',
378 'context' => array( 'embed', 'view', 'edit' ),
379 'readonly' => true,
380 ),
381 'after_widget' => array(
382 'description' => __( 'HTML content to append to each widget\'s HTML output when assigned to this sidebar. Default is a closing list item element.', 'gutenberg' ),
383 'type' => 'string',
384 'default' => '',
385 'context' => array( 'embed', 'view', 'edit' ),
386 'readonly' => true,
387 ),
388 'before_title' => array(
389 'description' => __( 'HTML content to prepend to the sidebar title when displayed. Default is an opening h2 element.', 'gutenberg' ),
390 'type' => 'string',
391 'default' => '',
392 'context' => array( 'embed', 'view', 'edit' ),
393 'readonly' => true,
394 ),
395 'after_title' => array(
396 'description' => __( 'HTML content to append to the sidebar title when displayed. Default is a closing h2 element.', 'gutenberg' ),
397 'type' => 'string',
398 'default' => '',
399 'context' => array( 'embed', 'view', 'edit' ),
400 'readonly' => true,
401 ),
402 'status' => array(
403 'description' => __( 'Status of sidebar.', 'gutenberg' ),
404 'type' => 'string',
405 'enum' => array( 'active', 'inactive' ),
406 'default' => '',
407 'context' => array( 'embed', 'view', 'edit' ),
408 'readonly' => true,
409 ),
410 'widgets' => array(
411 'description' => __( 'Nested widgets.', 'gutenberg' ),
412 'type' => 'array',
413 'items' => array(
414 'type' => array( 'object', 'string' ),
415 ),
416 'default' => array(),
417 'context' => array( 'embed', 'view', 'edit' ),
418 ),
419 ),
420 );
421
422 $this->schema = $schema;
423
424 return $this->add_additional_fields_schema( $this->schema );
425 }
426 }
427