From 3a89b15b59cb52ee4dc8eda6fc417fb0fe98de62 Mon Sep 17 00:00:00 2001 From: Jan-Niclas Loosen Date: Tue, 20 Oct 2026 00:14:57 +0200 Subject: [PATCH] =?UTF-8?q?fix(audit=20M1):=20Update-/Move-Warnung=20nur?= =?UTF-8?q?=20f=C3=BCr=20Inhalte,=20die=20vorher=20zur=20Schleifen-Kette?= =?UTF-8?q?=20passten=20(kein=20Alarm=20f=C3=BCr=20ACF-Optionen);=20Tests?= =?UTF-8?q?=20f=C3=BCr=20Update=20und=20Kettenwarnung=20beim=20Move?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 5.5 --- .../Divi/Design/PresetRestorePlanner.php | 5 +- .../Divi/Design/RestoreUsages.php | 4 +- .../Divi/Pages/DiviWriteAbility.php | 8 ++- .../Divi/Pages/DiviLoopWriteTest.php | 50 +++++++++++++++++++ 4 files changed, 61 insertions(+), 6 deletions(-) diff --git a/src/Integrations/Divi/Design/PresetRestorePlanner.php b/src/Integrations/Divi/Design/PresetRestorePlanner.php index bab2331..daa35f5 100644 --- a/src/Integrations/Divi/Design/PresetRestorePlanner.php +++ b/src/Integrations/Divi/Design/PresetRestorePlanner.php @@ -78,8 +78,9 @@ final class PresetRestorePlanner implements RestorePlanner } /** - * Audit L4: the pages using a preset the restore touches in any way, also re-created ones (spec §4 step 4, ruling P8a); a default - * preset also counts its implicit users (like lit/divi-presets-delete). The orphan warning stays (spec §5). + * Audit L4: the pages using a preset the restore touches in any way, also re-created ones (spec §4 step 4, + * ruling P8a); a default preset also counts its implicit users (like lit/divi-presets-delete). The orphan + * warning stays (spec §5). * * @param list> $diff */ diff --git a/src/Integrations/Divi/Design/RestoreUsages.php b/src/Integrations/Divi/Design/RestoreUsages.php index d872aac..49e9092 100644 --- a/src/Integrations/Divi/Design/RestoreUsages.php +++ b/src/Integrations/Divi/Design/RestoreUsages.php @@ -11,8 +11,8 @@ defined('ABSPATH') || exit; /** * The usages a snapshot restore has to report (audit L4, spec §4 step 4): the pages that use an entry the restore - * changes, removes, (de)activates or re-creates (an old ID that pages still reference) – DesignChange then blocks the confirmed restore for pages the caller may not edit - * (ruling P8a) and the dry run lists them as "affected". + * changes, removes, (de)activates or re-creates (an old ID that pages still reference) – DesignChange then blocks + * the confirmed restore for pages the caller may not edit (ruling P8a) and the dry run lists them as "affected". */ final class RestoreUsages { diff --git a/src/Integrations/Divi/Pages/DiviWriteAbility.php b/src/Integrations/Divi/Pages/DiviWriteAbility.php index 37b6e29..7c927b8 100644 --- a/src/Integrations/Divi/Pages/DiviWriteAbility.php +++ b/src/Integrations/Divi/Pages/DiviWriteAbility.php @@ -170,7 +170,8 @@ abstract class DiviWriteAbility implements Ability, RequiresDiviFeatures /** * Whether moving or changing loop content from $from to $to needs a warning: the kind changes, or (audit M1) - * a loop option no longer fits the whole chain – meta key options are checked against every enclosing loop. + * a loop option that fitted before no longer fits the whole chain – meta key options are checked against every + * enclosing loop. Content that never fitted (ACF repeater options, unknown loops) is not the move's doing. * * @param list $names */ @@ -181,7 +182,10 @@ abstract class DiviWriteAbility implements Ability, RequiresDiviFeatures } return $from->kind() !== $to->kind() - || array_filter($names, static fn (string $name): bool => ! $to->fits($name)) !== []; + || array_filter( + $names, + static fn (string $name): bool => $from->fits($name) && ! $to->fits($name) + ) !== []; } /** @param list $names */ diff --git a/tests/Unit/Integrations/Divi/Pages/DiviLoopWriteTest.php b/tests/Unit/Integrations/Divi/Pages/DiviLoopWriteTest.php index 84e8653..ef1b2d8 100644 --- a/tests/Unit/Integrations/Divi/Pages/DiviLoopWriteTest.php +++ b/tests/Unit/Integrations/Divi/Pages/DiviLoopWriteTest.php @@ -480,4 +480,54 @@ final class DiviLoopWriteTest extends DiviWriteAbilityTestCase self::assertStringContainsString($right, self::problems($updated)); self::assertSame([], $this->saved); } + + private function usePage(string $content): void + { + $this->original = $content; + $this->post->post_content = $content; + } + + /** Re-review: content that never fitted its loop (ACF repeater options) is no reason for a warning on an update. */ + public function testUpdatingALoopContainerDoesNotWarnForContentThatNeverFitted(): void + { + $acf = VariableRef::serialize('content', 'loop_acf_name', ['before' => '', 'after' => '']); + $text = self::block('text', ['content' => ['innerContent' => ['desktop' => ['value' => $acf]]]]); + $repeater = ['enable' => 'on', 'queryType' => 'repeater_team']; + $this->usePage('' . self::block('section', self::loop($repeater), self::block( + 'row', + [], + self::block('column', [], $text) + )) . ''); + + $result = $this->changeAll([[ + 'id' => 's0', + 'attrs' => ['module.decoration.background' => ['desktop' => ['color' => '#ff0000']]], + ]]); + + self::assertTrue($result['ok'], (string) json_encode($result)); + self::assertStringNotContainsString('Schleife', implode(' | ', $result['warnings'])); + } + + /** Re-review (M1): a moved loop with a post meta key option takes the outer term loop into its chain – warned. */ + public function testMovingALoopWithMetaKeyContentUnderAnotherKindOfLoopWarns(): void + { + $meta = VariableRef::serialize( + 'content', + 'loop_post_meta_key_manual_custom_field', + ['before' => '', 'after' => ''] + ); + $own = self::block('text', self::loop(self::POST_LOOP) + [ + 'content' => ['innerContent' => ['desktop' => ['value' => $meta]]], + ]); + $termColumn = self::block('column', self::loop(self::TERM_LOOP), self::text('y')); + $this->usePage('' . self::block('section', [], self::block('row', [], implode('', [ + self::block('column', [], $own), + $termColumn, + ]))) . ''); + + $result = $this->moveNode(['id' => 's0.r0.c0.m0', 'parent' => 's0.r0.c1']); + + self::assertTrue($result['ok'], (string) json_encode($result)); + self::assertStringContainsString('loop_post_meta_key_manual_custom_field', implode(' | ', $result['warnings'])); + } }