PluginProbe
Elementor Website Builder – more than just a page builder / 3.6.0-dev1
Elementor Website Builder – more than just a page builder v3.6.0-dev1
4.3.0-beta2 4.3.0-beta1 4.2.4 4.2.3 4.2.2 4.2.1 4.2.0 4.1.5 4.2.0-beta2 4.2.0-dev2 4.2.0-beta1 4.1.4 4.1.3 4.1.2 4.1.1 4.1.0 4.1.0-beta3 4.1.0-dev3 4.0.9 4.1.0-beta2 4.1.0-dev2 4.0.8 4.1.0-beta1 4.1.0-dev1 4.0.7 All 451 releases
elementor / trunk / data / v2 / base / controller.php

controller.php in Elementor Website Builder – more than just a page builder 3.6.0-dev1, at trunk/data/v2/base/controller.php

481 lines 11.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace Elementor\Data\V2\Base;
3
4 use Elementor\Data\V2\Base\Exceptions\WP_Error_Exception;
5 use Elementor\Data\V2\Manager;
6 use WP_REST_Controller;
7
8 if ( ! defined( 'ABSPATH' ) ) {
9 exit; // Exit if accessed directly
10 }
11
12 /**
13 * TODO: Utilize 'WP_REST_Controller' as much as possible.
14 */
15 abstract class Controller extends WP_REST_Controller {
16
17 /**
18 * Loaded endpoint(s).
19 *
20 * @var \Elementor\Data\V2\Base\Endpoint[]
21 */
22 public $endpoints = [];
23
24 /**
25 * Index endpoint.
26 *
27 * @var \Elementor\Data\V2\Base\Endpoint\Index
28 */
29 public $index_endpoint = null;
30
31 /**
32 * Loaded processor(s).
33 *
34 * @var \Elementor\Data\V2\Base\Processor[][]
35 */
36 public $processors = [];
37
38 /**
39 * @var \Elementor\Data\V2\Base\Controller|null
40 */
41 private $parent = null;
42
43 /**
44 * @var \Elementor\Data\V2\Base\Controller[]
45 */
46 private $sub_controllers = [];
47
48 public static function get_default_namespace() {
49 return Manager::ROOT_NAMESPACE;
50 }
51
52 public static function get_default_version() {
53 return Manager::VERSION;
54 }
55
56 /**
57 * Get controller name.
58 *
59 * @return string
60 */
61 abstract public function get_name();
62
63 /**
64 * Register endpoints.
65 */
66 public function register_endpoints() {
67 }
68
69 public function register_routes() {
70 _doing_it_wrong( 'Elementor\Data\V2\Controller::register_routes', sprintf( "Method '%s' deprecated. use `register_endpoints()`.", __METHOD__ ), '3.5.0' );
71 }
72
73 /**
74 * Get parent controller name.
75 *
76 * @note: If `get_parent_name()` provided, controller will work as sub-controller.
77 *
78 * @returns null|string
79 */
80 public function get_parent_name() {
81 return null;
82 }
83
84 /**
85 * Get full controller name.
86 *
87 * The method exist to handle situations when parent exist, to include the parent name.
88 *
89 * @return string
90 */
91 public function get_full_name() {
92 if ( ! $this->parent ) {
93 return $this->get_name();
94 }
95
96 return $this->parent->get_name() . '/' . $this->get_name();
97 }
98
99 /**
100 * Get controller namespace.
101 *
102 * @return string
103 */
104 public function get_namespace() {
105 return $this->namespace;
106 }
107
108 /**
109 * Get controller reset base.
110 *
111 * @return string
112 */
113 public function get_base_route() {
114 if ( ! $this->parent ) {
115 return $this->rest_base;
116 }
117
118 return $this->parent->get_base_route() . '/' . $this->get_name();
119 }
120
121 /**
122 * Get controller route.
123 *
124 * @return string
125 */
126 public function get_controller_route() {
127 return $this->get_namespace() . '/' . $this->get_base_route();
128 }
129
130 /**
131 * Retrieves rest route(s) index for current controller.
132 *
133 * @return \WP_REST_Response|\WP_Error
134 */
135 public function get_controller_index() {
136 $server = rest_get_server();
137 $routes = $server->get_routes();
138
139 $endpoints = array_intersect_key( $server->get_routes(), $routes );
140
141 $controller_route = $this->get_controller_route();
142
143 array_walk( $endpoints, function ( &$item, $endpoint ) use ( &$endpoints, $controller_route ) {
144 if ( ! strstr( $endpoint, $controller_route ) ) {
145 unset( $endpoints[ $endpoint ] );
146 }
147 } );
148
149 $data = [
150 'namespace' => $this->get_namespace(),
151 'controller' => $controller_route,
152 'routes' => $server->get_data_for_routes( $endpoints ),
153 ];
154
155 $response = rest_ensure_response( $data );
156
157 // Link to the root index.
158 $response->add_link( 'up', rest_url( '/' ) );
159
160 return $response;
161 }
162
163 /**
164 * Get items args of index endpoint.
165 *
166 * Is method is used when `get_collection_params()` is not enough, and need of knowing the methods is required.
167 *
168 * @param string $methods
169 *
170 * @return array
171 */
172 public function get_items_args( $methods ) {
173 if ( \WP_REST_Server::READABLE === $methods ) {
174 return $this->get_collection_params();
175 }
176
177 return [];
178 }
179
180 /**
181 * Get item args of index endpoint.
182 *
183 * @param string $methods
184 *
185 * @return array
186 */
187 public function get_item_args( $methods ) {
188 return [];
189 }
190
191 /**
192 * Get permission callback.
193 *
194 * Default controller permission callback.
195 * By default endpoint will inherit the permission callback from the controller.
196 *
197 * @param \WP_REST_Request $request
198 *
199 * @return bool
200 */
201 public function get_permission_callback( $request ) {
202 $is_multi = (bool) $request->get_param( 'is_multi' );
203
204 $result = false;
205
206 // The function is public since endpoint need to access it.
207 // Utilize 'WP_REST_Controller' get_permission_check methods.
208 switch ( $request->get_method() ) {
209 case 'GET':
210 $result = $is_multi ? $this->get_items_permissions_check( $request ) : $this->get_item_permissions_check( $request );
211 break;
212 case 'POST':
213 $result = $is_multi ? $this->create_items_permissions_check( $request ) : $this->create_item_permissions_check( $request );
214 break;
215 case 'UPDATE':
216 case 'PUT':
217 case 'PATCH':
218 $result = $is_multi ? $this->update_items_permissions_check( $request ) : $this->update_item_permissions_check( $request );
219 break;
220
221 case 'DELETE':
222 $result = $is_multi ? $this->delete_items_permissions_check( $request ) : $this->delete_item_permissions_check( $request );
223 break;
224 }
225
226 if ( $result instanceof \WP_Error ) {
227 throw new WP_Error_Exception( $result );
228 }
229
230 return $result;
231 }
232
233 /**
234 * Checks if a given request has access to create items.
235 **
236 *
237 * @param \WP_REST_Request $request Full details about the request.
238 *
239 * @return true|\WP_Error True if the request has access to create items, WP_Error object otherwise.
240 */
241 public function create_items_permissions_check( $request ) {
242 return new \WP_Error( 'invalid-method', sprintf( "Method '%s' not implemented. Must be overridden in subclass.", __METHOD__ ), [ 'status' => 405 ] );
243 }
244
245 /**
246 * Checks if a given request has access to update items.
247 *
248 * @param \WP_REST_Request $request Full details about the request.
249 *
250 * @return true|\WP_Error True if the request has access to update the item, WP_Error object otherwise.
251 */
252 public function update_items_permissions_check( $request ) {
253 return new \WP_Error( 'invalid-method', sprintf( "Method '%s' not implemented. Must be overridden in subclass.", __METHOD__ ), [ 'status' => 405 ] );
254 }
255
256 /**
257 * Checks if a given request has access to delete items.
258 *
259 * @param \WP_REST_Request $request Full details about the request.
260 *
261 * @return true|\WP_Error True if the request has access to delete the item, WP_Error object otherwise.
262 */
263 public function delete_items_permissions_check( $request ) {
264 return new \WP_Error( 'invalid-method', sprintf( "Method '%s' not implemented. Must be overridden in subclass.", __METHOD__ ), [ 'status' => 405 ] );
265 }
266
267 public function get_items( $request ) {
268 return $this->get_controller_index();
269 }
270
271 /**
272 * Creates multiple items.
273 *
274 * @param \WP_REST_Request $request Full data about the request.
275 *
276 * @return \WP_Error|\WP_REST_Response Response object on success, or WP_Error object on failure.
277 */
278 public function create_items( $request ) {
279 return new \WP_Error( 'invalid-method', sprintf( "Method '%s' not implemented. Must be overridden in subclass.", __METHOD__ ), [ 'status' => 405 ] );
280 }
281
282 /**
283 * Updates multiple items.
284 *
285 * @param \WP_REST_Request $request Full data about the request.
286 *
287 * @return \WP_Error|\WP_REST_Response Response object on success, or WP_Error object on failure.
288 */
289 public function update_items( $request ) {
290 return new \WP_Error( 'invalid-method', sprintf( "Method '%s' not implemented. Must be overridden in subclass.", __METHOD__ ), [ 'status' => 405 ] );
291 }
292
293 /**
294 * Delete multiple items.
295 *
296 * @param \WP_REST_Request $request Full data about the request.
297 *
298 * @return \WP_Error|\WP_REST_Response Response object on success, or WP_Error object on failure.
299 */
300 public function delete_items( $request ) {
301 return new \WP_Error( 'invalid-method', sprintf( "Method '%s' not implemented. Must be overridden in subclass.", __METHOD__ ), [ 'status' => 405 ] );
302 }
303
304 /**
305 * Get the parent controller.
306 *
307 * @return \Elementor\Data\V2\Base\Controller|null
308 */
309 public function get_parent() {
310 return $this->parent;
311 }
312
313 /**
314 * Get sub controller(s).
315 *
316 * @return \Elementor\Data\V2\Base\Controller[]
317 */
318 public function get_sub_controllers() {
319 return $this->sub_controllers;
320 }
321
322 /**
323 * Get processors.
324 *
325 * @param string $command
326 *
327 * @return \Elementor\Data\V2\Base\Processor[]
328 */
329 public function get_processors( $command ) {
330 $result = [];
331
332 if ( isset( $this->processors[ $command ] ) ) {
333 $result = $this->processors[ $command ];
334 }
335
336 return $result;
337 }
338
339 /**
340 * Register processors.
341 */
342 public function register_processors() {
343 }
344
345 /**
346 * Register index endpoint.
347 */
348 protected function register_index_endpoint() {
349 if ( ! $this->parent ) {
350 $this->register_endpoint( new Endpoint\Index( $this ) );
351
352 return;
353 }
354
355 $this->register_endpoint( new Endpoint\Index\Sub_Index_Endpoint( $this ) );
356 }
357
358 /**
359 * Register endpoint.
360 *
361 * @param \Elementor\Data\V2\Base\Endpoint $endpoint
362 *
363 * @return \Elementor\Data\V2\Base\Endpoint
364 */
365 protected function register_endpoint( Endpoint $endpoint ) {
366 $command = $endpoint->get_full_command();
367
368 if ( $endpoint instanceof Endpoint\Index ) {
369 $this->index_endpoint = $endpoint;
370 } else {
371 $this->endpoints[ $command ] = $endpoint;
372 }
373
374 $format = $endpoint->get_format();
375
376 // `$e.data.registerFormat()`.
377 Manager::instance()->register_endpoint_format( $command, $format );
378
379 return $endpoint;
380 }
381
382 /**
383 * Register a processor.
384 *
385 * That will be later attached to the endpoint class.
386 *
387 * @param Processor $processor
388 *
389 * @return \Elementor\Data\V2\Base\Processor $processor_instance
390 */
391 protected function register_processor( Processor $processor ) {
392 $command = $processor->get_command();
393
394 if ( ! isset( $this->processors[ $command ] ) ) {
395 $this->processors[ $command ] = [];
396 }
397
398 $this->processors[ $command ] [] = $processor;
399
400 return $processor;
401 }
402
403 /**
404 * Register.
405 *
406 * Endpoints & processors.
407 */
408 protected function register() {
409 $this->register_index_endpoint();
410 $this->register_endpoints();
411
412 // Aka hooks.
413 $this->register_processors();
414 }
415
416 /**
417 * Get collection params by 'additionalProperties' context.
418 *
419 * @param string $context
420 *
421 * @return array
422 */
423 protected function get_collection_params_by_additional_props_context( $context ) {
424 $result = [];
425
426 $collection_params = $this->get_collection_params();
427
428 foreach ( $collection_params as $collection_param_key => $collection_param ) {
429 if ( isset( $collection_param['additionalProperties']['context'] ) && $context === $collection_param['additionalProperties']['context'] ) {
430 $result[ $collection_param_key ] = $collection_param;
431 }
432 }
433
434 return $result;
435 }
436
437 /**
438 * When `$this->get_parent_name` is extended, the controller will have a parent, and will know to behave like a sub-controller.
439 *
440 * @param string $parent_name
441 */
442 private function act_as_sub_controller( $parent_name ) {
443 $this->parent = Manager::instance()->get_controller( $parent_name );
444
445 if ( ! $this->parent ) {
446 trigger_error( "Cannot find parent controller: '$parent_name'", E_USER_ERROR ); // phpcs:ignore
447 }
448
449 $this->parent->sub_controllers [] = $this;
450 }
451
452 /**
453 * Controller constructor.
454 *
455 * Register endpoints on 'rest_api_init'.
456 */
457 public function __construct() {
458 $this->namespace = static::get_default_namespace() . '/v' . static::get_default_version();
459 $this->rest_base = $this->get_name();
460
461 add_action( 'rest_api_init', function () {
462 $this->register(); // Because 'register' is protected.
463 } );
464
465 /**
466 * Since all actions were removed for custom internal REST server.
467 * Re-add the actions.
468 */
469 add_action( 'elementor_rest_api_before_init', function () {
470 add_action( 'rest_api_init', function () {
471 $this->register();
472 } );
473 } );
474
475 $parent_name = $this->get_parent_name();
476 if ( $parent_name ) {
477 $this->act_as_sub_controller( $parent_name );
478 }
479 }
480 }
481