fix: anchor Divi name/id patterns at string end, number-advanced stays unknown, doc wording
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -24,7 +24,7 @@ Breakpoints: `desktop`, `tablet`, `phone` (je nach Website auch `tabletWide`, `p
|
|||||||
gültigen Pfade dieses Moduls auf dieser Website (live aus Divi) und die Kurzform-Felder mit ihrem Pfad.
|
gültigen Pfade dieses Moduls auf dieser Website (live aus Divi) und die Kurzform-Felder mit ihrem Pfad.
|
||||||
`path_kinds` nennt die Feldart eines Pfads (`text`, `richtext`, `code`, `url`, `image`, `color`, `enum`,
|
`path_kinds` nennt die Feldart eines Pfads (`text`, `richtext`, `code`, `url`, `image`, `color`, `enum`,
|
||||||
`onoff`, `number`, `list`, `icon`), soweit aus den Divi-Metadaten ableitbar. Bei einem zusammengesetzten
|
`onoff`, `number`, `list`, `icon`), soweit aus den Divi-Metadaten ableitbar. Bei einem zusammengesetzten
|
||||||
Pfad (mehrere benannte Unterfelder unter einem Pfad, z. B. `buttonOne.innerContent` mit `text` und
|
Pfad (ein oder mehrere benannte Unterfelder unter einem Pfad, z. B. `buttonOne.innerContent` mit `text` und
|
||||||
`linkUrl`) ist der Eintrag stattdessen eine Zuordnung Unterfeld → Feldart (`{"text": "text", "linkUrl":
|
`linkUrl`) ist der Eintrag stattdessen eine Zuordnung Unterfeld → Feldart (`{"text": "text", "linkUrl":
|
||||||
"url"}`), soweit für die einzelnen Unterfelder ableitbar; fehlende Pfade oder Unterfelder gelten als
|
"url"}`), soweit für die einzelnen Unterfelder ableitbar; fehlende Pfade oder Unterfelder gelten als
|
||||||
unbekannt, statt eine Feldart zu raten.
|
unbekannt, statt eine Feldart zu raten.
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ use stdClass;
|
|||||||
final class Block extends Container
|
final class Block extends Container
|
||||||
{
|
{
|
||||||
/** A valid block name: "namespace/block-name" (WordPress' own block name convention). */
|
/** A valid block name: "namespace/block-name" (WordPress' own block name convention). */
|
||||||
private const NAME_PATTERN = '/^[a-z][a-z0-9_-]*\/[a-z][a-z0-9_-]*$/';
|
private const NAME_PATTERN = '/^[a-z][a-z0-9_-]*\/[a-z][a-z0-9_-]*$/D';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array<string, mixed> $attrs
|
* @param array<string, mixed> $attrs
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ namespace LIT\MCP\Integrations\Divi\BlockTree;
|
|||||||
*/
|
*/
|
||||||
final class NodeIndex
|
final class NodeIndex
|
||||||
{
|
{
|
||||||
public const ID_PATTERN = '/^[srcmgx]\d+(\.[srcmgx]\d+)*$/';
|
public const ID_PATTERN = '/^[srcmgx]\d+(\.[srcmgx]\d+)*$/D';
|
||||||
|
|
||||||
/** @var array<string, Block> */
|
/** @var array<string, Block> */
|
||||||
private array $byId = [];
|
private array $byId = [];
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ namespace LIT\MCP\Integrations\Divi\BlockTree;
|
|||||||
* delimiters; changed or new blocks get delimiters generated exactly like WordPress'
|
* delimiters; changed or new blocks get delimiters generated exactly like WordPress'
|
||||||
* get_comment_delimited_block_content() / serialize_block_attributes() do, which also
|
* get_comment_delimited_block_content() / serialize_block_attributes() do, which also
|
||||||
* yields the escaping Divi expects inside $variable(…)$ payloads: json_encode()'s own
|
* yields the escaping Divi expects inside $variable(…)$ payloads: json_encode()'s own
|
||||||
* \" (an escaped quote inside a JSON string) is replaced by ", see ESCAPES below.
|
* \" (an escaped quote inside a JSON string) is replaced by \u0022, see ESCAPES below.
|
||||||
*/
|
*/
|
||||||
final class Serializer
|
final class Serializer
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -69,7 +69,10 @@ final class AttrPathIndex
|
|||||||
* type still tells them apart reliably. Only used for composite (subName-bearing)
|
* type still tells them apart reliably. Only used for composite (subName-bearing)
|
||||||
* candidates; a plain path keeps trusting its field component alone (COMPONENT_KINDS),
|
* candidates; a plain path keeps trusting its field component alone (COMPONENT_KINDS),
|
||||||
* so an already more specific kind there (richtext, code, …) is never downgraded to the
|
* so an already more specific kind there (richtext, code, …) is never downgraded to the
|
||||||
* generic "text" dynamicContent commonly names for both.
|
* generic "text" dynamicContent commonly names for both. number-advanced (e.g. border
|
||||||
|
* radius) holds an object of corner values and therefore stays unknown. A path that has
|
||||||
|
* both a plain field and named sub-fields keeps only the sub-field map (the plain field
|
||||||
|
* then counts as unknown).
|
||||||
*/
|
*/
|
||||||
private const DYNAMIC_CONTENT_KINDS = [
|
private const DYNAMIC_CONTENT_KINDS = [
|
||||||
'text' => 'text',
|
'text' => 'text',
|
||||||
@@ -77,7 +80,6 @@ final class AttrPathIndex
|
|||||||
'image' => 'image',
|
'image' => 'image',
|
||||||
'color' => 'color',
|
'color' => 'color',
|
||||||
'number' => 'number',
|
'number' => 'number',
|
||||||
'number-advanced' => 'number',
|
|
||||||
];
|
];
|
||||||
|
|
||||||
private const ATTR_NAME_PATTERN = '/^[A-Za-z0-9]+(\.[A-Za-z0-9]+)+$/';
|
private const ATTR_NAME_PATTERN = '/^[A-Za-z0-9]+(\.[A-Za-z0-9]+)+$/';
|
||||||
|
|||||||
@@ -84,8 +84,9 @@ final class DiviCatalogAbility implements Ability
|
|||||||
'type' => 'object',
|
'type' => 'object',
|
||||||
'description' => 'Bekannter Attributpfad => Feldart (text, richtext, code, url, '
|
'description' => 'Bekannter Attributpfad => Feldart (text, richtext, code, url, '
|
||||||
. 'image, color, enum, onoff, number, list, icon), soweit aus den Divi-Metadaten '
|
. 'image, color, enum, onoff, number, list, icon), soweit aus den Divi-Metadaten '
|
||||||
. 'ableitbar. Bei einem zusammengesetzten Pfad (mehrere benannte Unterfelder unter '
|
. 'ableitbar. Bei einem zusammengesetzten Pfad (ein oder mehrere benannte '
|
||||||
. 'einem Pfad, z. B. buttonOne.innerContent mit "text" und "linkUrl") ist der Wert '
|
. 'Unterfelder unter einem Pfad, z. B. buttonOne.innerContent mit "text" und '
|
||||||
|
. '"linkUrl") ist der Wert '
|
||||||
. 'stattdessen eine Zuordnung Unterfeld => Feldart, soweit für die einzelnen '
|
. 'stattdessen eine Zuordnung Unterfeld => Feldart, soweit für die einzelnen '
|
||||||
. 'Unterfelder ableitbar. Fehlende Pfade oder Unterfelder gelten als unbekannt.',
|
. 'Unterfelder ableitbar. Fehlende Pfade oder Unterfelder gelten als unbekannt.',
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ final class BlockTest extends TestCase
|
|||||||
return [
|
return [
|
||||||
'no namespace' => ['button'],
|
'no namespace' => ['button'],
|
||||||
'trailing markup injection' => ['divi/x --><script>'],
|
'trailing markup injection' => ['divi/x --><script>'],
|
||||||
|
'trailing newline' => ["divi/x\n"],
|
||||||
'uppercase' => ['Divi/Button'],
|
'uppercase' => ['Divi/Button'],
|
||||||
'empty' => [''],
|
'empty' => [''],
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ final class NodeIndexTest extends TestCase
|
|||||||
);
|
);
|
||||||
self::assertSame(1, preg_match(NodeIndex::ID_PATTERN, 's1.g2'));
|
self::assertSame(1, preg_match(NodeIndex::ID_PATTERN, 's1.g2'));
|
||||||
self::assertSame(0, preg_match(NodeIndex::ID_PATTERN, 's1..g2'));
|
self::assertSame(0, preg_match(NodeIndex::ID_PATTERN, 's1..g2'));
|
||||||
|
self::assertSame(0, preg_match(NodeIndex::ID_PATTERN, "s1\n"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testDocumentWithoutPlaceholderIsItsOwnRoot(): void
|
public function testDocumentWithoutPlaceholderIsItsOwnRoot(): void
|
||||||
|
|||||||
Reference in New Issue
Block a user