fix: TB dry runs hide uneditable live templates, off-switch despite draft (rulings Q20, Q21)

- ThemeBuilderAccess::editableLiveTemplates() shared by tb-list and the tb-assign/tb-activate dry runs;
  uneditable live templates only as a count (hidden_overlaps, hidden_live)
- tb-activate enabled:false works while the Theme Builder has a draft, with a warning
- possible_overlaps skips identical conditions; reattach records the previous enabled state;
  exclude_from must be a list; tb-activate live from the read-back

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-27 20:55:53 +02:00
co-authored by Claude Opus 5.5
parent 64fc439cb2
commit a31d4340f9
11 changed files with 355 additions and 37 deletions
@@ -118,9 +118,14 @@ final class TbAssignAbility implements Ability
$useOn = is_array($input['use_on'] ?? null)
? $this->conditions->check($input['use_on'], 'use_on')
: ['ids' => [], 'errors' => ['use_on' => 'Liste von Bedingungs-IDs erwartet (leere Liste = keine)']];
$excludeFrom = array_key_exists('exclude_from', $input)
? $this->conditions->check($input['exclude_from'] ?? [], 'exclude_from')
: ['ids' => $template->excludeFrom, 'errors' => []];
$excludeFrom = match (true) {
! array_key_exists('exclude_from', $input) => ['ids' => $template->excludeFrom, 'errors' => []],
is_array($input['exclude_from']) => $this->conditions->check($input['exclude_from'], 'exclude_from'),
default => [
'ids' => [],
'errors' => ['exclude_from' => 'Liste von Bedingungs-IDs erwartet ([] entfernt die Ausnahmen)'],
],
};
$errors = array_merge($useOn['errors'], $excludeFrom['errors']);
if ($errors !== []) {
return Errors::invalidInput('Bedingungen sind ungültig; nichts wurde gespeichert.', $errors);
@@ -181,20 +186,19 @@ final class TbAssignAbility implements Ability
*/
private function dryRun(Template $template, array $useOn, array $excludeFrom): WP_Error
{
$live = $this->access->store()->liveTemplates();
$overlaps = Template::overlapDetails($this->access->editableLiveTemplates(), $template->id, $useOn);
return Errors::confirmRequired(
sprintf(
'Vorlage „%s“ ist aktiv; die neuen Bedingungen (use_on) und Ausnahmen (exclude_from) wirken sofort auf '
. 'der Website – vorher/nachher unter before/after. Nichts wurde gespeichert (Probelauf).',
$template->title
. 'der Website – vorher/nachher unter before/after.%s Nichts wurde gespeichert (Probelauf).',
$template->title,
Template::hiddenOverlapsNote($overlaps['hidden_overlaps'])
),
[
'before' => $this->labels($template->useOn, $template->excludeFrom),
'after' => $this->labels($useOn, $excludeFrom),
'overlaps' => Template::overlaps($live, $template->id, $useOn),
'possible_overlaps' => Template::possibleOverlaps($live, $template->id, $useOn),
]
] + $overlaps
);
}
@@ -256,7 +260,12 @@ final class TbAssignAbility implements Ability
sprintf(
'Theme Builder: Bedingungen von „%s“ gesetzt%s (vorher: %s; Ausnahmen vorher: %s)',
$template->title,
$reattach ? ', wieder zugeordnet (deaktiviert)' : '',
$reattach
? sprintf(
', wieder zugeordnet (deaktiviert, vorher %s)',
$template->enabled ? 'aktiviert' : 'deaktiviert'
)
: '',
self::listed($template->useOn),
self::listed($template->excludeFrom)
)
@@ -276,7 +285,8 @@ final class TbAssignAbility implements Ability
->with('template_id', $template->id)
->with('template_rev', $after?->rev() ?? '')
->with('live', $live)
->with('previous', ['use_on' => $template->useOn, 'exclude_from' => $template->excludeFrom])
->with('previous', ['use_on' => $template->useOn, 'exclude_from' => $template->excludeFrom]
+ ($reattach ? ['enabled' => $template->enabled] : []))
->warnings($warnings)
->logId($logId)
->urls(null, (string) admin_url('admin.php?page=et_theme_builder'))