PluginProbe
Elementor Website Builder – more than just a page builder / 4.2.4
Elementor Website Builder – more than just a page builder v4.2.4
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 / data / v2 / base / controller.php

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

482 lines 11.8 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 * @throws WP_Error_Exception If API request validation fails, permissions are insufficient, or processing errors occur.
202 */
203 public function get_permission_callback( $request ) {
204 $is_multi = (bool) $request->get_param( 'is_multi' );
205
206 $result = false;
207
208 // The function is public since endpoint need to access it.
209 // Utilize 'WP_REST_Controller' get_permission_check methods.
210 switch ( $request->get_method() ) {
211 case 'GET':
212 $result = $is_multi ? $this->get_items_permissions_check( $request ) : $this->get_item_permissions_check( $request );
213 break;
214 case 'POST':
215 $result = $is_multi ? $this->create_items_permissions_check( $request ) : $this->create_item_permissions_check( $request );
216 break;
217 case 'UPDATE':
218 case 'PUT':
219 case 'PATCH':
220 $result = $is_multi ? $this->update_items_permissions_check( $request ) : $this->update_item_permissions_check( $request );
221 break;
222
223 case 'DELETE':
224 $result = $is_multi ? $this->delete_items_permissions_check( $request ) : $this->delete_item_permissions_check( $request );
225 break;
226 }
227
228 if ( $result instanceof \WP_Error ) {
229 throw new WP_Error_Exception( esc_html( $result ) );
230 }
231
232 return $result;
233 }
234
235 /**
236 * Checks if a given request has access to create items.
237 *
238 * @param \WP_REST_Request $request Full details about the request.
239 *
240 * @return true|\WP_Error True if the request has access to create items, WP_Error object otherwise.
241 */
242 public function create_items_permissions_check( $request ) {
243 return new \WP_Error( 'invalid-method', sprintf( "Method '%s' not implemented. Must be overridden in subclass.", __METHOD__ ), [ 'status' => 405 ] );
244 }
245
246 /**
247 * Checks if a given request has access to update items.
248 *
249 * @param \WP_REST_Request $request Full details about the request.
250 *
251 * @return true|\WP_Error True if the request has access to update the item, WP_Error object otherwise.
252 */
253 public function update_items_permissions_check( $request ) {
254 return new \WP_Error( 'invalid-method', sprintf( "Method '%s' not implemented. Must be overridden in subclass.", __METHOD__ ), [ 'status' => 405 ] );
255 }
256
257 /**
258 * Checks if a given request has access to delete items.
259 *
260 * @param \WP_REST_Request $request Full details about the request.
261 *
262 * @return true|\WP_Error True if the request has access to delete the item, WP_Error object otherwise.
263 */
264 public function delete_items_permissions_check( $request ) {
265 return new \WP_Error( 'invalid-method', sprintf( "Method '%s' not implemented. Must be overridden in subclass.", __METHOD__ ), [ 'status' => 405 ] );
266 }
267
268 public function get_items( $request ) {
269 return $this->get_controller_index();
270 }
271
272 /**
273 * Creates multiple items.
274 *
275 * @param \WP_REST_Request $request Full data about the request.
276 *
277 * @return \WP_Error|\WP_REST_Response Response object on success, or WP_Error object on failure.
278 */
279 public function create_items( $request ) {
280 return new \WP_Error( 'invalid-method', sprintf( "Method '%s' not implemented. Must be overridden in subclass.", __METHOD__ ), [ 'status' => 405 ] );
281 }
282
283 /**
284 * Updates multiple items.
285 *
286 * @param \WP_REST_Request $request Full data about the request.
287 *
288 * @return \WP_Error|\WP_REST_Response Response object on success, or WP_Error object on failure.
289 */
290 public function update_items( $request ) {
291 return new \WP_Error( 'invalid-method', sprintf( "Method '%s' not implemented. Must be overridden in subclass.", __METHOD__ ), [ 'status' => 405 ] );
292 }
293
294 /**
295 * Delete multiple items.
296 *
297 * @param \WP_REST_Request $request Full data about the request.
298 *
299 * @return \WP_Error|\WP_REST_Response Response object on success, or WP_Error object on failure.
300 */
301 public function delete_items( $request ) {
302 return new \WP_Error( 'invalid-method', sprintf( "Method '%s' not implemented. Must be overridden in subclass.", __METHOD__ ), [ 'status' => 405 ] );
303 }
304
305 /**
306 * Get the parent controller.
307 *
308 * @return \Elementor\Data\V2\Base\Controller|null
309 */
310 public function get_parent() {
311 return $this->parent;
312 }
313
314 /**
315 * Get sub controller(s).
316 *
317 * @return \Elementor\Data\V2\Base\Controller[]
318 */
319 public function get_sub_controllers() {
320 return $this->sub_controllers;
321 }
322
323 /**
324 * Get processors.
325 *
326 * @param string $command
327 *
328 * @return \Elementor\Data\V2\Base\Processor[]
329 */
330 public function get_processors( $command ) {
331 $result = [];
332
333 if ( isset( $this->processors[ $command ] ) ) {
334 $result = $this->processors[ $command ];
335 }
336
337 return $result;
338 }
339
340 /**
341 * Register processors.
342 */
343 public function register_processors() {
344 }
345
346 /**
347 * Register index endpoint.
348 */
349 protected function register_index_endpoint() {
350 if ( ! $this->parent ) {
351 $this->register_endpoint( new Endpoint\Index( $this ) );
352
353 return;
354 }
355
356 $this->register_endpoint( new Endpoint\Index\Sub_Index_Endpoint( $this ) );
357 }
358
359 /**
360 * Register endpoint.
361 *
362 * @param \Elementor\Data\V2\Base\Endpoint $endpoint
363 *
364 * @return \Elementor\Data\V2\Base\Endpoint
365 */
366 protected function register_endpoint( Endpoint $endpoint ) {
367 $command = $endpoint->get_full_command();
368
369 if ( $endpoint instanceof Endpoint\Index ) {
370 $this->index_endpoint = $endpoint;
371 } else {
372 $this->endpoints[ $command ] = $endpoint;
373 }
374
375 $format = $endpoint->get_format();
376
377 // `$e.data.registerFormat()`.
378 Manager::instance()->register_endpoint_format( $command, $format );
379
380 return $endpoint;
381 }
382
383 /**
384 * Register a processor.
385 *
386 * That will be later attached to the endpoint class.
387 *
388 * @param Processor $processor
389 *
390 * @return \Elementor\Data\V2\Base\Processor $processor_instance
391 */
392 protected function register_processor( Processor $processor ) {
393 $command = $processor->get_command();
394
395 if ( ! isset( $this->processors[ $command ] ) ) {
396 $this->processors[ $command ] = [];
397 }
398
399 $this->processors[ $command ] [] = $processor;
400
401 return $processor;
402 }
403
404 /**
405 * Register.
406 *
407 * Endpoints & processors.
408 */
409 protected function register() {
410 $this->register_index_endpoint();
411 $this->register_endpoints();
412
413 // Aka hooks.
414 $this->register_processors();
415 }
416
417 /**
418 * Get collection params by 'additionalProperties' context.
419 *
420 * @param string $context
421 *
422 * @return array
423 */
424 protected function get_collection_params_by_additional_props_context( $context ) {
425 $result = [];
426
427 $collection_params = $this->get_collection_params();
428
429 foreach ( $collection_params as $collection_param_key => $collection_param ) {
430 if ( isset( $collection_param['additionalProperties']['context'] ) && $context === $collection_param['additionalProperties']['context'] ) {
431 $result[ $collection_param_key ] = $collection_param;
432 }
433 }
434
435 return $result;
436 }
437
438 /**
439 * When `$this->get_parent_name` is extended, the controller will have a parent, and will know to behave like a sub-controller.
440 *
441 * @param string $parent_name
442 */
443 private function act_as_sub_controller( $parent_name ) {
444 $this->parent = Manager::instance()->get_controller( $parent_name );
445
446 if ( ! $this->parent ) {
447 trigger_error( "Cannot find parent controller: '$parent_name'", E_USER_ERROR ); // phpcs:ignore
448 }
449
450 $this->parent->sub_controllers [] = $this;
451 }
452
453 /**
454 * Controller constructor.
455 *
456 * Register endpoints on 'rest_api_init'.
457 */
458 public function __construct() {
459 $this->namespace = static::get_default_namespace() . '/v' . static::get_default_version();
460 $this->rest_base = $this->get_name();
461
462 add_action( 'rest_api_init', function () {
463 $this->register(); // Because 'register' is protected.
464 } );
465
466 /**
467 * Since all actions were removed for custom internal REST server.
468 * Re-add the actions.
469 */
470 add_action( 'elementor_rest_api_before_init', function () {
471 add_action( 'rest_api_init', function () {
472 $this->register();
473 } );
474 } );
475
476 $parent_name = $this->get_parent_name();
477 if ( $parent_name ) {
478 $this->act_as_sub_controller( $parent_name );
479 }
480 }
481 }
482