@@ -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 ,
0 commit comments