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
@@ -160,7 +160,7 @@ class ThemeBuilderAccess
* never the default template (E8), the current template_rev. $offSwitch (lit/tb-activate with enabled: false,
* ruling Q16): also a template visitors see although it is not published (e.g. in the trash – Divi renders
* every attached, enabled template, B8), so it can always be switched off; any other unpublished template
* still reads as missing.
* still reads as missing. The off-switch also works while the Theme Builder has unsaved changes (ruling Q20).
*
* @param array<string, mixed> $input template_id, template_rev
*/
@@ -177,10 +177,27 @@ class ThemeBuilderAccess
$gate = $this->writableGate();
return $gate ?? $this->checkedTemplate($id, $input);
return $gate ?? $this->checkedTemplate($id, $input, true);
}
return $this->checkedTemplate((int) $post->ID, $input);
return $this->checkedTemplate((int) $post->ID, $input, $offSwitch);
}
/**
* The templates of the live Theme Builder post split by canEditTemplate() (ruling Q21 – one place for
* tb-list and the dry runs of tb-assign/tb-activate): only "templates" may be shown; "hidden" serves counts
* ("weitere aktive Vorlagen ohne Berechtigung"), never its IDs, titles or conditions (Q8/B11, P12).
*
* @return array{templates: list<Template>, hidden: list<Template>}
*/
public function editableLiveTemplates(): array
{
$split = ['templates' => [], 'hidden' => []];
foreach ($this->store->liveTemplates() as $template) {
$split[$this->canEditTemplate($template->id) ? 'templates' : 'hidden'][] = $template;
}
return $split;
}
/**
@@ -297,12 +314,14 @@ class ThemeBuilderAccess
/**
* The draft, default and template_rev checks of changeableTemplate() for template $id (rights already checked).
* The off-switch skips the draft refusal (ruling Q20): hiding a template must always be possible; the caller
* warns that saving an open Theme Builder editor may restore its own state.
*
* @param array<string, mixed> $input
*/
private function checkedTemplate(int $id, array $input): Template|WP_Error
private function checkedTemplate(int $id, array $input, bool $offSwitch): Template|WP_Error
{
$refusal = $this->draftRefusal();
$refusal = $offSwitch ? null : $this->draftRefusal();
if ($refusal !== null) {
return $refusal;
}