fix(4e-review clean-code): eine sanitize_key-Nachbildung (LoopScope::sanitizeKey) statt dreier; Docblock zur strengeren LoopContext::enabled()

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Jan-Niclas Loosen
2026-10-20 00:41:33 +02:00
co-authored by Claude Sonnet 5.5
parent 71ffbdbf59
commit 410e773d28
4 changed files with 29 additions and 11 deletions
@@ -26,7 +26,13 @@ final class LoopContext
{
private const PATH = 'module.advanced.loop';
/** @param array<string, mixed> $attrs Attributes of a block */
/**
* Whether the block runs a loop for the tools: exactly the raw string "on", Divi's render gate. Deliberately
* stricter than the write guard (ValueCleaner::guardLoop reads enable like sanitize_key): a loop the render
* gate does not run gives its content no loop context, which fails closed.
*
* @param array<string, mixed> $attrs Attributes of a block
*/
public static function enabled(array $attrs): bool
{
return (self::settings($attrs)['enable'] ?? null) === 'on';
@@ -45,10 +51,7 @@ final class LoopContext
$queryType = self::settings($attrs)['queryType'] ?? 'post_types';
// Divi's sanitize_key() (LoopUtils.php:729-731) makes a non-string "" and lowercases and strips the rest.
return LoopScope::ofQueryType(
is_string($queryType) ? preg_replace('/[^a-z0-9_\-]/', '', strtolower($queryType)) ?? '' : ''
);
return LoopScope::ofQueryType(LoopScope::sanitizeKey($queryType));
}
/**
@@ -158,6 +158,12 @@ final class LoopScope
return ! str_contains($option, '_meta_key_') || array_unique($this->kinds()) === [$kind];
}
/** Divi's sanitize_key(): lowercase, only a-z, 0-9, "_" and "-"; "" for anything that is no scalar. */
public static function sanitizeKey(mixed $value): string
{
return is_scalar($value) ? (string) preg_replace('/[^a-z0-9_\-]/', '', strtolower((string) $value)) : '';
}
/** Kind of a loop_* option by its name; null for other names and ACF repeater options. */
public static function kindOfOption(string $option): ?string
{
@@ -181,15 +181,14 @@ final class ValueCleaner
return;
}
// Divi reads enable and queryType through sanitize_key() (LoopUtils.php:725-731): stored values count so.
$key = static fn (mixed $value): string => is_scalar($value)
? (string) preg_replace('/[^a-z0-9_\-]/', '', strtolower((string) $value))
: '';
if ($key($desktopValue['enable'] ?? null) !== 'on') {
if (LoopScope::sanitizeKey($desktopValue['enable'] ?? null) !== 'on') {
return;
}
// isset() like Divi: null falls back to post_types.
$queryType = isset($desktopValue['queryType']) ? $key($desktopValue['queryType']) : 'post_types';
$queryType = isset($desktopValue['queryType'])
? LoopScope::sanitizeKey($desktopValue['queryType'])
: 'post_types';
if (($queryType === 'user_roles' || $queryType === 'users') && ! $this->sanitizer->canListUsers()) {
throw new InvalidArgumentException(
'Eine Benutzer-Schleife listet Konten und E-Mail-Adressen und braucht das Recht list_users; '
@@ -214,7 +213,7 @@ final class ValueCleaner
foreach ($raw as $entry) {
$value = is_string($subTypes) ? $entry : (is_array($entry) ? ($entry['value'] ?? null) : null);
if (is_string($value) && trim($value) !== '') {
$types[] = preg_replace('/[^a-z0-9_\-]/', '', strtolower($value));
$types[] = LoopScope::sanitizeKey($value);
}
}
@@ -105,4 +105,14 @@ final class LoopScopeTest extends TestCase
self::assertFalse(LoopScope::ofQueryType('repeater_team')->fits('loop_post_title'));
self::assertTrue(LoopScope::ofQueryType('current_page')->fits('loop_post_title'));
}
/** The one reading of Divi's sanitize_key() (LoopUtils.php:725-731) the loop checks share. */
public function testSanitizeKeyReadsLikeDivi(): void
{
self::assertSame('userbb_roles', LoopScope::sanitizeKey(' User<b></b>_Roles '));
self::assertSame('on', LoopScope::sanitizeKey('o n'));
self::assertSame('1', LoopScope::sanitizeKey(true));
self::assertSame('', LoopScope::sanitizeKey(null));
self::assertSame('', LoopScope::sanitizeKey(['on']));
}
}