fix: global usages follow the Theme Builder access (ruling Q17 M1)

GlobalUsages gets the Theme Builder access injected as a closure
(ThemeBuilderAccess::usageState(), wired at both construction sites through
DiviIntegration::globalUsages()). Theme Builder posts are named only while
the Theme Builder is visible to the account, otherwise only counted (also
in blocked_ids); a global edit that changes them needs canUse(), a writable
"Divi Theme Builder" group and edit_post. Without an injected access the
fail-safe default checks what canUse() checks. The duplicate
THEME_BUILDER_TYPES list gives way to 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:00:36 +02:00
co-authored by Claude Opus 5.5
parent 7590da4d96
commit 43dc3fb889
11 changed files with 271 additions and 32 deletions
@@ -94,6 +94,38 @@ final class DiviIntegrationTest extends TestCase
}
}
/**
* Review I-2 (ruling Q17 M1): the library usages follow the Theme Builder access – without it (here: no Divi
* role check in unit tests, so canUse() fails) TB layouts are counted and block, never named.
* ThemeBuilderAccessTest covers usageState() itself.
*/
public function testGlobalUsagesFollowTheThemeBuilderAccess(): void
{
Functions\when('current_user_can')->justReturn(true);
Functions\when('get_post')->justReturn(null);
Functions\when('_get_non_cached_ids')->returnArg(1);
Functions\when('_prime_post_caches')->justReturn(null);
Functions\when('wp_cache_delete')->justReturn(true);
$db = Mockery::mock(\wpdb::class)->makePartial();
$db->allows('get_results')->andReturnUsing(static fn (string $sql): array => str_contains($sql, 'post_content FROM')
? [
['ID' => '1053', 'post_content' => '<!-- wp:divi/global-layout {"globalModule":"1058"} /-->'],
['ID' => '1061', 'post_content' => '<!-- wp:divi/global-layout {"globalModule":"1058"} /-->'],
]
: [
['ID' => '1053', 'post_status' => 'publish', 'post_type' => 'page'],
['ID' => '1061', 'post_status' => 'publish', 'post_type' => 'et_header_layout'],
]);
$report = (new DiviIntegration(Mockery::mock(ContentSchema::class), FakeChangeLog::forbidden()))
->globalUsages($db)
->report(1058);
self::assertSame([1053], array_column($report->items, 'post_id'));
self::assertSame([], $report->blocked);
self::assertSame(1, $report->blockedHidden);
}
/** Ruling P9 (E9): lit/divi-node-copy follows lit/divi-insert's Tools-tab state. */
public function testNodeCopyFollowsLitDiviInsert(): void
{