/var/www/html_it/wp-content/plugins/elementor/modules/components/components-rest-api.php


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
<?php

namespace Elementor\Modules\Components;

use 
Elementor\Core\Utils\Api\Error_Builder;
use 
Elementor\Core\Utils\Api\Response_Builder;

if ( ! 
defined'ABSPATH' ) ) {
    exit; 
// Exit if accessed directly.
}

class 
Components_REST_API {
    const 
API_NAMESPACE 'elementor/v1';
    const 
API_BASE 'components';
    const 
STYLES_ROUTE 'styles';
    const 
MAX_COMPONENTS 50;

    private 
$repository null;

    public function 
register_hooks() {
        
add_action'rest_api_init', fn() => $this->register_routes() );
    }

    private function 
get_repository() {
        if ( ! 
$this->repository ) {
            
$this->repository = new Components_Repository();
        }

        return 
$this->repository;
    }

    private function 
register_routes() {
        
register_rest_routeself::API_NAMESPACE'/' self::API_BASE, [
            [
                
'methods' => 'GET',
                
'callback' => fn() => $this->route_wrapper( fn() => $this->get_components() ),
                
'permission_callback' => fn() => is_user_logged_in(),
            ],
        ] );

        
register_rest_routeself::API_NAMESPACE'/' self::API_BASE '/' self::STYLES_ROUTE, [
            [
                
'methods' => 'GET',
                
'callback' => fn() => $this->route_wrapper( fn() => $this->get_styles() ),
                
'permission_callback' => fn() => is_user_logged_in(),
            ],
        ] );

        
register_rest_routeself::API_NAMESPACE'/' self::API_BASE, [
            [
                
'methods' => 'POST',
                
'callback' => fn( $request ) => $this->route_wrapper( fn() => $this->create_component$request ) ),
                
'permission_callback' => fn() => current_user_can'manage_options' ),
                
'args' => [
                    
'name' => [
                        
'type' => 'string',
                        
'required' => true,
                    ],
                    
'content' => [
                        
'type' => 'array',
                        
'required' => true,
                        
'items' => [
                            
'type' => 'object',
                        ],
                    ],
                ],
            ],
        ] );
    }

    private function 
get_components() {
        
$components $this->get_repository()->all();

        
$components_list $components->get_components()->map( fn( $component ) => [
            
'id' => $component['id'],
            
'name' => $component['name'],
        ])->
all();

        return 
Response_Builder::make$components_list )->build();
    }

    private function 
get_styles() {
        
$components $this->get_repository()->all();

        
$styles = [];
        
$components->get_components()->each( function( $component ) use ( &$styles ) {
            
$styles$component['id'] ] = $component['styles'];
        } );

        return 
Response_Builder::make$styles )->build();
    }
    private function 
create_component\WP_REST_Request $request ) {
        
$components $this->get_repository()->all();
        
$components_count $components->get_components()->count();

        if ( 
$components_count >= static::MAX_COMPONENTS ) {
            return 
Error_Builder::make'components_limit_exceeded' )
                ->
set_status400 )
                ->
set_messagesprintf(
                    
/* translators: %d: maximum components limit. */
                    
__'Components limit exceeded. Maximum allowed: %d''elementor' ),
                    static::
MAX_COMPONENTS
                
) )
                ->
build();
        }

        
$parser Components_Parser::make();

        
$name_result $parser->parse_name$request->get_param'name' ), $components->get_components()->map( fn( $component ) => $component['name'] )->all() );

        if ( ! 
$name_result->is_valid() ) {
            return 
Error_Builder::make'invalid_name' )
                ->
set_status400 )
                ->
set_message'Invalid component name: ' $name_result->errors()->to_string() )
                ->
build();
        }

        
$name $name_result->unwrap();
        
// The content is validated & sanitized in the document save process.
        
$content $request->get_param'content' );

        try {
            
$component_id $this->get_repository()->create$name$content );

            return 
Response_Builder::make( [ 'component_id' => $component_id ] )->set_status201 )->build();
        } catch ( 
\Exception $e ) {
            
$error_message $e->getMessage();

            
$invalid_elements_structure_error str_contains$error_message'Invalid data' );
            
$atomic_styles_validation_error str_contains$error_message'Styles validation failed' );
            
$atomic_settings_validation_error str_contains$error_message'Settings validation failed' );

            if ( 
$invalid_elements_structure_error || $atomic_styles_validation_error || $atomic_settings_validation_error ) {
                return 
Error_Builder::make'content_validation_failed' )
                                            ->
set_status400 )
                                            ->
set_message$error_message )
                                            ->
build();
            }

            throw 
$e;
        }
    }

    private function 
route_wrapper( callable $cb ) {
        try {
            
$response $cb();
        } catch ( 
\Exception $e ) {
            return 
Error_Builder::make'unexpected_error' )
                ->
set_message__'Something went wrong''elementor' ) )
                ->
build();
        }

        return 
$response;
    }
}