Skip to content
This repository was archived by the owner on Jan 13, 2022. It is now read-only.

Commit ac0b9d6

Browse files
committed
Merge pull request #15 from WP-API/get_widget_endpoint
Get widget endpoint
2 parents 406de4b + 90aa7bc commit ac0b9d6

File tree

2 files changed

+187
-17
lines changed

2 files changed

+187
-17
lines changed

lib/class-wp-rest-widgets-controller.php

Lines changed: 181 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,27 @@ class WP_REST_Widgets_Controller extends WP_REST_Controller {
1313
*/
1414
public $widgets;
1515

16+
/**
17+
* Registered widgets.
18+
*/
19+
public $registered_widgets;
20+
21+
/**
22+
* Sidebars
23+
*/
24+
public $sidebars;
25+
1626
/**
1727
* WP_REST_Widgets_Controller constructor.
1828
*
1929
* @param WP_Widget[] $widgets Widget objects.
2030
*/
21-
public function __construct( $widgets ) {
31+
public function __construct( $widgets, $registered_widgets ) {
2232
$this->namespace = 'wp/v2';
2333
$this->rest_base = 'widgets';
2434
$this->widgets = $widgets;
35+
$this->registered_widgets = $registered_widgets;
36+
$this->sidebars = wp_get_sidebars_widgets();
2537

2638
// @todo Now given $this->widgets, inject schema information for Core widgets in lieu of them being in core now. See #35574.
2739

@@ -121,14 +133,105 @@ public function get_items_permissions_check( $request ) {
121133
return true;
122134
}
123135

136+
/**
137+
* Get a collection of widgets
138+
*
139+
* @param WP_REST_Request $request Full details about the request.
140+
* @return WP_Error|WP_REST_Response
141+
*/
124142
public function get_items( $request ) {
143+
if ( empty( $this->registered_widgets ) ) {
144+
return rest_ensure_response( array() );
145+
};
146+
147+
$args = array();
148+
$args['sidebar'] = $request['sidebar'];
149+
150+
// TODO pagination
151+
152+
$widgets = array();
153+
foreach( $this->registered_widgets as $instance_id => $widget ) {
154+
if ( !$this->get_instance_permissions_check( $instance_id ) ) {
155+
continue;
156+
}
157+
if ( !is_null( $args['sidebar'] ) && $args['sidebar'] !== $this->get_instance_sidebar( $instance_id ) ) {
158+
continue;
159+
}
160+
$data = $this->prepare_item_for_response( $widget, $request );
161+
$widgets[] = $this->prepare_response_for_collection( $data );
162+
}
163+
164+
if ( !empty( $widgets ) && !is_null( $args['sidebar'] ) ) {
165+
$widgets = $this->sort_widgets_by_sidebar_order( $args['sidebar'], $widgets );
166+
}
125167

168+
return rest_ensure_response( $widgets );
126169
}
127170

128171
public function get_item_permissions_check( $request ) {
129172
return true;
130173
}
131174

175+
/**
176+
* Check if current user can get the widget instance.
177+
*
178+
* @param string $instance_id Instance id
179+
* @return bool
180+
*/
181+
public function get_instance_permissions_check( $instance_id ) {
182+
// Require `edit_theme_options` to view unassigned widgets
183+
$sidebar = $this->get_instance_sidebar( $instance_id );
184+
if ( $sidebar === false || $sidebar == 'wp_inactive_widgets' ) {
185+
return current_user_can( 'edit_theme_options' );
186+
}
187+
188+
return true;
189+
}
190+
191+
/**
192+
* Get the sidebar a widget instance is assigned to
193+
*
194+
* @param string id Widget instance id
195+
* @return bool|string Sidebar id it is assigned to or false if not found. Will
196+
* return `wp_inactive_widgets` as sidebar for unassigned widgets
197+
*/
198+
public function get_instance_sidebar( $id ) {
199+
foreach( $this->sidebars as $sidebar_id => $widgets ) {
200+
if ( in_array( $id, $widgets ) ) {
201+
return $sidebar_id;
202+
}
203+
}
204+
205+
return false;
206+
}
207+
208+
/**
209+
* Sort the widgets by their order in the sidebar.
210+
*
211+
* Widgets not assigned to the specified sidebar will be discarded.
212+
*
213+
* @param string sidebar Sidebar id
214+
* @param array widgets Widgets to sort
215+
* @return array
216+
*/
217+
public function sort_widgets_by_sidebar_order( $sidebar, $widgets ) {
218+
if ( empty( $this->sidebars[$sidebar] ) ) {
219+
return array();
220+
}
221+
222+
$new_widgets = array();
223+
foreach( $this->sidebars[$sidebar] as $widget_id ) {
224+
foreach( $widgets as $widget ) {
225+
if ( $widget_id === $widget['id'] ) {
226+
$new_widgets[] = $widget;
227+
break;
228+
}
229+
}
230+
}
231+
232+
return $new_widgets;
233+
}
234+
132235
public function get_item( $request ) {
133236

134237
}
@@ -141,16 +244,81 @@ public function delete_item( $request ) {
141244

142245
}
143246

144-
public function prepare_item_for_response( $item, $request ) {
247+
/**
248+
* Prepare a single widget output for response
249+
*
250+
* @param array $widget Widget instance
251+
* @param WP_REST_Request $request Request object.
252+
* @return WP_REST_Response $data
253+
*/
254+
public function prepare_item_for_response( $widget, $request ) {
255+
256+
$id = $widget['id'];
257+
$id_base = $widget['callback'][0]->id_base;
258+
$array_key = $widget['params'][0]['number'];
259+
260+
$values = array(
261+
'id' => $id,
262+
'type' => $id_base,
263+
);
264+
if ( !empty( $array_key ) ) {
265+
$widgets = get_option( 'widget_' . $id_base );
266+
if ( isset( $widgets[$array_key] ) ) {
267+
$values = array_merge( $values, $widgets[$array_key] );
268+
}
269+
}
145270

271+
$schema = $this->get_type_schema( $widget['callback'][0]->id_base );
272+
273+
$data = array();
274+
foreach( $schema['properties'] as $property_id => $property ) {
275+
276+
// TODO check for public visibility of property and run permissions
277+
// check for private properties.
278+
279+
if ( isset( $values[$property_id] ) && gettype( $values[$property_id] ) === $property['type'] ) {
280+
$data[$property_id] = $values[$property_id];
281+
} elseif ( isset( $property['default'] ) ) {
282+
$data[$property_id] = $property['default'];
283+
}
284+
}
285+
286+
$response = rest_ensure_response( $data );
287+
288+
// @TODO Add _link to sidebar if assigned?
289+
290+
/**
291+
* Filter the widget data for a response.
292+
*
293+
* @param WP_REST_Response $response The response object.
294+
* @param array $widget Widget instance.
295+
* @param WP_REST_Request $request Request object.
296+
*/
297+
return apply_filters( 'rest_prepare_widget', $response, $widget, $request );
146298
}
147299

148300
public function get_item_schema() {
149301

150302
}
151303

304+
/**
305+
* Get the query params for collections of attachments.
306+
*
307+
* @return array
308+
*/
152309
public function get_collection_params() {
153-
return array();
310+
$params = parent::get_collection_params();
311+
312+
$params['context']['default'] = 'view';
313+
314+
$params['sidebar'] = array(
315+
'description' => __( 'Limit result set to widgets assigned to this sidebar.' ),
316+
'type' => 'string',
317+
'default' => null,
318+
'sanitize_callback' => 'sanitize_key',
319+
);
320+
321+
return $params;
154322
}
155323

156324
/**
@@ -185,17 +353,17 @@ public function get_types( $request ) {
185353
*/
186354
public function get_type( $request ) {
187355

188-
if ( empty( $request['type'] ) ) {
189-
return new WP_Error( 'rest_widget_missing_type', __( 'Request missing widget type.' ), array( 'status' => 400 ) );
190-
}
356+
if ( empty( $request['type'] ) ) {
357+
return new WP_Error( 'rest_widget_missing_type', __( 'Request missing widget type.' ), array( 'status' => 400 ) );
358+
}
191359

192-
$schema = $this->get_type_schema( $request['type'] );
360+
$schema = $this->get_type_schema( $request['type'] );
193361

194-
if ( $schema === false ) {
195-
return new WP_Error( 'rest_widget_type_not_found', __( 'Requested widget type was not found.' ), array( 'status' => 404 ) );
196-
}
362+
if ( $schema === false ) {
363+
return new WP_Error( 'rest_widget_type_not_found', __( 'Requested widget type was not found.' ), array( 'status' => 404 ) );
364+
}
197365

198-
return rest_ensure_response( $schema );
366+
return rest_ensure_response( $schema );
199367
}
200368

201369
/**
@@ -211,9 +379,6 @@ public function get_types_permissions_check( $request ) {
211379
/**
212380
* Return a schema matching this widget type
213381
*
214-
* TODO this is a placeholder. A final implementation needs to look up a
215-
* schema which would specify the visibility and type of widget control options.
216-
*
217382
* @param string $id_base Registered widget type
218383
* @return array $schema
219384
*/
@@ -292,13 +457,13 @@ public function get_type_schema( $id_base ) {
292457
'default' => '',
293458
),
294459
),
295-
'recent_comments' => array(
460+
'recent-comments' => array(
296461
'number' => array(
297462
'type' => 'integer',
298463
'default' => 5,
299464
),
300465
),
301-
'recent_posts' => array(
466+
'recent-posts' => array(
302467
'number' => array(
303468
'type' => 'integer',
304469
'default' => 5,

plugin.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ function wp_api_nav_menus_widgets_init_controllers() {
4040
*/
4141
global $wp_widget_factory;
4242

43-
$widgets_controller = new WP_REST_Widgets_Controller( $wp_widget_factory->widgets );
43+
/**
44+
* @type array $wp_registered_widgets
45+
*/
46+
global $wp_registered_widgets;
47+
48+
$widgets_controller = new WP_REST_Widgets_Controller( $wp_widget_factory->widgets, $wp_registered_widgets );
4449
$widgets_controller->register_routes();
4550
}

0 commit comments

Comments
 (0)