|
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 } |