PluginProbe
Gutenberg / 23.2.1
Gutenberg v23.2.1
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 / experimental / dashboard-widgets / class-wp-rest-widget-modules-controller.php

class-wp-rest-widget-modules-controller.php in Gutenberg 23.2.1, at lib/experimental/dashboard-widgets/class-wp-rest-widget-modules-controller.php

241 lines 7.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Widget Modules REST API: WP_REST_Widget_Modules_Controller class.
4 *
5 * @package gutenberg
6 */
7
8 if ( ! class_exists( 'WP_REST_Widget_Modules_Controller' ) ) {
9
10 /**
11 * Internal REST controller exposing the widget type registry.
12 *
13 * Reads from `WP_Widget_Type_Registry`. Read-only collection and item
14 * endpoints. Render and encode endpoints are intentionally absent:
15 * consumers import the render module on the client and render in JS,
16 * so there is no server-rendered HTML to expose.
17 *
18 * The endpoint lives at `/wp/v2/widget-modules` because the entity
19 * `(kind: 'root', name: 'widgetType')` and the path
20 * `/wp/v2/widget-types` are already taken by the legacy widgets API.
21 */
22 class WP_REST_Widget_Modules_Controller extends WP_REST_Controller {
23
24 /**
25 * Constructor.
26 */
27 public function __construct() {
28 $this->namespace = 'wp/v2';
29 $this->rest_base = 'widget-modules';
30 }
31
32 /**
33 * Registers the widget module routes.
34 */
35 public function register_routes() {
36 register_rest_route(
37 $this->namespace,
38 '/' . $this->rest_base,
39 array(
40 array(
41 'methods' => WP_REST_Server::READABLE,
42 'callback' => array( $this, 'get_items' ),
43 'permission_callback' => array( $this, 'get_items_permissions_check' ),
44 'args' => $this->get_collection_params(),
45 ),
46 'schema' => array( $this, 'get_public_item_schema' ),
47 )
48 );
49
50 register_rest_route(
51 $this->namespace,
52 '/' . $this->rest_base . '/(?P<id>[a-z0-9-]+\/[a-z0-9-]+)',
53 array(
54 'args' => array(
55 'id' => array(
56 'description' => __( 'Widget module name including namespace.', 'gutenberg' ),
57 'type' => 'string',
58 ),
59 ),
60 array(
61 'methods' => WP_REST_Server::READABLE,
62 'callback' => array( $this, 'get_item' ),
63 'permission_callback' => array( $this, 'get_item_permissions_check' ),
64 'args' => array(),
65 ),
66 'schema' => array( $this, 'get_public_item_schema' ),
67 )
68 );
69 }
70
71 /**
72 * Checks whether a given request has permission to read widget
73 * modules.
74 *
75 * @param WP_REST_Request $request Full details about the request.
76 * @return true|WP_Error True if the request has read access, WP_Error
77 * otherwise.
78 */
79 public function get_items_permissions_check( $request ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
80 return $this->check_read_permission();
81 }
82
83 /**
84 * Checks whether a given request has permission to read a single
85 * widget module.
86 *
87 * @param WP_REST_Request $request Full details about the request.
88 * @return true|WP_Error True if the request has read access, WP_Error
89 * otherwise.
90 */
91 public function get_item_permissions_check( $request ) {
92 $check = $this->check_read_permission();
93 if ( is_wp_error( $check ) ) {
94 return $check;
95 }
96
97 $widget_type = WP_Widget_Type_Registry::get_instance()->get_registered( $request['id'] );
98 if ( null === $widget_type ) {
99 return new WP_Error(
100 'rest_widget_module_invalid',
101 __( 'Invalid widget module name.', 'gutenberg' ),
102 array( 'status' => 404 )
103 );
104 }
105
106 return true;
107 }
108
109 /**
110 * Verifies the user has the basic read capability.
111 *
112 * Widget modules are not sensitive data; they describe what is
113 * available to render. Gating at the same level as the dashboard
114 * page menu (which requires `read`) keeps the surface consistent.
115 *
116 * @return true|WP_Error True if the request is allowed, WP_Error
117 * otherwise.
118 */
119 protected function check_read_permission() {
120 if ( ! current_user_can( 'read' ) ) {
121 return new WP_Error(
122 'rest_cannot_view_widget_modules',
123 __( 'Sorry, you are not allowed to view widget modules.', 'gutenberg' ),
124 array( 'status' => rest_authorization_required_code() )
125 );
126 }
127
128 return true;
129 }
130
131 /**
132 * Retrieves the list of all registered widget modules.
133 *
134 * @param WP_REST_Request $request Full details about the request.
135 * @return WP_REST_Response Response object on success.
136 */
137 public function get_items( $request ) {
138 $registered = WP_Widget_Type_Registry::get_instance()->get_all_registered();
139 $data = array();
140
141 foreach ( $registered as $widget_type ) {
142 $item = $this->prepare_item_for_response( $widget_type, $request );
143 $data[] = $this->prepare_response_for_collection( $item );
144 }
145
146 return rest_ensure_response( $data );
147 }
148
149 /**
150 * Retrieves a single widget module from the collection.
151 *
152 * @param WP_REST_Request $request Full details about the request.
153 * @return WP_REST_Response|WP_Error Response object on success, or
154 * WP_Error on failure.
155 */
156 public function get_item( $request ) {
157 $widget_type = WP_Widget_Type_Registry::get_instance()->get_registered( $request['id'] );
158 if ( null === $widget_type ) {
159 return new WP_Error(
160 'rest_widget_module_invalid',
161 __( 'Invalid widget module name.', 'gutenberg' ),
162 array( 'status' => 404 )
163 );
164 }
165
166 return rest_ensure_response( $this->prepare_item_for_response( $widget_type, $request ) );
167 }
168
169 /**
170 * Prepares a widget type object for serialization.
171 *
172 * @param WP_Widget_Type $item Widget type instance.
173 * @param WP_REST_Request $request Full details about the request.
174 * @return WP_REST_Response Response object containing the serialized
175 * widget module data.
176 */
177 public function prepare_item_for_response( $item, $request ) {
178 $widget_type = $item;
179 $fields = $this->get_fields_for_response( $request );
180 $data = array();
181
182 if ( rest_is_field_included( 'name', $fields ) ) {
183 $data['name'] = $widget_type->name;
184 }
185 if ( rest_is_field_included( 'render_module', $fields ) ) {
186 $data['render_module'] = $widget_type->render_module;
187 }
188 if ( rest_is_field_included( 'widget_module', $fields ) ) {
189 $data['widget_module'] = $widget_type->widget_module;
190 }
191
192 $context = ! empty( $request['context'] ) ? $request['context'] : 'view';
193 $data = $this->add_additional_fields_to_object( $data, $request );
194 $data = $this->filter_response_by_context( $data, $context );
195
196 return rest_ensure_response( $data );
197 }
198
199 /**
200 * Retrieves the widget module schema, conforming to JSON Schema.
201 *
202 * @return array Item schema data.
203 */
204 public function get_item_schema() {
205 if ( $this->schema ) {
206 return $this->add_additional_fields_schema( $this->schema );
207 }
208
209 $schema = array(
210 '$schema' => 'http://json-schema.org/draft-04/schema#',
211 'title' => 'widget-module',
212 'type' => 'object',
213 'properties' => array(
214 'name' => array(
215 'description' => __( 'Widget module name including namespace.', 'gutenberg' ),
216 'type' => 'string',
217 'context' => array( 'view', 'edit', 'embed' ),
218 'readonly' => true,
219 ),
220 'render_module' => array(
221 'description' => __( 'Script-module handle for the widget render entry point.', 'gutenberg' ),
222 'type' => array( 'string', 'null' ),
223 'context' => array( 'view', 'edit', 'embed' ),
224 'readonly' => true,
225 ),
226 'widget_module' => array(
227 'description' => __( 'Script-module handle for the widget metadata entry point.', 'gutenberg' ),
228 'type' => array( 'string', 'null' ),
229 'context' => array( 'view', 'edit', 'embed' ),
230 'readonly' => true,
231 ),
232 ),
233 );
234
235 $this->schema = $schema;
236
237 return $this->add_additional_fields_schema( $this->schema );
238 }
239 }
240 }
241