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:
@@ -9,6 +9,8 @@ use LIT\MCP\Integrations\Divi\BlockTree\MalformedMarkup;
|
||||
use LIT\MCP\Integrations\Divi\BlockTree\NodeIndex;
|
||||
use LIT\MCP\Integrations\Divi\BlockTree\Parser;
|
||||
use LIT\MCP\Integrations\Divi\Library\LibraryAccess;
|
||||
use LIT\MCP\Integrations\Divi\ThemeBuilder\DiviThemeBuilder;
|
||||
use LIT\MCP\Integrations\Divi\ThemeBuilder\ThemeBuilderAccess;
|
||||
use LIT\MCP\Integrations\WordPress\PostGuard;
|
||||
use LIT\MCP\Integrations\WordPress\Schema\ContentSchema;
|
||||
use LIT\MCP\Log;
|
||||
@@ -18,7 +20,8 @@ use WP_Post;
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Loads an entry for the Divi tools: Divi Library entries via LibraryAccess (E1/E3), every other
|
||||
* Loads an entry for the Divi tools: Divi Library entries via LibraryAccess (E1/E3), Theme Builder
|
||||
* layouts via ThemeBuilderAccess (Etappe 3b; hidden ones answer like a missing ID, P12), every other
|
||||
* entry with its rights and status via PostGuard (spec §4.5), then the block tree. Divi 4
|
||||
* shortcode content and unbalanced markup are refused with a hint – spec §3.4: Divi 4 content
|
||||
* is kept, never edited.
|
||||
@@ -31,7 +34,8 @@ final class DiviPageLoader
|
||||
public function __construct(
|
||||
private ContentSchema $schema,
|
||||
private Parser $parser = new Parser(),
|
||||
private ?LibraryAccess $library = null
|
||||
private ?LibraryAccess $library = null,
|
||||
private ?ThemeBuilderAccess $themeBuilder = null
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -50,9 +54,10 @@ final class DiviPageLoader
|
||||
/** Readers pass $forWrite = false (trashed entries may be read, like lit-content-get). */
|
||||
public function load(mixed $postId, bool $forWrite): DiviPage|WP_Error
|
||||
{
|
||||
// Library entries (E1): with a library access, for reading and writing.
|
||||
// Library entries (E1) and Theme Builder layouts (Etappe 3b) through their access, everything else PostGuard.
|
||||
$item = $this->library?->item($postId, $forWrite);
|
||||
$post = $item ?? PostGuard::editable($postId, $this->schema, 'post_id', ! $forWrite);
|
||||
$layout = $item === null ? $this->themeBuilder?->layout($postId, $forWrite) : null;
|
||||
$post = $item ?? $layout ?? PostGuard::editable($postId, $this->schema, 'post_id', ! $forWrite);
|
||||
if ($post instanceof WP_Error) {
|
||||
return $post;
|
||||
}
|
||||
@@ -84,7 +89,9 @@ final class DiviPageLoader
|
||||
);
|
||||
}
|
||||
|
||||
return new DiviPage($post, $document, NodeIndex::build($document), $item instanceof WP_Post);
|
||||
$area = $layout instanceof WP_Post ? DiviThemeBuilder::areaOf((string) $layout->post_type) : null;
|
||||
|
||||
return new DiviPage($post, $document, NodeIndex::build($document), $item instanceof WP_Post, $area);
|
||||
}
|
||||
|
||||
/** The entry loaded for writing and checked by writable() – the refusal of either step. */
|
||||
@@ -99,14 +106,16 @@ final class DiviPageLoader
|
||||
}
|
||||
|
||||
/**
|
||||
* Additional checks for writing: the type must use the Divi builder (library entries always do),
|
||||
* Additional checks for writing: the type must use the Divi builder (library entries and Theme Builder
|
||||
* layouts always do),
|
||||
* the content must be a Divi 5 layout (or empty) and saving must not publish a missed schedule
|
||||
* (spec §2).
|
||||
*/
|
||||
public function writable(DiviPage $page): ?WP_Error
|
||||
{
|
||||
$post = $page->post;
|
||||
if (! $page->isLibraryItem() && ! $this->schema->diviEnabled((string) $post->post_type)) {
|
||||
$builderPost = $page->isLibraryItem() || $page->isThemeBuilderLayout();
|
||||
if (! $builderPost && ! $this->schema->diviEnabled((string) $post->post_type)) {
|
||||
return Errors::unsupported(
|
||||
sprintf('Für den Inhaltstyp "%s" ist der Divi-Builder nicht aktiviert.', $post->post_type),
|
||||
'In Divi → Theme-Optionen → Builder den Builder für diesen Inhaltstyp aktivieren (Administrator).'
|
||||
|
||||
Reference in New Issue
Block a user