feat: explain the type collision on contact fields (trial)
A contact-field item whose type is no allowed child now gets a hint that type is the node type, with the attrs path (fieldItem.advanced.type) and the lit-divi-update set alternative, instead of "unbekanntes Modul divi/email". The metadata fixture gains contact-form/contact-field (regenerated from Divi 5.2.1, additions only). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7
This commit is contained in:
@@ -256,7 +256,7 @@ final class Composer
|
|||||||
|
|
||||||
$violation = $this->rules->violation($parent, $type);
|
$violation = $this->rules->violation($parent, $type);
|
||||||
if ($violation !== null) {
|
if ($violation !== null) {
|
||||||
$this->errors[$path . '.type'] = $violation;
|
$this->errors[$path . '.type'] = $this->typeFieldCollision($spec, $parent) ?? $violation;
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -268,6 +268,42 @@ final class Composer
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trial feedback: an item whose only possible type has a short-form field named "type" (the
|
||||||
|
* contact field's field type) – a `type` that is no allowed child was almost certainly meant as
|
||||||
|
* that field. Explains the collision instead of "unbekanntes Modul divi/<value>".
|
||||||
|
*
|
||||||
|
* @param array<array-key, mixed> $spec
|
||||||
|
*/
|
||||||
|
private function typeFieldCollision(array $spec, ?Block $parent): ?string
|
||||||
|
{
|
||||||
|
$children = $parent === null ? [] : $this->catalog->childrenOf($parent->name());
|
||||||
|
if (count($children) !== 1 || ! is_string($spec['type'] ?? null)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$child = ModuleCatalog::shortName($children[0]);
|
||||||
|
$field = ShortformMap::fields($child)['type'] ?? null;
|
||||||
|
if ($field === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// phpcs:ignore WordPress.WP.AlternativeFunctions.json_encode_json_encode -- pure PHP (spec §4.4).
|
||||||
|
$value = json_encode(
|
||||||
|
$spec['type'],
|
||||||
|
JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_INVALID_UTF8_SUBSTITUTE
|
||||||
|
);
|
||||||
|
|
||||||
|
return sprintf(
|
||||||
|
'`type` ist hier der Knotentyp (%1$s, darf fehlen); das Feldtyp-Feld über attrs setzen: '
|
||||||
|
. '{"attrs": {"%2$s": {"desktop": %3$s}}} – oder type weglassen und danach mit lit-divi-update '
|
||||||
|
. '{"set": {"type": %3$s}} setzen.',
|
||||||
|
$child,
|
||||||
|
(string) $field['path'],
|
||||||
|
(string) $value
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/** @param array<array-key, mixed> $spec */
|
/** @param array<array-key, mixed> $spec */
|
||||||
private function typeOf(array $spec, ?Block $parent): ?string
|
private function typeOf(array $spec, ?Block $parent): ?string
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3530,6 +3530,821 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "divi/contact-form",
|
||||||
|
"title": "Contact Form",
|
||||||
|
"category": "module",
|
||||||
|
"childrenName": [
|
||||||
|
"divi/contact-field"
|
||||||
|
],
|
||||||
|
"childModuleName": "divi/contact-field",
|
||||||
|
"attributes": {
|
||||||
|
"module": {
|
||||||
|
"settings": {
|
||||||
|
"meta": {
|
||||||
|
"meta": []
|
||||||
|
},
|
||||||
|
"advanced": {
|
||||||
|
"elements": {
|
||||||
|
"groupType": "group-item",
|
||||||
|
"item": {
|
||||||
|
"groupSlug": "contentElements",
|
||||||
|
"priority": 5,
|
||||||
|
"render": true,
|
||||||
|
"component": {
|
||||||
|
"type": "group",
|
||||||
|
"name": "divi/elements",
|
||||||
|
"props": {
|
||||||
|
"grouped": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"html": [],
|
||||||
|
"link": [],
|
||||||
|
"loop": [],
|
||||||
|
"text": {
|
||||||
|
"component": {
|
||||||
|
"props": {
|
||||||
|
"fields": {
|
||||||
|
"color": {
|
||||||
|
"render": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"successMessage": {
|
||||||
|
"groupType": "group-item",
|
||||||
|
"item": {
|
||||||
|
"groupSlug": "contentText",
|
||||||
|
"priority": 10,
|
||||||
|
"render": true,
|
||||||
|
"attrName": "module.advanced.successMessage",
|
||||||
|
"label": "Success Message",
|
||||||
|
"description": "Type the message you want to display after successful form submission. Leave blank for default",
|
||||||
|
"category": "configuration",
|
||||||
|
"features": {
|
||||||
|
"dynamicContent": {
|
||||||
|
"type": "text"
|
||||||
|
},
|
||||||
|
"sticky": false,
|
||||||
|
"responsive": false,
|
||||||
|
"hover": false,
|
||||||
|
"preset": "content"
|
||||||
|
},
|
||||||
|
"component": {
|
||||||
|
"name": "divi/text",
|
||||||
|
"type": "field"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"decoration": {
|
||||||
|
"layout": [],
|
||||||
|
"animation": [],
|
||||||
|
"attributes": [],
|
||||||
|
"background": [],
|
||||||
|
"border": {
|
||||||
|
"component": {
|
||||||
|
"props": {
|
||||||
|
"fieldLabel": "Inputs"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"boxShadow": [],
|
||||||
|
"conditions": [],
|
||||||
|
"disabledOn": [],
|
||||||
|
"filters": [],
|
||||||
|
"interactions": [],
|
||||||
|
"overflow": [],
|
||||||
|
"order": [],
|
||||||
|
"position": [],
|
||||||
|
"scroll": [],
|
||||||
|
"sizing": [],
|
||||||
|
"spacing": [],
|
||||||
|
"sticky": [],
|
||||||
|
"transform": [],
|
||||||
|
"transition": [],
|
||||||
|
"zIndex": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"settings": {
|
||||||
|
"innerContent": {
|
||||||
|
"groupType": "group-item",
|
||||||
|
"item": {
|
||||||
|
"groupSlug": "contentText",
|
||||||
|
"priority": 5,
|
||||||
|
"render": true,
|
||||||
|
"attrName": "title.innerContent",
|
||||||
|
"label": "Title",
|
||||||
|
"description": "Define a title for your contact form.",
|
||||||
|
"category": "basic_option",
|
||||||
|
"features": {
|
||||||
|
"dynamicContent": {
|
||||||
|
"type": "text"
|
||||||
|
},
|
||||||
|
"sticky": false,
|
||||||
|
"preset": "content"
|
||||||
|
},
|
||||||
|
"component": {
|
||||||
|
"name": "divi/text",
|
||||||
|
"type": "field"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"decoration": {
|
||||||
|
"font": {
|
||||||
|
"priority": 10,
|
||||||
|
"component": {
|
||||||
|
"props": {
|
||||||
|
"groupLabel": "Title Text",
|
||||||
|
"fieldLabel": "Title",
|
||||||
|
"dynamicSubgroupHost": true,
|
||||||
|
"dynamicSubgroupHostLayoutStyle": "moduleLayout",
|
||||||
|
"fields": {
|
||||||
|
"headingLevel": {
|
||||||
|
"render": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"captcha": {
|
||||||
|
"settings": {
|
||||||
|
"decoration": {
|
||||||
|
"font": {
|
||||||
|
"priority": 15,
|
||||||
|
"component": {
|
||||||
|
"props": {
|
||||||
|
"groupLabel": "Captcha Text",
|
||||||
|
"fieldLabel": "Captcha",
|
||||||
|
"dynamicSubgroupHost": true,
|
||||||
|
"fields": {
|
||||||
|
"textAlign": {
|
||||||
|
"render": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"field": {
|
||||||
|
"settings": {
|
||||||
|
"decoration": {
|
||||||
|
"background": [],
|
||||||
|
"font": [],
|
||||||
|
"spacing": []
|
||||||
|
},
|
||||||
|
"advanced": {
|
||||||
|
"focus": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"button": {
|
||||||
|
"settings": {
|
||||||
|
"innerContent": {
|
||||||
|
"groupType": "group-item",
|
||||||
|
"item": {
|
||||||
|
"groupSlug": "contentText",
|
||||||
|
"priority": 20,
|
||||||
|
"render": true,
|
||||||
|
"attrName": "button.innerContent",
|
||||||
|
"subName": "text",
|
||||||
|
"label": "Submit Button",
|
||||||
|
"description": "Define the text of the form submit button.",
|
||||||
|
"category": "basic_option",
|
||||||
|
"features": {
|
||||||
|
"dynamicContent": {
|
||||||
|
"type": "text"
|
||||||
|
},
|
||||||
|
"sticky": false,
|
||||||
|
"preset": "content"
|
||||||
|
},
|
||||||
|
"component": {
|
||||||
|
"name": "divi/text",
|
||||||
|
"type": "field"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"decoration": {
|
||||||
|
"background": [],
|
||||||
|
"border": [],
|
||||||
|
"boxShadow": [],
|
||||||
|
"button": {
|
||||||
|
"component": {
|
||||||
|
"props": {
|
||||||
|
"dynamicSubgroupHost": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"font": [],
|
||||||
|
"sizing": [],
|
||||||
|
"spacing": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"settings": {
|
||||||
|
"advanced": {
|
||||||
|
"receiver": {
|
||||||
|
"groupType": "group-item",
|
||||||
|
"item": {
|
||||||
|
"groupSlug": "contentEmail",
|
||||||
|
"priority": 5,
|
||||||
|
"render": true,
|
||||||
|
"attrName": "email.advanced.receiver",
|
||||||
|
"label": "Email Address",
|
||||||
|
"description": "Input the email address where messages should be sent.<br /><br /> Note: email delivery and spam prevention are complex processes. We recommend using a delivery service such as <a href=\"http://mandrill.com/\">Mandrill</a>, <a href=\"https://sendgrid.com/\">SendGrid</a>, or other similar service to ensure the deliverability of messages that are submitted through this form",
|
||||||
|
"category": "basic_option",
|
||||||
|
"features": {
|
||||||
|
"responsive": false,
|
||||||
|
"hover": false,
|
||||||
|
"sticky": false,
|
||||||
|
"preset": "content",
|
||||||
|
"dynamicContent": {
|
||||||
|
"type": "text"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"component": {
|
||||||
|
"name": "divi/text",
|
||||||
|
"type": "field"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"innerContent": {
|
||||||
|
"groupType": "group-item",
|
||||||
|
"item": {
|
||||||
|
"groupSlug": "contentEmail",
|
||||||
|
"priority": 10,
|
||||||
|
"render": true,
|
||||||
|
"attrName": "email.innerContent",
|
||||||
|
"label": "Message Pattern",
|
||||||
|
"description": "Here you can define the custom pattern for the email Message. Fields should be included in following format - <strong>%%field_id%%</strong>. For example if you want to include the field with id = <strong>phone</strong> and field with id = <strong>message</strong>, then you can use the following pattern: <strong>My message is %%message%% and phone number is %%phone%%</strong>. Leave blank for default.",
|
||||||
|
"category": "configuration",
|
||||||
|
"features": {
|
||||||
|
"responsive": false,
|
||||||
|
"hover": false,
|
||||||
|
"sticky": false,
|
||||||
|
"preset": "content",
|
||||||
|
"dynamicContent": {
|
||||||
|
"type": "text"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"component": {
|
||||||
|
"name": "divi/textarea",
|
||||||
|
"type": "field",
|
||||||
|
"props": {
|
||||||
|
"processing": "custom_message"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"redirect": {
|
||||||
|
"settings": {
|
||||||
|
"advanced": {
|
||||||
|
"useRedirect": {
|
||||||
|
"groupType": "group-item",
|
||||||
|
"item": {
|
||||||
|
"groupSlug": "contentRedirect",
|
||||||
|
"priority": 5,
|
||||||
|
"render": true,
|
||||||
|
"attrName": "redirect.advanced.useRedirect",
|
||||||
|
"label": "Enable Redirect URL",
|
||||||
|
"description": "Redirect users after successful form submission.",
|
||||||
|
"category": "configuration",
|
||||||
|
"features": {
|
||||||
|
"responsive": false,
|
||||||
|
"hover": false,
|
||||||
|
"sticky": false,
|
||||||
|
"preset": "content"
|
||||||
|
},
|
||||||
|
"component": {
|
||||||
|
"name": "divi/toggle",
|
||||||
|
"type": "field"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"innerContent": {
|
||||||
|
"groupType": "group-item",
|
||||||
|
"item": {
|
||||||
|
"groupSlug": "contentRedirect",
|
||||||
|
"priority": 10,
|
||||||
|
"render": true,
|
||||||
|
"attrName": "redirect.innerContent",
|
||||||
|
"label": "Redirect URL",
|
||||||
|
"description": "Type the Redirect URL",
|
||||||
|
"category": "configuration",
|
||||||
|
"features": {
|
||||||
|
"responsive": false,
|
||||||
|
"hover": false,
|
||||||
|
"sticky": false,
|
||||||
|
"preset": "content",
|
||||||
|
"dynamicContent": {
|
||||||
|
"type": "url"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"component": {
|
||||||
|
"name": "divi/text",
|
||||||
|
"type": "field"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "divi/contact-field",
|
||||||
|
"title": "Field",
|
||||||
|
"category": "child-module",
|
||||||
|
"childrenName": [],
|
||||||
|
"attributes": {
|
||||||
|
"module": {
|
||||||
|
"settings": {
|
||||||
|
"meta": {
|
||||||
|
"meta": []
|
||||||
|
},
|
||||||
|
"advanced": {
|
||||||
|
"elements": [],
|
||||||
|
"html": [],
|
||||||
|
"link": [],
|
||||||
|
"loop": [],
|
||||||
|
"text": {
|
||||||
|
"component": {
|
||||||
|
"props": {
|
||||||
|
"fields": {
|
||||||
|
"orientation": {
|
||||||
|
"component": {
|
||||||
|
"props": {
|
||||||
|
"allowClickToUnset": true,
|
||||||
|
"renderEmptyStringAsDefaultValue": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"color": {
|
||||||
|
"render": false
|
||||||
|
},
|
||||||
|
"textShadowGroup": {
|
||||||
|
"render": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"decoration": {
|
||||||
|
"layout": [],
|
||||||
|
"background": [],
|
||||||
|
"border": {
|
||||||
|
"component": {
|
||||||
|
"props": {
|
||||||
|
"fieldLabel": "Input"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"animation": [],
|
||||||
|
"attributes": [],
|
||||||
|
"boxShadow": [],
|
||||||
|
"conditions": [],
|
||||||
|
"disabledOn": [],
|
||||||
|
"filters": [],
|
||||||
|
"interactions": [],
|
||||||
|
"overflow": [],
|
||||||
|
"order": [],
|
||||||
|
"position": [],
|
||||||
|
"scroll": [],
|
||||||
|
"sizing": [],
|
||||||
|
"spacing": [],
|
||||||
|
"sticky": [],
|
||||||
|
"transform": [],
|
||||||
|
"transition": [],
|
||||||
|
"zIndex": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"field": {
|
||||||
|
"settings": {
|
||||||
|
"decoration": {
|
||||||
|
"background": [],
|
||||||
|
"font": []
|
||||||
|
},
|
||||||
|
"advanced": {
|
||||||
|
"focus": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fieldTitle": {
|
||||||
|
"settings": {
|
||||||
|
"decoration": {
|
||||||
|
"font": {
|
||||||
|
"priority": 10,
|
||||||
|
"component": {
|
||||||
|
"props": {
|
||||||
|
"groupLabel": "Title Text",
|
||||||
|
"fieldLabel": "Title"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fieldItem": {
|
||||||
|
"settings": {
|
||||||
|
"advanced": {
|
||||||
|
"id": {
|
||||||
|
"groupType": "group-item",
|
||||||
|
"item": {
|
||||||
|
"groupSlug": "contentText",
|
||||||
|
"priority": 5,
|
||||||
|
"render": true,
|
||||||
|
"attrName": "fieldItem.advanced.id",
|
||||||
|
"label": "Field ID",
|
||||||
|
"description": "Define the unique ID of this field. You should use only English characters without special characters and spaces.",
|
||||||
|
"category": "basic_option",
|
||||||
|
"features": {
|
||||||
|
"sticky": false,
|
||||||
|
"responsive": false,
|
||||||
|
"hover": false,
|
||||||
|
"preset": "content",
|
||||||
|
"dynamicContent": {
|
||||||
|
"type": "text"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"component": {
|
||||||
|
"name": "divi/text",
|
||||||
|
"type": "field"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"groupType": "group-item",
|
||||||
|
"item": {
|
||||||
|
"groupSlug": "contentFieldOptions",
|
||||||
|
"priority": 5,
|
||||||
|
"render": true,
|
||||||
|
"attrName": "fieldItem.advanced.type",
|
||||||
|
"label": "Type",
|
||||||
|
"description": "Choose the type of field",
|
||||||
|
"category": "basic_option",
|
||||||
|
"features": {
|
||||||
|
"sticky": false,
|
||||||
|
"responsive": false,
|
||||||
|
"hover": false,
|
||||||
|
"preset": "content"
|
||||||
|
},
|
||||||
|
"component": {
|
||||||
|
"name": "divi/select",
|
||||||
|
"type": "field",
|
||||||
|
"props": {
|
||||||
|
"options": {
|
||||||
|
"input": {
|
||||||
|
"label": "Input Field"
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"label": "Email Field"
|
||||||
|
},
|
||||||
|
"text": {
|
||||||
|
"label": "Textarea"
|
||||||
|
},
|
||||||
|
"checkbox": {
|
||||||
|
"label": "Checkboxes"
|
||||||
|
},
|
||||||
|
"radio": {
|
||||||
|
"label": "Radio Buttons"
|
||||||
|
},
|
||||||
|
"select": {
|
||||||
|
"label": "Select Dropdown"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"minLength": {
|
||||||
|
"groupType": "group-item",
|
||||||
|
"item": {
|
||||||
|
"groupSlug": "contentFieldOptions",
|
||||||
|
"priority": 5,
|
||||||
|
"render": true,
|
||||||
|
"attrName": "fieldItem.advanced.minLength",
|
||||||
|
"label": "Minimum Length",
|
||||||
|
"description": "Leave at 0 to remove restriction",
|
||||||
|
"category": "basic_option",
|
||||||
|
"features": {
|
||||||
|
"sticky": false,
|
||||||
|
"responsive": false,
|
||||||
|
"hover": false,
|
||||||
|
"preset": "content"
|
||||||
|
},
|
||||||
|
"component": {
|
||||||
|
"name": "divi/range",
|
||||||
|
"type": "field",
|
||||||
|
"props": {
|
||||||
|
"allowedUnits": [],
|
||||||
|
"defaultUnit": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"maxLength": {
|
||||||
|
"groupType": "group-item",
|
||||||
|
"item": {
|
||||||
|
"groupSlug": "contentFieldOptions",
|
||||||
|
"priority": 5,
|
||||||
|
"render": true,
|
||||||
|
"attrName": "fieldItem.advanced.maxLength",
|
||||||
|
"label": "Maximum Length",
|
||||||
|
"description": "Leave at 0 to remove restriction",
|
||||||
|
"category": "basic_option",
|
||||||
|
"features": {
|
||||||
|
"sticky": false,
|
||||||
|
"responsive": false,
|
||||||
|
"hover": false,
|
||||||
|
"preset": "content"
|
||||||
|
},
|
||||||
|
"component": {
|
||||||
|
"name": "divi/range",
|
||||||
|
"type": "field",
|
||||||
|
"props": {
|
||||||
|
"allowedUnits": [],
|
||||||
|
"defaultUnit": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"allowedSymbols": {
|
||||||
|
"groupType": "group-item",
|
||||||
|
"item": {
|
||||||
|
"groupSlug": "contentFieldOptions",
|
||||||
|
"priority": 5,
|
||||||
|
"render": true,
|
||||||
|
"attrName": "fieldItem.advanced.allowedSymbols",
|
||||||
|
"label": "Allowed Symbols",
|
||||||
|
"category": "basic_option",
|
||||||
|
"features": {
|
||||||
|
"sticky": false,
|
||||||
|
"responsive": false,
|
||||||
|
"hover": false,
|
||||||
|
"preset": "content"
|
||||||
|
},
|
||||||
|
"component": {
|
||||||
|
"name": "divi/select",
|
||||||
|
"type": "field",
|
||||||
|
"props": {
|
||||||
|
"options": {
|
||||||
|
"all": {
|
||||||
|
"label": "All"
|
||||||
|
},
|
||||||
|
"letters": {
|
||||||
|
"label": "Letters Only (A-Z)"
|
||||||
|
},
|
||||||
|
"numbers": {
|
||||||
|
"label": "Numbers Only (0-9)"
|
||||||
|
},
|
||||||
|
"alphanumeric": {
|
||||||
|
"label": "Alphanumeric Only (A-Z, 0-9)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"checkboxOptions": {
|
||||||
|
"groupType": "group-item",
|
||||||
|
"item": {
|
||||||
|
"groupSlug": "contentFieldOptions",
|
||||||
|
"priority": 5,
|
||||||
|
"render": true,
|
||||||
|
"attrName": "fieldItem.advanced.checkboxOptions",
|
||||||
|
"label": "Options",
|
||||||
|
"category": "basic_option",
|
||||||
|
"features": {
|
||||||
|
"sticky": false,
|
||||||
|
"responsive": false,
|
||||||
|
"hover": false,
|
||||||
|
"preset": "content"
|
||||||
|
},
|
||||||
|
"component": {
|
||||||
|
"name": "divi/sortable-list",
|
||||||
|
"type": "field",
|
||||||
|
"props": {
|
||||||
|
"isCheckbox": true,
|
||||||
|
"addFirstOnMount": true,
|
||||||
|
"actions": {
|
||||||
|
"right": [
|
||||||
|
"move",
|
||||||
|
"link",
|
||||||
|
"copy",
|
||||||
|
"delete"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"radioOptions": {
|
||||||
|
"groupType": "group-item",
|
||||||
|
"item": {
|
||||||
|
"groupSlug": "contentFieldOptions",
|
||||||
|
"priority": 5,
|
||||||
|
"render": true,
|
||||||
|
"attrName": "fieldItem.advanced.radioOptions",
|
||||||
|
"label": "Options",
|
||||||
|
"category": "basic_option",
|
||||||
|
"features": {
|
||||||
|
"sticky": false,
|
||||||
|
"responsive": false,
|
||||||
|
"hover": false,
|
||||||
|
"preset": "content"
|
||||||
|
},
|
||||||
|
"component": {
|
||||||
|
"name": "divi/sortable-list",
|
||||||
|
"type": "field",
|
||||||
|
"props": {
|
||||||
|
"isRadio": true,
|
||||||
|
"addFirstOnMount": true,
|
||||||
|
"actions": {
|
||||||
|
"right": [
|
||||||
|
"move",
|
||||||
|
"link",
|
||||||
|
"copy",
|
||||||
|
"delete"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"selectOptions": {
|
||||||
|
"groupType": "group-item",
|
||||||
|
"item": {
|
||||||
|
"groupSlug": "contentFieldOptions",
|
||||||
|
"priority": 5,
|
||||||
|
"render": true,
|
||||||
|
"attrName": "fieldItem.advanced.selectOptions",
|
||||||
|
"label": "Options",
|
||||||
|
"category": "basic_option",
|
||||||
|
"features": {
|
||||||
|
"sticky": false,
|
||||||
|
"responsive": false,
|
||||||
|
"hover": false,
|
||||||
|
"preset": "content"
|
||||||
|
},
|
||||||
|
"component": {
|
||||||
|
"name": "divi/sortable-list",
|
||||||
|
"type": "field",
|
||||||
|
"props": {
|
||||||
|
"addFirstOnMount": true,
|
||||||
|
"actions": {
|
||||||
|
"right": [
|
||||||
|
"move",
|
||||||
|
"copy",
|
||||||
|
"delete"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": {
|
||||||
|
"groupType": "group-item",
|
||||||
|
"item": {
|
||||||
|
"groupSlug": "contentFieldOptions",
|
||||||
|
"priority": 5,
|
||||||
|
"render": true,
|
||||||
|
"attrName": "fieldItem.advanced.required",
|
||||||
|
"label": "Required Field",
|
||||||
|
"description": "Define whether the field should be required or optional",
|
||||||
|
"category": "configuration",
|
||||||
|
"features": {
|
||||||
|
"sticky": false,
|
||||||
|
"responsive": false,
|
||||||
|
"hover": false,
|
||||||
|
"preset": "content"
|
||||||
|
},
|
||||||
|
"component": {
|
||||||
|
"name": "divi/toggle",
|
||||||
|
"type": "field"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"innerContent": {
|
||||||
|
"groupType": "group-item",
|
||||||
|
"item": {
|
||||||
|
"groupSlug": "contentText",
|
||||||
|
"priority": 10,
|
||||||
|
"render": true,
|
||||||
|
"attrName": "fieldItem.innerContent",
|
||||||
|
"label": "Title",
|
||||||
|
"description": "Here you can define the content that will be placed within the current tab.",
|
||||||
|
"category": "basic_option",
|
||||||
|
"features": {
|
||||||
|
"sticky": false,
|
||||||
|
"preset": "content",
|
||||||
|
"dynamicContent": {
|
||||||
|
"type": "text"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"component": {
|
||||||
|
"name": "divi/text",
|
||||||
|
"type": "field"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"conditionalLogic": {
|
||||||
|
"settings": {
|
||||||
|
"innerContent": {
|
||||||
|
"groupType": "group-item",
|
||||||
|
"item": {
|
||||||
|
"groupSlug": "contentConditionalLogic",
|
||||||
|
"priority": 10,
|
||||||
|
"render": true,
|
||||||
|
"attrName": "conditionalLogic.innerContent",
|
||||||
|
"label": "Rules",
|
||||||
|
"category": "layout",
|
||||||
|
"features": {
|
||||||
|
"responsive": false,
|
||||||
|
"hover": false,
|
||||||
|
"sticky": false,
|
||||||
|
"preset": "content"
|
||||||
|
},
|
||||||
|
"component": {
|
||||||
|
"name": "divi/conditions",
|
||||||
|
"type": "field"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"advanced": {
|
||||||
|
"enable": {
|
||||||
|
"groupType": "group-item",
|
||||||
|
"item": {
|
||||||
|
"groupSlug": "contentConditionalLogic",
|
||||||
|
"priority": 5,
|
||||||
|
"render": true,
|
||||||
|
"attrName": "conditionalLogic.advanced.enable",
|
||||||
|
"label": "Enable",
|
||||||
|
"description": "Enabling conditional logic makes this field only visible when any or all of the rules below are fulfilled<br><strong>Note:</strong> Only fields with an unique and non-empty field ID can be used",
|
||||||
|
"category": "layout",
|
||||||
|
"features": {
|
||||||
|
"responsive": false,
|
||||||
|
"hover": false,
|
||||||
|
"sticky": false,
|
||||||
|
"preset": "content"
|
||||||
|
},
|
||||||
|
"component": {
|
||||||
|
"name": "divi/toggle",
|
||||||
|
"type": "field"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"relation": {
|
||||||
|
"groupType": "group-item",
|
||||||
|
"item": {
|
||||||
|
"groupSlug": "contentConditionalLogic",
|
||||||
|
"priority": 5,
|
||||||
|
"render": true,
|
||||||
|
"attrName": "conditionalLogic.advanced.relation",
|
||||||
|
"label": "Relation",
|
||||||
|
"description": "Choose whether any or all of the rules should be fulfilled",
|
||||||
|
"category": "layout",
|
||||||
|
"features": {
|
||||||
|
"responsive": false,
|
||||||
|
"hover": false,
|
||||||
|
"sticky": false,
|
||||||
|
"preset": "content"
|
||||||
|
},
|
||||||
|
"component": {
|
||||||
|
"name": "divi/toggle",
|
||||||
|
"type": "field",
|
||||||
|
"props": {
|
||||||
|
"options": {
|
||||||
|
"off": "Any",
|
||||||
|
"on": "All"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"defaults": {
|
"defaults": {
|
||||||
@@ -3972,6 +4787,106 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"divi/contact-form": {
|
||||||
|
"module": {
|
||||||
|
"meta": {
|
||||||
|
"adminLabel": {
|
||||||
|
"desktop": {
|
||||||
|
"value": "Contact Form"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"advanced": {
|
||||||
|
"spamProtection": {
|
||||||
|
"desktop": {
|
||||||
|
"value": {
|
||||||
|
"enabled": "off",
|
||||||
|
"useBasicCaptcha": "on"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"decoration": {
|
||||||
|
"font": {
|
||||||
|
"font": {
|
||||||
|
"desktop": {
|
||||||
|
"value": {
|
||||||
|
"headingLevel": "h1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"button": {
|
||||||
|
"innerContent": {
|
||||||
|
"desktop": {
|
||||||
|
"value": {
|
||||||
|
"text": "Submit"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"decoration": {
|
||||||
|
"button": {
|
||||||
|
"desktop": {
|
||||||
|
"value": {
|
||||||
|
"icon": {
|
||||||
|
"enable": "on"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"redirect": {
|
||||||
|
"advanced": {
|
||||||
|
"useRedirect": {
|
||||||
|
"desktop": {
|
||||||
|
"value": "off"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"divi/contact-field": {
|
||||||
|
"module": {
|
||||||
|
"decoration": {
|
||||||
|
"sizing": {
|
||||||
|
"desktop": {
|
||||||
|
"value": {
|
||||||
|
"flexType": "24_24"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fieldItem": {
|
||||||
|
"advanced": {
|
||||||
|
"id": {
|
||||||
|
"desktop": {
|
||||||
|
"value": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"desktop": {
|
||||||
|
"value": "input"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": {
|
||||||
|
"desktop": {
|
||||||
|
"value": "on"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"innerContent": {
|
||||||
|
"desktop": {
|
||||||
|
"value": "New Field"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ if (! class_exists(ModuleRegistration::class)) {
|
|||||||
|
|
||||||
$wanted = [
|
$wanted = [
|
||||||
'section', 'row', 'column', 'text', 'heading', 'button', 'image', 'blurb', 'code', 'accordion',
|
'section', 'row', 'column', 'text', 'heading', 'button', 'image', 'blurb', 'code', 'accordion',
|
||||||
'accordion-item', 'fullwidth-header', 'group',
|
'accordion-item', 'fullwidth-header', 'group', 'contact-form', 'contact-field',
|
||||||
];
|
];
|
||||||
$all = ModuleRegistration::get_all_core_modules_metadata();
|
$all = ModuleRegistration::get_all_core_modules_metadata();
|
||||||
$metadata = [];
|
$metadata = [];
|
||||||
|
|||||||
@@ -530,4 +530,26 @@ final class ComposerTest extends TestCase
|
|||||||
|
|
||||||
self::assertStringContainsString('2 Spalten, aber 3 Modul-Listen', $result['errors']['nodes[0].rows[0].modules']);
|
self::assertStringContainsString('2 Spalten, aber 3 Modul-Listen', $result['errors']['nodes[0].rows[0].modules']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trial feedback: `type` on a contact field is the node type, not the field type. A value that
|
||||||
|
* is no allowed child gets a dedicated hint instead of "unbekanntes Modul divi/email".
|
||||||
|
*/
|
||||||
|
public function testTypeOnAnItemWithATypeFieldExplainsTheCollision(): void
|
||||||
|
{
|
||||||
|
$result = ComposeFixture::composer()->compose([['type' => 'section', 'modules' => [
|
||||||
|
['type' => 'contact-form', 'items' => [
|
||||||
|
['title' => 'Name'],
|
||||||
|
['type' => 'email', 'title' => 'E-Mail'],
|
||||||
|
['type' => 'contact-field', 'title' => 'Nachricht'],
|
||||||
|
]],
|
||||||
|
]]], null, 'nodes');
|
||||||
|
|
||||||
|
$message = $result['errors']['nodes[0].modules[0].modules[0][0].items[1].type'] ?? '';
|
||||||
|
self::assertStringContainsString('`type` ist hier der Knotentyp', $message);
|
||||||
|
self::assertStringContainsString('fieldItem.advanced.type', $message);
|
||||||
|
self::assertStringContainsString('"email"', $message);
|
||||||
|
self::assertStringNotContainsString('unbekanntes Modul', $message);
|
||||||
|
self::assertCount(1, $result['errors'], 'the explicit contact-field type is fine');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user