feat: Pods fields in Theme Builder bodies checked against the template's post types (E12)

Both forms Divi writes are recognized (ruling Q11): custom_meta_<key> and the
dialog form post_meta_key + select_meta_key. Choice fields get a note about the
stored value, relation fields name IDs (F4). Only templates the user may edit
are checked or named; others are counted (Q21 pattern). Warnings only, also in
the dry run of a live body. DynamicFields extracted from lit/divi-dynamic-sources.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-27 21:02:53 +02:00
co-authored by Claude Opus 5.5
parent a31d4340f9
commit 6be2e65432
15 changed files with 778 additions and 86 deletions
@@ -7,12 +7,14 @@ namespace LIT\MCP\Tests\Unit\Integrations\Divi\ThemeBuilder;
use Brain\Monkey\Functions;
use LIT\MCP\Abilities\WriteFailed;
use LIT\MCP\Integrations\Divi\Pages\DiviSaver;
use LIT\MCP\Integrations\Divi\Pages\DynamicFields;
use LIT\MCP\Integrations\Divi\Pages\SaveScope;
use LIT\MCP\Integrations\Divi\ThemeBuilder\DiviThemeBuilder;
use LIT\MCP\Integrations\Divi\ThemeBuilder\InsertedBeforeFailure;
use LIT\MCP\Integrations\Divi\ThemeBuilder\TbCreateTemplateAbility;
use LIT\MCP\Integrations\Divi\ThemeBuilder\Template;
use LIT\MCP\Integrations\Divi\ThemeBuilder\TemplateConditions;
use LIT\MCP\Integrations\Divi\ThemeBuilder\ThemeBuilderEdits;
use LIT\MCP\Tests\Support\DiviWriterFixture;
use LIT\MCP\Tests\Support\FakeChangeLog;
use LIT\MCP\Tests\Support\LibraryFixtures;
@@ -86,10 +88,22 @@ final class TbCreateTemplateAbilityTest extends TestCase
new TemplateConditions($store),
DiviWriterFixture::composition(DiviWriterFixture::designReader()),
$saver,
$log ?? DiviWriterFixture::log()
$log ?? DiviWriterFixture::log(),
new ThemeBuilderEdits(ThemeBuilderFixtures::access([], true, $store), fields: self::personFields())
);
}
private static function personFields(): DynamicFields
{
$fields = Mockery::mock(DynamicFields::class);
$fields->allows('reason')->andReturnUsing(
static fn (string $type, string $key): ?string => $key === 'role' ? null : 'kein bekanntes Feld dieses Inhaltstyps'
);
$fields->allows('note')->andReturnNull();
return $fields;
}
/** @return array<string, mixed> */
private static function input(array $extra = []): array
{
@@ -441,4 +455,20 @@ final class TbCreateTemplateAbilityTest extends TestCase
self::assertToolError($result, 'validation_failed');
self::assertArrayHasKey('header.source', self::errorFields($result));
}
public function testAnUnknownFieldInTheNewBodyIsAWarning(): void
{
$store = self::store();
self::expectCreation($store);
$store->shouldReceive('attach')->once();
$store->shouldReceive('clearCaches')->once();
$input = self::input();
$input['body']['nodes'][0]['modules'][] = ['type' => 'text', 'content' => '{{field:telefon}}'];
$result = $this->ability($store)->execute($input);
self::assertTrue($result['ok']);
self::assertNotSame([], array_filter($result['warnings'], static fn (string $w): bool => str_contains($w, '„telefon“')));
self::assertSame([], array_filter($result['warnings'], static fn (string $w): bool => str_contains($w, '„role“')));
}
}