13 * @since 5.8.0 |
13 * @since 5.8.0 |
14 * |
14 * |
15 * @see WP_REST_Controller |
15 * @see WP_REST_Controller |
16 */ |
16 */ |
17 class WP_REST_Widgets_Controller extends WP_REST_Controller { |
17 class WP_REST_Widgets_Controller extends WP_REST_Controller { |
|
18 |
|
19 /** |
|
20 * Tracks whether {@see retrieve_widgets()} has been called in the current request. |
|
21 * |
|
22 * @since 5.9.0 |
|
23 * @var bool |
|
24 */ |
|
25 protected $widgets_retrieved = false; |
|
26 |
|
27 /** |
|
28 * Whether the controller supports batching. |
|
29 * |
|
30 * @since 5.9.0 |
|
31 * @var array |
|
32 */ |
|
33 protected $allow_batch = array( 'v1' => true ); |
18 |
34 |
19 /** |
35 /** |
20 * Widgets controller constructor. |
36 * Widgets controller constructor. |
21 * |
37 * |
22 * @since 5.8.0 |
38 * @since 5.8.0 |
46 'methods' => WP_REST_Server::CREATABLE, |
62 'methods' => WP_REST_Server::CREATABLE, |
47 'callback' => array( $this, 'create_item' ), |
63 'callback' => array( $this, 'create_item' ), |
48 'permission_callback' => array( $this, 'create_item_permissions_check' ), |
64 'permission_callback' => array( $this, 'create_item_permissions_check' ), |
49 'args' => $this->get_endpoint_args_for_item_schema(), |
65 'args' => $this->get_endpoint_args_for_item_schema(), |
50 ), |
66 ), |
51 'allow_batch' => array( 'v1' => true ), |
67 'allow_batch' => $this->allow_batch, |
52 'schema' => array( $this, 'get_public_item_schema' ), |
68 'schema' => array( $this, 'get_public_item_schema' ), |
53 ) |
69 ) |
54 ); |
70 ); |
55 |
71 |
56 register_rest_route( |
72 register_rest_route( |
80 'description' => __( 'Whether to force removal of the widget, or move it to the inactive sidebar.' ), |
96 'description' => __( 'Whether to force removal of the widget, or move it to the inactive sidebar.' ), |
81 'type' => 'boolean', |
97 'type' => 'boolean', |
82 ), |
98 ), |
83 ), |
99 ), |
84 ), |
100 ), |
85 'allow_batch' => array( 'v1' => true ), |
101 'allow_batch' => $this->allow_batch, |
86 'schema' => array( $this, 'get_public_item_schema' ), |
102 'schema' => array( $this, 'get_public_item_schema' ), |
87 ) |
103 ) |
88 ); |
104 ); |
89 } |
105 } |
90 |
106 |
95 * |
111 * |
96 * @param WP_REST_Request $request Full details about the request. |
112 * @param WP_REST_Request $request Full details about the request. |
97 * @return true|WP_Error True if the request has read access, WP_Error object otherwise. |
113 * @return true|WP_Error True if the request has read access, WP_Error object otherwise. |
98 */ |
114 */ |
99 public function get_items_permissions_check( $request ) { |
115 public function get_items_permissions_check( $request ) { |
|
116 $this->retrieve_widgets(); |
|
117 if ( isset( $request['sidebar'] ) && $this->check_read_sidebar_permission( $request['sidebar'] ) ) { |
|
118 return true; |
|
119 } |
|
120 |
|
121 foreach ( wp_get_sidebars_widgets() as $sidebar_id => $widget_ids ) { |
|
122 if ( $this->check_read_sidebar_permission( $sidebar_id ) ) { |
|
123 return true; |
|
124 } |
|
125 } |
|
126 |
100 return $this->permissions_check( $request ); |
127 return $this->permissions_check( $request ); |
101 } |
128 } |
102 |
129 |
103 /** |
130 /** |
104 * Retrieves a collection of widgets. |
131 * Retrieves a collection of widgets. |
107 * |
134 * |
108 * @param WP_REST_Request $request Full details about the request. |
135 * @param WP_REST_Request $request Full details about the request. |
109 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. |
136 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. |
110 */ |
137 */ |
111 public function get_items( $request ) { |
138 public function get_items( $request ) { |
112 retrieve_widgets(); |
139 $this->retrieve_widgets(); |
113 |
140 |
114 $prepared = array(); |
141 $prepared = array(); |
|
142 $permissions_check = $this->permissions_check( $request ); |
115 |
143 |
116 foreach ( wp_get_sidebars_widgets() as $sidebar_id => $widget_ids ) { |
144 foreach ( wp_get_sidebars_widgets() as $sidebar_id => $widget_ids ) { |
117 if ( isset( $request['sidebar'] ) && $sidebar_id !== $request['sidebar'] ) { |
145 if ( isset( $request['sidebar'] ) && $sidebar_id !== $request['sidebar'] ) { |
118 continue; |
146 continue; |
119 } |
147 } |
120 |
148 |
|
149 if ( is_wp_error( $permissions_check ) && ! $this->check_read_sidebar_permission( $sidebar_id ) ) { |
|
150 continue; |
|
151 } |
|
152 |
121 foreach ( $widget_ids as $widget_id ) { |
153 foreach ( $widget_ids as $widget_id ) { |
122 $response = $this->prepare_item_for_response( compact( 'sidebar_id', 'widget_id' ), $request ); |
154 $response = $this->prepare_item_for_response( compact( 'sidebar_id', 'widget_id' ), $request ); |
123 |
155 |
124 if ( ! is_wp_error( $response ) ) { |
156 if ( ! is_wp_error( $response ) ) { |
125 $prepared[] = $this->prepare_response_for_collection( $response ); |
157 $prepared[] = $this->prepare_response_for_collection( $response ); |
137 * |
169 * |
138 * @param WP_REST_Request $request Full details about the request. |
170 * @param WP_REST_Request $request Full details about the request. |
139 * @return true|WP_Error True if the request has read access, WP_Error object otherwise. |
171 * @return true|WP_Error True if the request has read access, WP_Error object otherwise. |
140 */ |
172 */ |
141 public function get_item_permissions_check( $request ) { |
173 public function get_item_permissions_check( $request ) { |
|
174 $this->retrieve_widgets(); |
|
175 |
|
176 $widget_id = $request['id']; |
|
177 $sidebar_id = wp_find_widgets_sidebar( $widget_id ); |
|
178 |
|
179 if ( $sidebar_id && $this->check_read_sidebar_permission( $sidebar_id ) ) { |
|
180 return true; |
|
181 } |
|
182 |
142 return $this->permissions_check( $request ); |
183 return $this->permissions_check( $request ); |
143 } |
184 } |
144 |
185 |
145 /** |
186 /** |
|
187 * Checks if a sidebar can be read publicly. |
|
188 * |
|
189 * @since 5.9.0 |
|
190 * |
|
191 * @param string $sidebar_id The sidebar ID. |
|
192 * @return bool Whether the sidebar can be read. |
|
193 */ |
|
194 protected function check_read_sidebar_permission( $sidebar_id ) { |
|
195 $sidebar = wp_get_sidebar( $sidebar_id ); |
|
196 |
|
197 return ! empty( $sidebar['show_in_rest'] ); |
|
198 } |
|
199 |
|
200 /** |
146 * Gets an individual widget. |
201 * Gets an individual widget. |
147 * |
202 * |
148 * @since 5.8.0 |
203 * @since 5.8.0 |
149 * |
204 * |
150 * @param WP_REST_Request $request Full details about the request. |
205 * @param WP_REST_Request $request Full details about the request. |
151 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. |
206 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. |
152 */ |
207 */ |
153 public function get_item( $request ) { |
208 public function get_item( $request ) { |
154 retrieve_widgets(); |
209 $this->retrieve_widgets(); |
155 |
210 |
156 $widget_id = $request['id']; |
211 $widget_id = $request['id']; |
157 $sidebar_id = wp_find_widgets_sidebar( $widget_id ); |
212 $sidebar_id = wp_find_widgets_sidebar( $widget_id ); |
158 |
213 |
159 if ( is_null( $sidebar_id ) ) { |
214 if ( is_null( $sidebar_id ) ) { |
245 * sidebar. |
300 * sidebar. |
246 * |
301 * |
247 * See https://core.trac.wordpress.org/ticket/53657. |
302 * See https://core.trac.wordpress.org/ticket/53657. |
248 */ |
303 */ |
249 wp_get_sidebars_widgets(); |
304 wp_get_sidebars_widgets(); |
250 |
305 $this->retrieve_widgets(); |
251 retrieve_widgets(); |
|
252 |
306 |
253 $widget_id = $request['id']; |
307 $widget_id = $request['id']; |
254 $sidebar_id = wp_find_widgets_sidebar( $widget_id ); |
308 $sidebar_id = wp_find_widgets_sidebar( $widget_id ); |
255 |
309 |
256 // Allow sidebar to be unset or missing when widget is not a WP_Widget. |
310 // Allow sidebar to be unset or missing when widget is not a WP_Widget. |
321 * sidebar. |
375 * sidebar. |
322 * |
376 * |
323 * See https://core.trac.wordpress.org/ticket/53657. |
377 * See https://core.trac.wordpress.org/ticket/53657. |
324 */ |
378 */ |
325 wp_get_sidebars_widgets(); |
379 wp_get_sidebars_widgets(); |
326 |
380 $this->retrieve_widgets(); |
327 retrieve_widgets(); |
|
328 |
381 |
329 $widget_id = $request['id']; |
382 $widget_id = $request['id']; |
330 $sidebar_id = wp_find_widgets_sidebar( $widget_id ); |
383 $sidebar_id = wp_find_widgets_sidebar( $widget_id ); |
331 |
384 |
332 if ( is_null( $sidebar_id ) ) { |
385 if ( is_null( $sidebar_id ) ) { |
405 /** |
458 /** |
406 * Fires after a widget is deleted via the REST API. |
459 * Fires after a widget is deleted via the REST API. |
407 * |
460 * |
408 * @since 5.8.0 |
461 * @since 5.8.0 |
409 * |
462 * |
410 * @param string $widget_id ID of the widget marked for deletion. |
463 * @param string $widget_id ID of the widget marked for deletion. |
411 * @param string $sidebar_id ID of the sidebar the widget was deleted from. |
464 * @param string $sidebar_id ID of the sidebar the widget was deleted from. |
412 * @param WP_REST_Response $response The response data. |
465 * @param WP_REST_Response|WP_Error $response The response data, or WP_Error object on failure. |
413 * @param WP_REST_Request $request The request sent to the API. |
466 * @param WP_REST_Request $request The request sent to the API. |
414 */ |
467 */ |
415 do_action( 'rest_delete_widget', $widget_id, $sidebar_id, $response, $request ); |
468 do_action( 'rest_delete_widget', $widget_id, $sidebar_id, $response, $request ); |
416 |
469 |
417 return $response; |
470 return $response; |
418 } |
471 } |
664 /** |
731 /** |
665 * Filters the REST API response for a widget. |
732 * Filters the REST API response for a widget. |
666 * |
733 * |
667 * @since 5.8.0 |
734 * @since 5.8.0 |
668 * |
735 * |
669 * @param WP_REST_Response $response The response object. |
736 * @param WP_REST_Response|WP_Error $response The response object, or WP_Error object on failure. |
670 * @param array $widget The registered widget data. |
737 * @param array $widget The registered widget data. |
671 * @param WP_REST_Request $request Request used to generate the response. |
738 * @param WP_REST_Request $request Request used to generate the response. |
672 */ |
739 */ |
673 return apply_filters( 'rest_prepare_widget', $response, $widget, $request ); |
740 return apply_filters( 'rest_prepare_widget', $response, $widget, $request ); |
674 } |
741 } |
675 |
742 |
676 /** |
743 /** |
765 'readonly' => true, |
832 'readonly' => true, |
766 ), |
833 ), |
767 'instance' => array( |
834 'instance' => array( |
768 'description' => __( 'Instance settings of the widget, if supported.' ), |
835 'description' => __( 'Instance settings of the widget, if supported.' ), |
769 'type' => 'object', |
836 'type' => 'object', |
770 'context' => array( 'view', 'edit', 'embed' ), |
837 'context' => array( 'edit' ), |
771 'default' => null, |
838 'default' => null, |
772 'properties' => array( |
839 'properties' => array( |
773 'encoded' => array( |
840 'encoded' => array( |
774 'description' => __( 'Base64 encoded representation of the instance settings.' ), |
841 'description' => __( 'Base64 encoded representation of the instance settings.' ), |
775 'type' => 'string', |
842 'type' => 'string', |
776 'context' => array( 'view', 'edit', 'embed' ), |
843 'context' => array( 'edit' ), |
777 ), |
844 ), |
778 'hash' => array( |
845 'hash' => array( |
779 'description' => __( 'Cryptographic hash of the instance settings.' ), |
846 'description' => __( 'Cryptographic hash of the instance settings.' ), |
780 'type' => 'string', |
847 'type' => 'string', |
781 'context' => array( 'view', 'edit', 'embed' ), |
848 'context' => array( 'edit' ), |
782 ), |
849 ), |
783 'raw' => array( |
850 'raw' => array( |
784 'description' => __( 'Unencoded instance settings, if supported.' ), |
851 'description' => __( 'Unencoded instance settings, if supported.' ), |
785 'type' => 'object', |
852 'type' => 'object', |
786 'context' => array( 'view', 'edit', 'embed' ), |
853 'context' => array( 'edit' ), |
787 ), |
854 ), |
788 ), |
855 ), |
789 ), |
856 ), |
790 'form_data' => array( |
857 'form_data' => array( |
791 'description' => __( 'URL-encoded form data from the widget admin form. Used to update a widget that does not support instance. Write only.' ), |
858 'description' => __( 'URL-encoded form data from the widget admin form. Used to update a widget that does not support instance. Write only.' ), |
792 'type' => 'string', |
859 'type' => 'string', |
793 'context' => array(), |
860 'context' => array(), |
794 'arg_options' => array( |
861 'arg_options' => array( |
795 'sanitize_callback' => function( $string ) { |
862 'sanitize_callback' => static function( $string ) { |
796 $array = array(); |
863 $array = array(); |
797 wp_parse_str( $string, $array ); |
864 wp_parse_str( $string, $array ); |
798 return $array; |
865 return $array; |
799 }, |
866 }, |
800 ), |
867 ), |