Every file under src/ exits outside WordPress (defined('ABSPATH') ||
exit; after the use block, so a direct request no longer prints a fatal
error with the server path); divi-convert-fixture.php gets the WP_CLI
guard the other integration scripts have. A unit test keeps both true;
PSR1 side-effects warning excluded for the guard.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7
61 lines
2.3 KiB
PHP
61 lines
2.3 KiB
PHP
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
namespace LIT\MCP\Integrations\Divi\Compose;
|
||
|
||
use LIT\MCP\Integrations\Divi\BlockTree\Serializer;
|
||
|
||
defined('ABSPATH') || exit;
|
||
|
||
/**
|
||
* The forms a search text can take in stored block markup – the database prefilter of
|
||
* lit/divi-replace-text and the check for global modules it does not edit. Only a prefilter:
|
||
* the exact, safe match happens in the tree (TextReplacer). Pure PHP.
|
||
*/
|
||
final class StoredForms
|
||
{
|
||
/**
|
||
* The search text as it can be stored in block markup: raw, as serialize_block_attributes()
|
||
* escapes it (<, >, &, " and --; the JS builder keeps non-ASCII raw) and with \uXXXX for
|
||
* non-ASCII (WordPress' PHP serializer). Case-insensitive adds the lower and upper case
|
||
* forms, since the hex digits of \u escapes do not fold.
|
||
*
|
||
* @return list<string>
|
||
*/
|
||
public static function of(string $search, bool $caseSensitive): array
|
||
{
|
||
$variants = $caseSensitive ? [$search] : [$search, mb_strtolower($search), mb_strtoupper($search)];
|
||
$forms = [];
|
||
foreach ($variants as $variant) {
|
||
$escaped = substr(Serializer::attributes(['s' => $variant]), 6, -2);
|
||
array_push($forms, $variant, $escaped, self::unicodeEscaped($escaped));
|
||
}
|
||
|
||
return array_values(array_unique($forms));
|
||
}
|
||
|
||
/** Whether block markup contains $search in one of its stored forms. */
|
||
public static function mentions(string $markup, string $search, bool $caseSensitive): bool
|
||
{
|
||
foreach (self::of($search, $caseSensitive) as $form) {
|
||
$found = $caseSensitive ? str_contains($markup, $form) : mb_stripos($markup, $form) !== false;
|
||
if ($found) {
|
||
return true;
|
||
}
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
/** Non-ASCII characters as JSON \uXXXX escapes (UTF-16, lower-case hex like json_encode()). */
|
||
private static function unicodeEscaped(string $value): string
|
||
{
|
||
return (string) preg_replace_callback('/[^\x00-\x7F]/u', static function (array $match): string {
|
||
$units = unpack('n*', (string) mb_convert_encoding($match[0], 'UTF-16BE', 'UTF-8'));
|
||
|
||
return implode('', array_map(static fn (int $unit): string => sprintf('\\u%04x', $unit), (array) $units));
|
||
}, $value);
|
||
}
|
||
}
|