fix: find-similar marks replaceable matches and names excluded types (review M-3, M-7, M-8)

Every match carries replaceable: true only when it is identical and in a
page or post, the scope lit/library-make-global replaces; the description
and the guide say so. An excluded post type is answered like any
unavailable one, by its name (PostGuard::unavailableType()), and the
excluded list takes the Theme Builder types from DiviThemeBuilder::postTypes().

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-27 23:09:13 +02:00
co-authored by Claude Opus 5.5
parent 5290a9d81d
commit e7bbe1e9d7
4 changed files with 80 additions and 28 deletions
@@ -150,14 +150,50 @@ final class LibraryFindSimilarAbilityTest extends TestCase
{
Functions\expect('get_posts')->never();
foreach (['et_pb_layout', 'et_body_layout', 'et_header_layout', 'et_footer_layout', 'et_template'] as $type) {
self::assertToolError(
self::ability()->execute(['library_id' => 1055, 'post_type' => $type]),
'not_found'
);
foreach (
['et_pb_layout', 'et_body_layout', 'et_header_layout', 'et_footer_layout', 'et_template', 'et_theme_builder']
as $type
) {
$refused = self::ability()->execute(['library_id' => 1055, 'post_type' => $type]);
self::assertToolError($refused, 'not_found');
// Review M-7: named like any unavailable type, never as "".
self::assertSame(sprintf('Inhaltstyp "%s" ist nicht verfügbar.', $type), self::clientError($refused)['message']);
}
}
/**
* Review M-8: lit/library-make-global replaces only pages and posts – every match says whether it can be
* replaced there (identical and of such a type).
*/
public function testMatchesSayWhetherMakeGlobalCanReplaceThem(): void
{
$project = get_post(8);
$project = new WP_Post(['ID' => 10, 'post_type' => 'project', 'post_status' => 'publish', 'post_title' => 'Projekt',
'post_content' => $project->post_content]);
LibraryFixtures::given(array_merge([get_post(8), $project], array_map(
static fn (int $id): WP_Post => LibraryFixtures::item($id),
array_keys(LibraryFixtures::ITEMS)
)));
Functions\when('get_post_type_object')->justReturn((object) ['cap' => (object) [
'edit_posts' => 'edit_posts',
'edit_others_posts' => 'edit_others_posts',
]]);
// The query is mocked: it stands for a scan over several Divi-enabled types.
Functions\when('get_posts')->justReturn([8, 10]);
$result = self::ability()->execute(['library_id' => 1055, 'post_type' => 'page']);
$found = array_map(
static fn (array $m): string => sprintf('%d %s %s %s', $m['post_id'], $m['id'], $m['match'], json_encode($m['replaceable'])),
$result['matches']
);
self::assertSame(
['8 s0 structure false', '8 s1 identical true', '10 s0 structure false', '10 s1 identical false'],
$found
);
self::assertStringContainsString('replaceable', self::ability()->description());
}
/** With the library group hidden the library entry is answered like a missing ID (P9/P12). */
public function testAHiddenLibraryAnswersLikeAMissingEntry(): void
{