feat: DynamicContentRules/VariableRef mit LoopScope – loop_* nur in passender Schleife (X2, X5)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5.5
parent
3d12043b4f
commit
f8912c255d
@@ -15,7 +15,8 @@ defined('ABSPATH') || exit;
|
||||
*
|
||||
* Allowed names: a non-color global variable or a theme font (no settings, DESIGN_SETTINGS,
|
||||
* S27); custom_meta_<key> with META_KEY (no leading "_", ruling S12; settings from the map entry
|
||||
* of that exact name, else META_SETTINGS); or a key of the dynamic content map.
|
||||
* of that exact name, else META_SETTINGS); a loop_* key of the map only inside a Divi loop of its
|
||||
* kind (constructor argument $loop, rulings X2/X5 – see loopFieldsFor()); or another key of the map.
|
||||
*
|
||||
* Dynamic content map (ruling S22), constructor argument $map:
|
||||
* array<string, array<string, string>> option name => [setting key => field type]
|
||||
@@ -27,7 +28,7 @@ defined('ABSPATH') || exit;
|
||||
* Default (null): DEFAULT_DYNAMIC_CONTENT. Task 5 builds the map from Divi's live registry
|
||||
* DynamicContentOptions::get_options($post_id, 'edit') – option name => its "fields" (key =>
|
||||
* field "type"). Always, whatever the map says: "enable_html" is rejected (VariableRef), loop_*
|
||||
* names only when the map names them, custom_meta_<key> names and the values of settings whose
|
||||
* names only in a loop of their kind, custom_meta_<key> names and the values of settings whose
|
||||
* key ends in "meta_key" (meta_key, select_meta_key, loop_meta_key …) obey META_KEY after Divi's
|
||||
* own prefix stripping (rulings S29, S30), and no string – before or after cleaning (ruling S28)
|
||||
* – may contain a reference or ")$". A map of another shape fails in the constructor with
|
||||
@@ -86,13 +87,17 @@ final class DynamicContentRules
|
||||
/** @var array<string, array<string, string>> */
|
||||
private array $map;
|
||||
|
||||
private LoopScope $loop;
|
||||
|
||||
/**
|
||||
* @param array<array-key, mixed>|null $map See the class docblock.
|
||||
* @param array<array-key, mixed>|null $map See the class docblock.
|
||||
* @param LoopScope|null $loop The Divi loop the content sits in; null = none (no loop_* names).
|
||||
* @throws InvalidArgumentException When the map does not have that shape.
|
||||
*/
|
||||
public function __construct(private DesignSystem $design, ?array $map = null)
|
||||
public function __construct(private DesignSystem $design, ?array $map = null, ?LoopScope $loop = null)
|
||||
{
|
||||
$this->map = $map === null ? self::DEFAULT_DYNAMIC_CONTENT : self::checkMap($map);
|
||||
$this->loop = $loop ?? LoopScope::none();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -110,15 +115,12 @@ final class DynamicContentRules
|
||||
return $this->map[$name] ?? self::META_SETTINGS;
|
||||
}
|
||||
|
||||
if (isset($this->map[$name])) {
|
||||
return $this->map[$name];
|
||||
if (str_starts_with($name, 'loop_')) {
|
||||
return $this->loopFieldsFor($name);
|
||||
}
|
||||
|
||||
if (str_starts_with($name, 'loop_')) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'Schleifen-Inhalt "%s" ist hier nicht verfügbar (nur innerhalb von Divi-Schleifen).',
|
||||
$name
|
||||
));
|
||||
if (isset($this->map[$name])) {
|
||||
return $this->map[$name];
|
||||
}
|
||||
|
||||
if (in_array($name, $this->design->contentVariableIds(), true)) {
|
||||
@@ -128,6 +130,40 @@ final class DynamicContentRules
|
||||
throw VariableRef::unknownName($name, 'content');
|
||||
}
|
||||
|
||||
/**
|
||||
* A loop_* option (rulings X2/X5): only inside a Divi loop, only of the loop's kind (LoopScope::fits(),
|
||||
* by the option name – Divi reads the meta of the loop object's ID whatever the object is, so a post
|
||||
* meta option in a term loop would print the post with the term's ID: a security boundary, always an
|
||||
* error), and only when the map names it. Its settings then follow the usual rules (meta keys S29/S30).
|
||||
*
|
||||
* @return array<string, string>
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
private function loopFieldsFor(string $name): array
|
||||
{
|
||||
if ($this->loop->queryType() === null) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'Schleifen-Inhalt "%s" braucht eine Divi-Schleife in diesem Modul oder einem übergeordneten '
|
||||
. 'Element (Abschnitt, Zeile, Spalte, Gruppe).',
|
||||
$name
|
||||
));
|
||||
}
|
||||
|
||||
if (! $this->loop->fits($name)) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'Schleifen-Inhalt "%s" passt nicht zur Schleife dieses Elements (Typ: %s).',
|
||||
$name,
|
||||
$this->loop->label()
|
||||
));
|
||||
}
|
||||
|
||||
if (! isset($this->map[$name])) {
|
||||
throw VariableRef::unknownName($name, 'content');
|
||||
}
|
||||
|
||||
return $this->map[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans one content setting by its field type (rulings S21/S22). The steps, in this order:
|
||||
* 1. control characters off the RAW value (S32/S32a);
|
||||
|
||||
@@ -27,7 +27,8 @@ defined('ABSPATH') || exit;
|
||||
* - type "content": DynamicContentRules – the dynamic content map (ruling S22), custom_meta_<key>
|
||||
* (S12/S29/S30), non-color global variables and theme fonts (S27); it also cleans each content
|
||||
* setting. "enable_html" is always rejected here. Internal links post_link_url_<type> ({{link:…}},
|
||||
* E13a) only in URL fields.
|
||||
* E13a) only in URL fields. loop_* options only inside a Divi loop of their kind (constructor
|
||||
* argument $loop, rulings X2/X5); without it no loop_* name is allowed.
|
||||
* A dynamic content map of the wrong shape fails in the constructor with InvalidArgumentException.
|
||||
*/
|
||||
final class VariableRef
|
||||
@@ -47,11 +48,12 @@ final class VariableRef
|
||||
|
||||
/**
|
||||
* @param array<array-key, mixed>|null $dynamicContent See DynamicContentRules.
|
||||
* @param LoopScope|null $loop The Divi loop of the values; null = none.
|
||||
* @throws InvalidArgumentException When the map does not have that shape.
|
||||
*/
|
||||
public function __construct(private DesignSystem $design, ?array $dynamicContent = null)
|
||||
public function __construct(private DesignSystem $design, ?array $dynamicContent = null, ?LoopScope $loop = null)
|
||||
{
|
||||
$this->content = new DynamicContentRules($design, $dynamicContent);
|
||||
$this->content = new DynamicContentRules($design, $dynamicContent, $loop);
|
||||
}
|
||||
|
||||
/** Whether $value contains a reference anywhere (such a value may only be a whole reference). */
|
||||
|
||||
Reference in New Issue
Block a user