PluginProbe
Elementor Website Builder – more than just a page builder / 3.32.4
Elementor Website Builder – more than just a page builder v3.32.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 / modules / global-classes / global-classes-rest-api.php

global-classes-rest-api.php in Elementor Website Builder – more than just a page builder 3.32.4, at modules/global-classes/global-classes-rest-api.php

230 lines 6.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Elementor\Modules\GlobalClasses;
4
5 use Elementor\Modules\GlobalClasses\Usage\Applied_Global_Classes_Usage;
6 use Elementor\Core\Utils\Api\Error_Builder;
7 use Elementor\Core\Utils\Api\Response_Builder;
8 use Elementor\Modules\GlobalClasses\Database\Migrations\Add_Capabilities;
9
10 if ( ! defined( 'ABSPATH' ) ) {
11 exit; // Exit if accessed directly.
12 }
13
14 class Global_Classes_REST_API {
15 const API_NAMESPACE = 'elementor/v1';
16 const API_BASE = 'global-classes';
17 const API_BASE_USAGE = self::API_BASE . '/usage';
18 const MAX_ITEMS = 50;
19
20 private $repository = null;
21
22 public function register_hooks() {
23 add_action( 'rest_api_init', fn() => $this->register_routes() );
24 }
25
26 private function get_repository() {
27 if ( ! $this->repository ) {
28 $this->repository = new Global_Classes_Repository();
29 }
30
31 return $this->repository;
32 }
33
34 private function register_routes() {
35 register_rest_route( self::API_NAMESPACE, '/' . self::API_BASE, [
36 [
37 'methods' => 'GET',
38 'callback' => fn( $request ) => $this->route_wrapper( fn() => $this->all( $request ) ),
39 'permission_callback' => fn() => is_user_logged_in(),
40 'args' => [
41 'context' => [
42 'type' => 'string',
43 'required' => false,
44 'default' => Global_Classes_Repository::CONTEXT_FRONTEND,
45 'enum' => [
46 Global_Classes_Repository::CONTEXT_FRONTEND,
47 Global_Classes_Repository::CONTEXT_PREVIEW,
48 ],
49 ],
50 ],
51 ],
52 ] );
53
54 register_rest_route( self::API_NAMESPACE, '/' . self::API_BASE_USAGE, [
55 [
56 'callback' => fn() => $this->route_wrapper( fn() => $this->get_usage() ),
57 'permission_callback' => fn() => current_user_can( 'manage_options' ),
58 'args' => [
59 'context' => [
60 'type' => 'string',
61 'required' => false,
62 'default' => Global_Classes_Repository::CONTEXT_FRONTEND,
63 'enum' => [
64 Global_Classes_Repository::CONTEXT_FRONTEND,
65 Global_Classes_Repository::CONTEXT_PREVIEW,
66 ],
67 ],
68 ],
69 ],
70 ] );
71
72 register_rest_route( self::API_NAMESPACE, '/' . self::API_BASE, [
73 [
74 'methods' => 'PUT',
75 'callback' => fn( $request ) => $this->route_wrapper( fn() => $this->put( $request ) ),
76 'permission_callback' => fn() => current_user_can( Add_Capabilities::UPDATE_CLASS ),
77 'args' => [
78 'context' => [
79 'type' => 'string',
80 'required' => false,
81 'default' => Global_Classes_Repository::CONTEXT_FRONTEND,
82 'enum' => [
83 Global_Classes_Repository::CONTEXT_FRONTEND,
84 Global_Classes_Repository::CONTEXT_PREVIEW,
85 ],
86 ],
87 'changes' => [
88 'type' => 'object',
89 'required' => true,
90 'additionalProperties' => false,
91 'properties' => [
92 'added' => [
93 'type' => 'array',
94 'required' => true,
95 'items' => [ 'type' => 'string' ],
96 ],
97 'deleted' => [
98 'type' => 'array',
99 'required' => true,
100 'items' => [ 'type' => 'string' ],
101 ],
102 'modified' => [
103 'type' => 'array',
104 'required' => true,
105 'items' => [ 'type' => 'string' ],
106 ],
107 ],
108 ],
109 'items' => [
110 'required' => true,
111 'type' => 'object',
112 'additionalProperties' => [
113 'type' => 'object',
114 'properties' => [
115 'id' => [
116 'type' => 'string',
117 'required' => true,
118 ],
119 'variants' => [
120 'type' => 'array',
121 'required' => true,
122 ],
123 'type' => [
124 'type' => 'string',
125 'enum' => [ 'class' ],
126 'required' => true,
127 ],
128 'label' => [
129 'type' => 'string',
130 'required' => true,
131 ],
132 ],
133 ],
134 ],
135 'order' => [
136 'required' => true,
137 'type' => 'array',
138 'items' => [
139 'type' => 'string',
140 ],
141 ],
142 ],
143 ],
144 ] );
145 }
146
147 private function all( \WP_REST_Request $request ) {
148 $context = $request->get_param( 'context' );
149
150 $classes = $this->get_repository()->context( $context )->all();
151
152 return Response_Builder::make( (object) $classes->get_items()->all() )
153 ->set_meta( [ 'order' => $classes->get_order()->all() ] )
154 ->build();
155 }
156
157 private function get_usage() {
158 $classes_usage = ( new Applied_Global_Classes_Usage() )->get_detailed_usage();
159
160 return Response_Builder::make( (object) $classes_usage )->build();
161 }
162
163 private function put( \WP_REST_Request $request ) {
164 $parser = Global_Classes_Parser::make();
165
166 $items_result = $parser->parse_items(
167 $request->get_param( 'items' )
168 );
169
170 $items_count = count( $items_result->unwrap() );
171
172 if ( $items_count > static::MAX_ITEMS ) {
173 return Error_Builder::make( 'global_classes_limit_exceeded' )
174 ->set_status( 400 )
175 ->set_message( sprintf(
176 /* translators: %d: Maximum allowed items. */
177 __( 'Global classes limit exceeded. Maximum allowed: %d', 'elementor' ),
178 static::MAX_ITEMS
179 ) )
180 ->build();
181 }
182
183 if ( ! $items_result->is_valid() ) {
184 return Error_Builder::make( 'invalid_items' )
185 ->set_status( 400 )
186 ->set_message( 'Invalid items: ' . $items_result->errors()->to_string() )
187 ->build();
188 }
189
190 $order_result = $parser->parse_order(
191 $request->get_param( 'order' ),
192 $items_result->unwrap()
193 );
194
195 if ( ! $order_result->is_valid() ) {
196 return Error_Builder::make( 'invalid_order' )
197 ->set_status( 400 )
198 ->set_message( 'Invalid order: ' . $order_result->errors()->to_string() )
199 ->build();
200 }
201
202 $repository = $this->get_repository()
203 ->context( $request->get_param( 'context' ) );
204
205 $changes_resolver = Global_Classes_Changes_Resolver::make(
206 $repository,
207 $request->get_param( 'changes' ) ?? [],
208 );
209
210 $repository->put(
211 $changes_resolver->resolve_items( $items_result->unwrap() ),
212 $changes_resolver->resolve_order( $order_result->unwrap() ),
213 );
214
215 return Response_Builder::make()->no_content()->build();
216 }
217
218 private function route_wrapper( callable $cb ) {
219 try {
220 $response = $cb();
221 } catch ( \Exception $e ) {
222 return Error_Builder::make( 'unexpected_error' )
223 ->set_message( __( 'Something went wrong', 'elementor' ) )
224 ->build();
225 }
226
227 return $response;
228 }
229 }
230