fix: check WordPress meta capabilities per field key

Fields from the meta/sample sources need edit_post_meta (update, checked in
PostWriter::prepare) or add_post_meta (create, checked right after the insert;
a refusal deletes the new draft again) for their key; a refusal is a
fields.<key> validation error.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7
This commit is contained in:
2026-09-26 01:24:20 +02:00
co-authored by Claude Opus 5.5
parent 563d9e8d15
commit 106a099483
4 changed files with 160 additions and 0 deletions
@@ -131,6 +131,49 @@ final class PostWriterTest extends TestCase
self::assertCount(1, $result['warnings']);
}
public function testMetaFieldsNeedTheRightToEditThatMetaKeyOnUpdate(): void
{
Functions\when('get_object_taxonomies')->justReturn([]);
$schema = Mockery::mock(ContentSchema::class);
$schema->allows('fields')->andReturn([
'city' => new FieldDefinition('city', 'city', 'unknown', 'sample', 'unknown'),
'secret' => new FieldDefinition('secret', 'secret', 'string', 'meta', 'writable'),
'role' => new FieldDefinition('role', 'Funktion', 'string', 'pods', 'writable'),
]);
$checked = [];
Functions\when('current_user_can')->alias(static function (string $cap, ...$args) use (&$checked): bool {
$checked[] = array_merge([$cap], $args);
return $args !== [5, 'secret'];
});
$result = (new PostWriter($schema, new FieldValidator(), new TermAssigner()))->prepare(
'page',
['post_id' => 5, 'fields' => ['city' => 'Trier', 'secret' => 'x', 'role' => 'Leitung']],
false
);
self::assertSame(['fields.secret' => 'Keine Berechtigung, dieses Feld zu ändern.'], $result->get_error_data()['fields']);
self::assertSame([['edit_post_meta', 5, 'city'], ['edit_post_meta', 5, 'secret']], $checked);
}
public function testCreateChecksMetaRightsOnlyOnceTheDraftExists(): void
{
Functions\when('get_object_taxonomies')->justReturn([]);
$schema = Mockery::mock(ContentSchema::class);
$schema->allows('fields')->andReturn([
'city' => new FieldDefinition('city', 'city', 'unknown', 'sample', 'unknown'),
'role' => new FieldDefinition('role', 'Funktion', 'string', 'pods', 'writable'),
]);
Functions\expect('current_user_can')->once()->with('add_post_meta', 42, 'city')->andReturn(false);
$writer = new PostWriter($schema, new FieldValidator(), new TermAssigner());
self::assertIsArray($writer->prepare('page', ['fields' => ['city' => 'Trier', 'role' => 'x']], true));
self::assertSame(
['fields.city' => 'Keine Berechtigung, dieses Feld zu ändern.'],
$writer->deniedMeta(42, 'page', ['city' => 'Trier', 'role' => 'x'], 'add_post_meta')
);
}
public function testPostDataMapsOnlyGivenKeys(): void
{
$writer = new PostWriter(Mockery::mock(ContentSchema::class), new FieldValidator(), new TermAssigner());