- ThemeBuilderAccess::changeableTemplate(): rights (Q18 not_found), group gate,
no TB draft, never the default template, current template_rev
- omitted exclude_from stays, [] clears (Q3); live dry run shows use_on and
exclude_from before/after, overlaps and possible overlaps (B9)
- reattach only with published layouts (B10) and a live TB post; always
disabled, unmarks template and layouts; failure restores everything
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Outline, node-get, write outlines, the render summary and replace-text's
opaque-node match name no library ID unless the library group is visible
and the user has divi_library; read-only still names them.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Reuses NewDraft for insert and rollback (P6), requires edit_global_library
for scope global (P7), refuses opaque and global roots before wrapping (P11)
and checks the node with StoredNodeGuard. The source page is never written.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- tests/Support/FakeChangeLog extends ChangeLog: records record()/recordPartial()
calls, increasing ids, optional failure; new FakeChangeLog(id) / partialsOnly() /
any(id) / forbidden() mirror what the replaced mocks allowed. assertRecorded() /
assertPartials() check count and the named arguments. Calls a fake does not allow
throw and are also verified in TestCase::tearDown (one assertion per test that
uses a fake), so swallowed change-log calls still fail like a never() expectation.
- All ChangeLog mocks of ability/integration tests replaced (the admin tests that
stub query/purge/clear keep their mocks); expectException tests that checked the
partial log now catch and assert.
- SchemaFixture::managed(?divi) replaces the 21 isManaged-only ContentSchema mocks;
DiviFixtures::schema() uses it.
Tests 1397 -> 1404 (FakeChangeLogTest); no test has fewer assertions.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
New input divi (1-30 sections, short form like lit-divi-insert) builds a Divi 5
layout in one divi/placeholder. The whole description is checked before the
insert (Divi's map for "no entry yet"); the draft is inserted with its normal
WordPress fields only, then DiviContentComposer composes again bound to the new
entry and stores it via DiviSaver::saveNew (same kses window as save(), strict
DiviFlags). A refusal or failure deletes the draft. Result adds tree_rev and the
outline.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
TextReplacer replaces only in plain-text segments (S8 split), outside
script/style bodies, inserts the replacement cleaned per field kind and
refuses any result whose tags, entities or references differ from the
original plus the inserted text. Unchanged strings are never cleaned.
Per page all or nothing with the tree_rev lock; Throwables are reported
per page (S10).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7
Adds per-path attribute kind (text/richtext/code/url/image/color/enum/
onoff/number/list/icon), derived from Divi's field component metadata
where an attribute path names one unambiguously (module.paths() itself
is unchanged; kinds() is a new, separate lookup exposed as path_kinds
on lit/divi-catalog's module detail). This is not in the task-4 brief;
it is added because 2b's sanitization routing (ruling R3) needs a
metadata-derived field kind per attribute path. Verified live against
the full 100-module catalog (564/4358 paths resolve a kind; the rest
default to "unknown" and fall back to 2b's key-name routing).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7