PluginProbe
Elementor Website Builder – more than just a page builder / 3.28.0-dev3
Elementor Website Builder – more than just a page builder v3.28.0-dev3
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 3.28.0-dev3, at data/v2/base/controller.php

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