PluginProbe
Elementor Website Builder – more than just a page builder / 4.3.0-beta3
Elementor Website Builder – more than just a page builder v4.3.0-beta3
4.3.0-beta3 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 All 452 releases
elementor / modules / atomic-widgets / css-converter / css-converter-rest-api.php

css-converter-rest-api.php in Elementor Website Builder – more than just a page builder 4.3.0-beta3, at modules/atomic-widgets/css-converter/css-converter-rest-api.php

166 lines 4.8 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\AtomicWidgets\CssConverter;
4
5 use Elementor\Core\Utils\Api\Error_Builder;
6 use Elementor\Core\Utils\Api\Response_Builder;
7 use Elementor\Modules\AtomicWidgets\CssConverter\Metrics\Null_Failure_Reporter;
8 use Elementor\Modules\AtomicWidgets\Module as AtomicWidgetsModule;
9 use Elementor\Modules\Variables\Module as Variables_Module;
10 use Elementor\Modules\Variables\Services\Batch_Operations\Batch_Processor;
11 use Elementor\Modules\Variables\Services\Variables_Service;
12 use Elementor\Modules\Variables\Storage\Variables_Repository;
13 use Elementor\Plugin;
14
15 if ( ! defined( 'ABSPATH' ) ) {
16 exit; // Exit if accessed directly.
17 }
18
19 class Css_Converter_REST_API {
20 const API_NAMESPACE = 'elementor/v1';
21 const API_BASE = 'css-to-atomic';
22
23 public function register_hooks() {
24 add_action( 'rest_api_init', fn() => $this->register_routes() );
25 }
26
27 private function register_routes() {
28 register_rest_route( self::API_NAMESPACE, '/' . self::API_BASE, [
29 [
30 'methods' => 'POST',
31 'callback' => fn( $request ) => $this->route_wrapper( fn() => $this->convert( $request ) ),
32 'permission_callback' => fn() => current_user_can( 'edit_posts' ),
33 'args' => [
34 'blocks' => [
35 'type' => 'object',
36 'required' => true,
37 ],
38 ],
39 ],
40 ] );
41 }
42
43 private function convert( \WP_REST_Request $request ) {
44 $blocks = $request->get_param( 'blocks' );
45
46 if ( ! is_array( $blocks ) ) {
47 return Error_Builder::make( 'invalid_blocks' )
48 ->set_status( 400 )
49 ->set_message( __( 'The "blocks" parameter must be an object of named CSS blocks.', 'elementor' ) )
50 ->build();
51 }
52
53 $converter = $this->create_converter();
54
55 $results = [];
56
57 foreach ( $blocks as $name => $block ) {
58 if ( is_string( $block ) ) {
59 $results[ $name ] = $this->convert_css_text( $converter, $block );
60 continue;
61 }
62
63 if ( ! is_array( $block ) ) {
64 return Error_Builder::make( 'invalid_block' )
65 ->set_status( 400 )
66 ->set_message( __( 'Each block must be a CSS text string or a property declaration map.', 'elementor' ) )
67 ->build();
68 }
69
70 $results[ $name ] = $this->convert_block( $converter, $block );
71 }
72
73 return Response_Builder::make( $results )->build();
74 }
75
76 /**
77 * @return array{props: object, customCss: string, rejected: string[]}
78 */
79 private function convert_css_text( Css_Converter $converter, string $css ): array {
80 $result = $converter->convert( $css );
81
82 return [
83 'props' => (object) $result['props'],
84 'customCss' => $result['customCss'],
85 'rejected' => $result['rejected'],
86 ];
87 }
88
89 /**
90 * A block is a property->value map. A null value is an explicit reset: it bypasses CSS conversion
91 * and is emitted as a null prop so the editor restores the property to its default. Every non-null
92 * value is serialized back into a CSS declaration for the converter.
93 *
94 * @param Css_Converter $converter The shared CSS converter.
95 * @param array<string, string|null> $declarations The block's property->value map.
96 * @return array{props: object, customCss: string, rejected: string[]}
97 */
98 private function convert_block( Css_Converter $converter, array $declarations ): array {
99 $css_declarations = [];
100
101 foreach ( $declarations as $property => $value ) {
102 $is_null_reset = null === $value || 'null' === $value;
103
104 $css_declarations[] = $property . ': ' . ( $is_null_reset ? 'null' : $value ) . ';';
105 }
106
107 $result = $converter->convert( implode( ' ', $css_declarations ) );
108
109 return [
110 'props' => (object) $result['props'],
111 'customCss' => $result['customCss'],
112 'rejected' => $result['rejected'],
113 ];
114 }
115
116 private function create_converter(): Css_Converter {
117 $variables_service = $this->create_variables_service();
118 $variable_transformer = $variables_service
119 ? new Variable_Prop_Value_Transformer( $variables_service )
120 : null;
121
122 return new Css_Converter(
123 Converter_Registry_Factory::create( $variables_service ),
124 new Null_Failure_Reporter(),
125 Expander_Registry_Factory::create( $variables_service ),
126 $variable_transformer
127 );
128 }
129
130 private function create_variables_service(): ?Variables_Service {
131 if ( ! $this->is_variables_active() ) {
132 return null;
133 }
134
135 $kit = Plugin::$instance->kits_manager->get_active_kit();
136
137 if ( ! $kit ) {
138 return null;
139 }
140
141 return new Variables_Service(
142 new Variables_Repository( $kit ),
143 new Batch_Processor()
144 );
145 }
146
147 private function is_variables_active(): bool {
148 $experiments = Plugin::$instance->experiments;
149
150 return $experiments->is_feature_active( Variables_Module::EXPERIMENT_NAME )
151 && $experiments->is_feature_active( AtomicWidgetsModule::EXPERIMENT_NAME );
152 }
153
154 private function route_wrapper( callable $cb ) {
155 try {
156 $response = $cb();
157 } catch ( \Exception $e ) {
158 return Error_Builder::make( 'unexpected_error' )
159 ->set_message( __( 'Something went wrong', 'elementor' ) )
160 ->build();
161 }
162
163 return $response;
164 }
165 }
166