PluginProbe
Elementor Website Builder – more than just a page builder / 4.3.1
Elementor Website Builder – more than just a page builder v4.3.1
4.3.2 4.3.1 4.3.0 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 All 455 releases
← All changes | modules/mcp/abilities/utils/widget-context-helper.php +45 -8 4.3.0-beta1 → 4.3.1 View file →
@@ -4,8 +4,9 @@
4 4
5 5 use Elementor\Modules\AtomicWidgets\PropTypes\Base\Array_Prop_Type;
6 6 use Elementor\Modules\AtomicWidgets\PropTypes\Base\Object_Prop_Type;
7 7 use Elementor\Modules\AtomicWidgets\PropTypes\Contracts\Prop_Type;
8 +use Elementor\Modules\AtomicWidgets\PropTypes\Escaped_Html_Prop_Type;
8 9 use Elementor\Modules\AtomicWidgets\PropTypes\Utils\Plain_Llm_Schema_Converter;
9 10 use Elementor\Modules\GlobalClasses\Utils\Atomic_Elements_Utils;
10 11 use Elementor\Modules\Mcp\Abilities\Appliers\V3\V3_Widget_Bridge_Registry;
11 12 use Elementor\Plugin;
@@ -41,8 +42,10 @@
41 42 const V3_FALLBACK_MESSAGE = '`properties` lists the only keys accepted in `element_config` / `manage-elements.settings` for this widget. Put all visual styling in the `style` (CSS) input.';
42 43
43 44 const V3_FALLBACK_FIELDS_NOTE = 'All properties are optional. Object-typed properties describe common shapes but do not include exhaustive inner validation.';
44 45
46 + const ALLOWED_HTML_TAGS_NOTE = 'May contain inline HTML written directly in the string (e.g. "Hello <strong>world</strong>"), limited to these tags: %s. Any other tag is stripped on save.';
47 +
45 48 /**
46 49 * @return array<string, array> widget_type => config, filtered to widgets eligible for LLM use.
47 50 */
48 51 public static function get_llm_eligible_widgets(): array {
@@ -166,9 +169,9 @@
166 169 'additionalProperties' => false,
167 170 ] );
168 171 }
169 172
170 - $properties = self::build_configurable_properties_schema( $props_schema );
173 + $properties = self::build_configurable_properties_schema( $props_schema, $widget_type );
171 174
172 175 return self::filter_nulls( [
173 176 'type' => 'object',
174 177 'properties' => $properties,
@@ -179,9 +182,9 @@
179 182
180 183 /**
181 184 * @param array<string, Prop_Type> $props_schema
182 185 */
183 - private static function build_configurable_properties_schema( array $props_schema ): array {
186 + private static function build_configurable_properties_schema( array $props_schema, string $widget_type ): array {
184 187 $properties = [];
185 188
186 189 foreach ( $props_schema as $key => $prop_type ) {
187 190 if ( ! $prop_type instanceof Prop_Type || ! self::is_prop_key_configurable( $key, $prop_type ) ) {
@@ -187,20 +190,54 @@
187 190 if ( ! $prop_type instanceof Prop_Type || ! self::is_prop_key_configurable( $key, $prop_type ) ) {
188 191 continue;
189 192 }
190 193
191 - $properties[ $key ] = $prop_type->to_json_schema();
194 + $schema = self::to_plain_llm_schema_from_json( $prop_type->to_json_schema() );
195 + $allowed_html_tags = Escaped_Html_Prop_Type::get_allowed_html_tags_for_prop( $widget_type, $key );
196 +
197 + if ( null !== $allowed_html_tags ) {
198 + $schema = self::describe_allowed_html_tags( $schema, $allowed_html_tags );
199 + }
200 +
201 + $properties[ $key ] = $schema;
192 202 }
193 203
194 - return self::apply_llm_schema_filters( $properties );
204 + return $properties;
195 205 }
196 206
197 - private static function apply_llm_schema_filters( array $properties ): array {
198 - foreach ( $properties as $key => $schema ) {
199 - $properties[ $key ] = self::to_plain_llm_schema_from_json( $schema );
207 + /**
208 + * Keeps the machine-readable tag list while spelling out in the description that the string
209 + * itself may carry that markup — a bare `allowed_html_tags` key is non-standard JSON Schema
210 + * and reads as ambiguous next to `type: string`.
211 + */
212 + private static function describe_allowed_html_tags( array $schema, array $allowed_html_tags ): array {
213 + $schema['allowed_html_tags'] = $allowed_html_tags;
214 +
215 + $tag_list = implode( ', ', array_map( fn( $tag ) => "<{$tag}>", $allowed_html_tags ) );
216 + $note = sprintf( self::ALLOWED_HTML_TAGS_NOTE, $tag_list );
217 +
218 + if ( ! isset( $schema['anyOf'] ) || ! is_array( $schema['anyOf'] ) ) {
219 + return self::append_description( $schema, $note );
200 220 }
201 221
202 - return $properties;
222 + // The markup rule belongs on the static string variant only — a dynamic-tag branch
223 + // resolves its own value and never carries inline HTML from the caller.
224 + $schema['anyOf'] = array_map(
225 + fn( $branch ) => is_array( $branch ) && 'string' === ( $branch['type'] ?? null )
226 + ? self::append_description( $branch, $note )
227 + : $branch,
228 + $schema['anyOf']
229 + );
230 +
231 + return $schema;
232 + }
233 +
234 + private static function append_description( array $schema, string $note ): array {
235 + $schema['description'] = isset( $schema['description'] )
236 + ? $schema['description'] . ' ' . $note
237 + : $note;
238 +
239 + return $schema;
203 240 }
204 241
205 242 public static function to_plain_llm_schema( Prop_Type $prop_type ): array {
206 243 $schema = self::to_plain_llm_schema_from_json( $prop_type->to_json_schema() );