Every file under src/ exits outside WordPress (defined('ABSPATH') ||
exit; after the use block, so a direct request no longer prints a fatal
error with the server path); divi-convert-fixture.php gets the WP_CLI
guard the other integration scripts have. A unit test keeps both true;
PSR1 side-effects warning excluded for the guard.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7
Composer::autoLabel is private (tested through compose()); the
DiviComposition getters used only by tests are marked @internal;
Limits::snapshotCount is documented as reserved; the ShortformWriter test
seam is named $modulesForTests.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7
The choke point moves out of AttrWriter into ValueCleaner (catalog, the
composition's VariableRef, sanitizer): clean() (was AttrWriter::cleanValue),
kindOf(), guardPath() and the private cleanNode/kind/unknownKind/tightens with
VALUE_KEY, URL_KEY, URL_SEGMENT, STRICTNESS, BUILDER_ONLY (its docblock now sits
on it; STRUCTURE stays in AttrWriter). Code of the pipeline moved unchanged.
- ValueCleaner's docblock is the one canonical description: steps 0-8 with their
rulings in code order, invariants I1-I3; the step comments in cleanNode carry
the same numbers. AttrWriter/ShortformWriter/Composer/TextReplacer docblocks
point there and keep only their own rules.
- ValueCleaner::textReplacementFor($module) holds the D10 rule that was a
closure in DiviReplaceTextAbility::replace (text/html only, clean() by kind).
- AttrWriter, ShortformWriter and Composer take the ValueCleaner; DiviComposition
builds one per composition (cleaner()).
Tests: the eight AttrWriterTest methods that only exercised cleanValue/kindOf
moved verbatim to ValueCleanerTest (clean/kindOf, ComposeFixture::cleaner());
mixed tests call the cleaner in place; +1 test for textReplacementFor. Every
provider row and per-test assertion count unchanged.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7
- DiviComposition::references() builds the one VariableRef with the entry's
live map (S22/S31) and passes it to AttrWriter; Placeholders only needs the
design system now, Placeholders::references() is gone (no reach-through).
- DesignSystem::colorIdFor()/variableFor() replace the dead colorId()/variable()
and carry Placeholders' lookup incl. the S13a ambiguity check (byLabel moved,
messages unchanged); isColorVariable() decides color vs content for {{var:}}.
- DesignSystem::colorReferenceIds() (VariableRef color names) and
contentVariableIds() (DynamicContentRules design names) replace the two
inline computations; same lists, same order.
Tests: fixtures/tests get the VariableRef from ComposeFixture::references() or
build it with the map; DesignSystemTest uses the new lookups (+2 tests).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7
DiviSaver/DiviWriter/DiviComposition/DiviChange, WpValueSanitizer (S4),
WpMediaResolver, DiviFlags (S11), DynamicContentMap from Divi's live
registry (S22), S31 wiring, S35 control strip at apply() entry.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>