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 / mcp / abilities / list-components-ability.php

list-components-ability.php in Elementor Website Builder – more than just a page builder 4.3.0-beta3, at modules/mcp/abilities/list-components-ability.php

235 lines 6.3 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\Mcp\Abilities;
4
5 use Elementor\Modules\Components\Components_Access_Controller;
6 use Elementor\Modules\Components\Components_Repository;
7 use Elementor\Modules\Components\Documents\Component_Overridable_Prop;
8 use Elementor\Modules\Components\Utils\Parsing_Utils;
9 use Elementor\Modules\Mcp\Abilities\Utils\Prompt_Loader;
10 use Elementor\Modules\Mcp\Abilities\Utils\Widget_Context_Helper;
11
12 if ( ! defined( 'ABSPATH' ) ) {
13 exit;
14 }
15
16 class List_Components_Ability extends Abstract_Ability {
17
18 protected function get_ability_id(): string {
19 return 'elementor/list-components';
20 }
21
22 public function is_exposed_via_proxy(): bool {
23 return false;
24 }
25
26 protected function get_definition(): Ability_Definition {
27 return new Ability_Definition(
28 __( 'List Elementor Components', 'elementor' ),
29 Prompt_Loader::load( 'list-components' ),
30 'elementor',
31 [
32 'type' => 'object',
33 'properties' => [
34 'components' => [
35 'type' => 'array',
36 'items' => [
37 'type' => 'object',
38 'properties' => [
39 'id' => [ 'type' => 'integer' ],
40 'name' => [ 'type' => 'string' ],
41 'uid' => [ 'type' => 'string' ],
42 'is_archived' => [
43 'type' => 'boolean',
44 'description' => 'Only present for components requested via component_ids. The discovery list never includes archived components.',
45 ],
46 'overridable_props' => [
47 'type' => 'object',
48 'description' => 'Only present for components requested via component_ids.',
49 ],
50 ],
51 ],
52 ],
53 'capabilities' => [
54 'type' => 'object',
55 'description' => 'Component operations available to the current user and license tier.',
56 'properties' => [
57 'can_create' => [ 'type' => 'boolean' ],
58 'can_edit' => [ 'type' => 'boolean' ],
59 'can_add_to_page' => [ 'type' => 'boolean' ],
60 ],
61 ],
62 ],
63 ],
64 [
65 'annotations' => [
66 'readonly' => true,
67 'idempotent' => true,
68 'destructive' => false,
69 ],
70 ],
71 fn() => current_user_can( 'edit_posts' ),
72 [
73 'type' => 'object',
74 'properties' => [
75 'component_ids' => [
76 'type' => 'array',
77 'items' => [ 'type' => 'integer' ],
78 'description' => 'Post IDs of the components you intend to place. Omit to list every component without its overridable props, then call again with the ids you need.',
79 ],
80 ],
81 ]
82 );
83 }
84
85 public function execute( $input = [] ) {
86 $input = is_array( $input ) ? $input : [];
87 $requested_ids = is_array( $input['component_ids'] ?? null ) ? $input['component_ids'] : [];
88
89 if ( empty( $requested_ids ) ) {
90 return $this->build_response( $this->build_summaries() );
91 }
92
93 $component_ids = $this->normalize_ids( $requested_ids );
94
95 if ( empty( $component_ids ) ) {
96 return new \WP_Error(
97 'invalid_input',
98 __( 'component_ids must contain positive integers.', 'elementor' ),
99 [ 'status' => \WP_Http::BAD_REQUEST ]
100 );
101 }
102
103 $result = $this->build_schemas( $component_ids );
104
105 if ( is_wp_error( $result ) ) {
106 return $result;
107 }
108
109 return $this->build_response( $result['components'] );
110 }
111
112 private function build_response( array $components ): array {
113 $can_manage_components = current_user_can( 'manage_options' );
114
115 return [
116 'components' => $components,
117 'capabilities' => [
118 'can_create' => $can_manage_components && Components_Access_Controller::can_create(),
119 'can_edit' => $can_manage_components && Components_Access_Controller::can_edit(),
120 'can_add_to_page' => current_user_can( 'edit_posts' ) && Components_Access_Controller::can_add_to_page(),
121 ],
122 ];
123 }
124
125 private function build_summaries(): array {
126 $repository = new Components_Repository();
127
128 return array_values(
129 $repository->all()
130 ->filter( fn( $component ) => ! ( $component['is_archived'] ?? false ) )
131 ->map( fn( $component ) => [
132 'id' => $component['id'],
133 'name' => $component['title'],
134 'uid' => $component['uid'],
135 ] )
136 ->all()
137 );
138 }
139
140 private function build_schemas( array $component_ids ) {
141 $repository = new Components_Repository();
142 $components = [];
143 $not_found = [];
144
145 foreach ( $component_ids as $component_id ) {
146 $component = $repository->get( $component_id, false );
147
148 if ( ! $component ) {
149 $not_found[] = $component_id;
150 continue;
151 }
152
153 $components[] = [
154 'id' => $component->get_main_id(),
155 'name' => $component->get_post()->post_title,
156 'uid' => $component->get_component_uid(),
157 'is_archived' => $component->get_is_archived(),
158 'overridable_props' => $this->build_props_schema( $component->get_overridable_props()->props ),
159 ];
160 }
161
162 if ( ! empty( $not_found ) ) {
163 return new \WP_Error(
164 'elementor_not_found',
165 sprintf(
166 /* translators: %s: comma-separated list of component IDs */
167 __( 'Components not found: %s.', 'elementor' ),
168 implode( ', ', $not_found )
169 ),
170 [ 'status' => \WP_Http::NOT_FOUND ]
171 );
172 }
173
174 return [ 'components' => $components ];
175 }
176
177 private function normalize_ids( array $raw ): array {
178 $ids = [];
179
180 foreach ( $raw as $value ) {
181 $id = (int) $value;
182
183 if ( $id > 0 ) {
184 $ids[ $id ] = $id;
185 }
186 }
187
188 return array_values( $ids );
189 }
190
191 private function build_props_schema( array $props ): array {
192 $schema = [];
193
194 foreach ( $props as $prop ) {
195 /** @var Component_Overridable_Prop $prop */
196 $origin_prop_schema = $this->resolve_origin_prop_schema( $prop );
197
198 $entry = [
199 'label' => $prop->label,
200 'group_id' => $prop->group_id,
201 ];
202
203 if ( $origin_prop_schema ) {
204 $entry['origin_prop_schema'] = $origin_prop_schema;
205 }
206
207 $schema[ $prop->override_key ] = $entry;
208 }
209
210 return $schema;
211 }
212
213 private function resolve_origin_prop_schema( Component_Overridable_Prop $prop ): ?array {
214 try {
215 if ( $prop->origin_prop_fields ) {
216 $prop_type = Parsing_Utils::get_prop_type(
217 $prop->origin_prop_fields['el_type'],
218 $prop->origin_prop_fields['widget_type'],
219 $prop->origin_prop_fields['prop_key']
220 );
221 } else {
222 $prop_type = Parsing_Utils::get_prop_type(
223 $prop->el_type,
224 $prop->widget_type,
225 $prop->prop_key
226 );
227 }
228
229 return Widget_Context_Helper::to_plain_llm_schema( $prop_type );
230 } catch ( \Exception $e ) {
231 return null;
232 }
233 }
234 }
235