feat: Divi tools edit Theme Builder layouts; visible layouts need confirm
TB layouts load through ThemeBuilderAccess (P12), live layouts (attached + enabled, Q8) need a dry run and confirm (Q9) and get the shared restore point of VisibleEdits, extracted from GlobalEdits (Q2: backup when revisions are off, P9 refusals, P14 naming). divi/post-content only in body layouts (F22), also for nested stored nodes. SaveScope::ThemeBuilderLayout sets Divi flags and clears site CSS + TB cache. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace LIT\MCP\Integrations\Divi\ThemeBuilder;
|
||||
|
||||
use LIT\MCP\Abilities\Errors;
|
||||
use LIT\MCP\Abilities\WriteFailed;
|
||||
use LIT\MCP\Integrations\Divi\Pages\DiviPage;
|
||||
use LIT\MCP\Integrations\Divi\Pages\SaveScope;
|
||||
use LIT\MCP\Integrations\Divi\Pages\VisibleEdits;
|
||||
use WP_Error;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* The extra rule of a Divi write to a Theme Builder layout (Etappe 3b, constraint "sichtbare Website nur mit
|
||||
* ausdrücklicher Freigabe"): Divi reads TB layouts live (F22), so a layout that a live template (attached to the
|
||||
* live Theme Builder and enabled, whatever its post status – ruling Q8) shows changes the website at once –
|
||||
* without confirm: true nothing is saved and the answer lists those templates (dry run of the fully validated
|
||||
* change, like global modules, answer F2; ruling Q9). A confirmed edit gets the restore point of every visible
|
||||
* change (VisibleEdits, ruling Q2): a backup when revisions are off, refused when it could not be faithful (P9).
|
||||
* Layouts of disabled or detached templates save at once. The save scope sets the Divi flags and clears every
|
||||
* page's CSS and the Theme Builder cache.
|
||||
*/
|
||||
final class ThemeBuilderEdits
|
||||
{
|
||||
public function __construct(
|
||||
private ThemeBuilderAccess $access,
|
||||
private VisibleEdits $visible = new VisibleEdits()
|
||||
) {
|
||||
}
|
||||
|
||||
/** @return list<Template> Live templates that show layout $page in its area. */
|
||||
public function showing(DiviPage $page): array
|
||||
{
|
||||
$area = (string) $page->themeBuilderArea();
|
||||
$id = (int) $page->post->ID;
|
||||
|
||||
return array_values(array_filter(
|
||||
$this->access->store()->liveTemplates(),
|
||||
static fn (Template $template): bool => $template->showsLayout($area, $id)
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $input
|
||||
* @return array{scope: SaveScope, details: array<string, mixed>}|WP_Error
|
||||
* @throws WriteFailed When the backup could not be made (nothing was saved).
|
||||
*/
|
||||
public function prepare(DiviPage $page, array $input): array|WP_Error
|
||||
{
|
||||
$templates = $this->showing($page);
|
||||
$details = ['templates' => self::listing($templates)];
|
||||
if ($templates === []) {
|
||||
return ['scope' => SaveScope::ThemeBuilderLayout, 'details' => $details];
|
||||
}
|
||||
|
||||
$id = (int) $page->post->ID;
|
||||
if (($input['confirm'] ?? false) !== true) {
|
||||
return Errors::confirmRequired(
|
||||
sprintf(
|
||||
'Theme-Builder-Layout %d ist auf der Website sichtbar (%s, siehe templates); die Änderung wirkt '
|
||||
. 'sofort. Nichts wurde gespeichert (Probelauf).',
|
||||
$id,
|
||||
self::count($templates)
|
||||
),
|
||||
$details
|
||||
);
|
||||
}
|
||||
|
||||
$refusal = $this->visible->backupRefusal(
|
||||
$page->post,
|
||||
sprintf('Theme-Builder-Layout %d', $id),
|
||||
'Revisionen aktivieren (WP_POST_REVISIONS) oder das Layout im Divi Theme Builder bearbeiten.'
|
||||
);
|
||||
if ($refusal !== null) {
|
||||
return $refusal;
|
||||
}
|
||||
|
||||
return [
|
||||
'scope' => SaveScope::ThemeBuilderLayout,
|
||||
'details' => array_merge($details, $this->visible->backup($page->post)),
|
||||
];
|
||||
}
|
||||
|
||||
/** A tool's own confirm_required (lit-divi-delete) on a visible layout, extended by the templates. */
|
||||
public function notice(DiviPage $page, WP_Error $error): WP_Error
|
||||
{
|
||||
$templates = Errors::codeOf($error) === 'confirm_required' ? $this->showing($page) : [];
|
||||
if ($templates === []) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
return VisibleEdits::merged(
|
||||
$error,
|
||||
sprintf('Das Layout ist auf der Website sichtbar (%s, siehe templates).', self::count($templates)),
|
||||
['templates' => self::listing($templates)]
|
||||
);
|
||||
}
|
||||
|
||||
/** @param list<Template> $templates */
|
||||
private static function count(array $templates): string
|
||||
{
|
||||
return sprintf('%d aktive %s', count($templates), count($templates) === 1 ? 'Vorlage' : 'Vorlagen');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param list<Template> $templates
|
||||
* @return list<array{id: int, title: string, use_on: list<string>}>
|
||||
*/
|
||||
private static function listing(array $templates): array
|
||||
{
|
||||
return array_map(
|
||||
static fn (Template $template): array => [
|
||||
'id' => $template->id,
|
||||
'title' => $template->title,
|
||||
'use_on' => $template->useOn,
|
||||
],
|
||||
$templates
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user