refactor: Divi pages adapter replaces DiviFlags
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -20,7 +20,7 @@ defined('ABSPATH') || exit;
|
|||||||
/**
|
/**
|
||||||
* Divi short form for lit/content-create (spec §6.2): the sections become a Divi 5 layout in
|
* Divi short form for lit/content-create (spec §6.2): the sections become a Divi 5 layout in
|
||||||
* exactly one divi/placeholder – inserted by TreeEditor like the first section of an empty page
|
* exactly one divi/placeholder – inserted by TreeEditor like the first section of an empty page
|
||||||
* (ruling S9) – stored through DiviSaver's kses window, with the builder flags (DiviFlags, S11).
|
* (ruling S9) – stored through DiviSaver's kses window, with the builder flags (DiviPages, S11).
|
||||||
*
|
*
|
||||||
* Allow map (ruling S22) for an entry that does not exist yet: check() runs before the insert
|
* Allow map (ruling S22) for an entry that does not exist yet: check() runs before the insert
|
||||||
* with the composition bound to post ID 0 – Divi's own registry for "no entry" (get_options(0)
|
* with the composition bound to post ID 0 – Divi's own registry for "no entry" (get_options(0)
|
||||||
|
|||||||
@@ -1,40 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace LIT\MCP\Integrations\Divi\Pages;
|
|
||||||
|
|
||||||
use RuntimeException;
|
|
||||||
|
|
||||||
defined('ABSPATH') || exit;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Marks an entry as a Divi 5 builder layout, like the Visual Builder's own save does
|
|
||||||
* (Divi 5.2.1 SyncToServerController.php:382-387: _et_pb_use_divi_5 = "on", legacy
|
|
||||||
* _et_pb_use_builder = "on", and _et_pb_show_page_creation = "off" so the builder does not show
|
|
||||||
* its page creation flow on the first open). Ruling S11: update_post_meta() returns false for
|
|
||||||
* an unchanged value too, so success is checked by reading the flags back. Used by DiviSaver
|
|
||||||
* (inside FollowUp) and the Divi content creation.
|
|
||||||
*/
|
|
||||||
final class DiviFlags
|
|
||||||
{
|
|
||||||
public const FLAGS = [
|
|
||||||
'_et_pb_use_divi_5' => 'on',
|
|
||||||
'_et_pb_use_builder' => 'on',
|
|
||||||
'_et_pb_show_page_creation' => 'off',
|
|
||||||
];
|
|
||||||
|
|
||||||
/** @throws RuntimeException When a flag does not read back as set. */
|
|
||||||
public static function set(int $postId): void
|
|
||||||
{
|
|
||||||
foreach (self::FLAGS as $key => $value) {
|
|
||||||
update_post_meta($postId, $key, $value);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (self::FLAGS as $key => $value) {
|
|
||||||
if (get_post_meta($postId, $key, true) !== $value) {
|
|
||||||
throw new RuntimeException(sprintf('Divi flag %s of post %d is not "%s".', $key, $postId, $value));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -74,6 +74,6 @@ final class DiviPage
|
|||||||
/** The entry opened in the Divi Visual Builder – the edit_url of every Divi write (review I-1). */
|
/** The entry opened in the Divi Visual Builder – the edit_url of every Divi write (review I-1). */
|
||||||
public static function builderUrl(WP_Post|int $post): string
|
public static function builderUrl(WP_Post|int $post): string
|
||||||
{
|
{
|
||||||
return (string) add_query_arg('et_fb', '1', (string) get_permalink($post));
|
return DiviPages::builderUrl($post);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,98 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace LIT\MCP\Integrations\Divi\Pages;
|
||||||
|
|
||||||
|
use LIT\MCP\Integrations\Divi\Release\Call;
|
||||||
|
use LIT\MCP\Integrations\Divi\Release\DiviAdapter;
|
||||||
|
use LIT\MCP\Integrations\Divi\Release\Manifest;
|
||||||
|
use LIT\MCP\Integrations\Divi\Release\Mirror;
|
||||||
|
use RuntimeException;
|
||||||
|
use WP_Post;
|
||||||
|
|
||||||
|
defined('ABSPATH') || exit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adapter "Seiten" (spec §3): the Divi 5 builder flags of an entry as the Visual Builder's own save sets them
|
||||||
|
* (mirror vb-sync-flags: _et_pb_use_divi_5 = "on", legacy _et_pb_use_builder = "on", _et_pb_show_page_creation =
|
||||||
|
* "off" so the builder skips its page creation flow), whether an entry uses the builder, its builder URL, the
|
||||||
|
* static CSS of one page and Divi's list of linkable post types. Ruling S11: update_post_meta() returns false for an
|
||||||
|
* unchanged value too, so setFlags() checks by reading the flags back. Used by DiviSaver, the Divi content creation,
|
||||||
|
* WpLinkTargets and PostPresenter.
|
||||||
|
*/
|
||||||
|
final class DiviPages implements DiviAdapter
|
||||||
|
{
|
||||||
|
public const FLAGS = [
|
||||||
|
'_et_pb_use_divi_5' => 'on',
|
||||||
|
'_et_pb_use_builder' => 'on',
|
||||||
|
'_et_pb_show_page_creation' => 'off',
|
||||||
|
];
|
||||||
|
|
||||||
|
public static function manifest(): Manifest
|
||||||
|
{
|
||||||
|
return new Manifest(
|
||||||
|
Manifest::PAGES,
|
||||||
|
calls: [
|
||||||
|
new Call('ET_Core_PageResource::remove_static_resources', 3),
|
||||||
|
new Call('et_builder_get_public_post_types', 0),
|
||||||
|
],
|
||||||
|
keys: ['_et_pb_use_divi_5', '_et_pb_use_builder', '_et_pb_show_page_creation', 'et_fb'],
|
||||||
|
mirrors: [
|
||||||
|
new Mirror(
|
||||||
|
'vb-sync-flags',
|
||||||
|
'includes/builder-5/server/VisualBuilder/REST/SyncToServer/SyncToServerController.php',
|
||||||
|
'update',
|
||||||
|
'SyncToServerController',
|
||||||
|
'Builder-Kennzeichen einer Seite (_et_pb_use_divi_5, _et_pb_use_builder, _et_pb_show_page_creation)'
|
||||||
|
),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @throws RuntimeException When a flag does not read back as set. */
|
||||||
|
public static function setFlags(int $postId): void
|
||||||
|
{
|
||||||
|
foreach (self::FLAGS as $key => $value) {
|
||||||
|
update_post_meta($postId, $key, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (self::FLAGS as $key => $value) {
|
||||||
|
if (get_post_meta($postId, $key, true) !== $value) {
|
||||||
|
throw new RuntimeException(sprintf('Divi flag %s of post %d is not "%s".', $key, $postId, $value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether Divi's builder flag marks $postId as a builder layout. */
|
||||||
|
public static function usesBuilder(int $postId): bool
|
||||||
|
{
|
||||||
|
return get_post_meta($postId, '_et_pb_use_builder', true) === 'on';
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The entry opened in the Divi Visual Builder: its permalink with et_fb=1. */
|
||||||
|
public static function builderUrl(WP_Post|int $post): string
|
||||||
|
{
|
||||||
|
return (string) add_query_arg('et_fb', '1', (string) get_permalink($post));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Removes the static CSS files Divi generated for $postId (spec §5.6 step 5). */
|
||||||
|
public static function clearPageCss(int $postId): void
|
||||||
|
{
|
||||||
|
if (class_exists('ET_Core_PageResource')) {
|
||||||
|
\ET_Core_PageResource::remove_static_resources($postId, 'all', true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether Divi offers a post_link_url_<type> option for $postType. Fail closed: without Divi's list, none. */
|
||||||
|
public static function isLinkable(string $postType): bool
|
||||||
|
{
|
||||||
|
if (! function_exists('et_builder_get_public_post_types')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$types = et_builder_get_public_post_types();
|
||||||
|
|
||||||
|
return is_array($types) && array_key_exists($postType, $types);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,7 +20,7 @@ defined('ABSPATH') || exit;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Save pipeline of spec §5.6, steps 3–5: restore point and wp_update_post() with wp_slash() (the
|
* Save pipeline of spec §5.6, steps 3–5: restore point and wp_update_post() with wp_slash() (the
|
||||||
* status stays), Divi 5 flags (DiviFlags), Divi's static CSS cache. A failure after saving is
|
* status stays), Divi 5 flags and the page's static CSS (DiviPages). A failure after saving is
|
||||||
* only a warning (FollowUp); a filter that changed the stored content is reported as well.
|
* only a warning (FollowUp); a filter that changed the stored content is reported as well.
|
||||||
*
|
*
|
||||||
* kses (spec D7): for users without unfiltered_html WordPress' kses would run
|
* kses (spec D7): for users without unfiltered_html WordPress' kses would run
|
||||||
@@ -45,7 +45,7 @@ defined('ABSPATH') || exit;
|
|||||||
* for its single wp_update_post().
|
* for its single wp_update_post().
|
||||||
*
|
*
|
||||||
* Divi's own save filters are NOT kses and are never removed (ruling S7, defense in depth):
|
* Divi's own save filters are NOT kses and are never removed (ruling S7, defense in depth):
|
||||||
* Security::initialize() (Divi 5.2.1 Security.php:74-81) registers on wp_insert_post_data
|
* Security::initialize() (Divi's Security.php) registers on wp_insert_post_data
|
||||||
* AttributeSecurity (priority 5, always), HtmlSecurity (priority 6, by capability) and
|
* AttributeSecurity (priority 5, always), HtmlSecurity (priority 6, by capability) and
|
||||||
* DynamicContentFixes (priority 10: strips enable_html for users without unfiltered_html). The first
|
* DynamicContentFixes (priority 10: strips enable_html for users without unfiltered_html). The first
|
||||||
* two re-serialize the whole page when it holds custom attributes or htmlBefore/htmlAfter/elementType, so on such
|
* two re-serialize the whole page when it holds custom attributes or htmlBefore/htmlAfter/elementType, so on such
|
||||||
@@ -98,7 +98,7 @@ class DiviSaver
|
|||||||
$warnings = [];
|
$warnings = [];
|
||||||
if ($scope->setsFlags()) {
|
if ($scope->setsFlags()) {
|
||||||
FollowUp::run(
|
FollowUp::run(
|
||||||
static fn () => DiviFlags::set($postId),
|
static fn () => DiviPages::setFlags($postId),
|
||||||
'divi builder flags',
|
'divi builder flags',
|
||||||
'Die Divi-Kennzeichen der Seite konnten nicht gesetzt werden; der Inhalt ist gespeichert – die Seite '
|
'Die Divi-Kennzeichen der Seite konnten nicht gesetzt werden; der Inhalt ist gespeichert – die Seite '
|
||||||
. 'einmal im Divi-Builder öffnen und speichern.',
|
. 'einmal im Divi-Builder öffnen und speichern.',
|
||||||
@@ -107,9 +107,7 @@ class DiviSaver
|
|||||||
}
|
}
|
||||||
FollowUp::run(
|
FollowUp::run(
|
||||||
static function () use ($postId, $scope): void {
|
static function () use ($postId, $scope): void {
|
||||||
if (class_exists('ET_Core_PageResource')) {
|
DiviPages::clearPageCss($postId);
|
||||||
\ET_Core_PageResource::remove_static_resources($postId, 'all', true);
|
|
||||||
}
|
|
||||||
// A global library entry is part of every page that shows it (spec §5.6 step 5).
|
// A global library entry is part of every page that shows it (spec §5.6 step 5).
|
||||||
if ($scope->clearsSiteCss()) {
|
if ($scope->clearsSiteCss()) {
|
||||||
DiviThemeBuilder::clearSiteCaches();
|
DiviThemeBuilder::clearSiteCaches();
|
||||||
@@ -149,7 +147,7 @@ class DiviSaver
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($scope->setsFlags()) {
|
if ($scope->setsFlags()) {
|
||||||
DiviFlags::set($postId);
|
DiviPages::setFlags($postId);
|
||||||
}
|
}
|
||||||
|
|
||||||
$stored = get_post($postId);
|
$stored = get_post($postId);
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ namespace LIT\MCP\Integrations\Divi\Pages;
|
|||||||
|
|
||||||
use Closure;
|
use Closure;
|
||||||
use LIT\MCP\Integrations\Divi\Compose\LinkTargets;
|
use LIT\MCP\Integrations\Divi\Compose\LinkTargets;
|
||||||
|
use LIT\MCP\Integrations\Divi\Library\DiviLibraryStore;
|
||||||
use WP_Post;
|
use WP_Post;
|
||||||
|
|
||||||
defined('ABSPATH') || exit;
|
defined('ABSPATH') || exit;
|
||||||
@@ -22,18 +23,19 @@ final class WpLinkTargets implements LinkTargets
|
|||||||
private const DEAD = ['trash', 'auto-draft', 'inherit'];
|
private const DEAD = ['trash', 'auto-draft', 'inherit'];
|
||||||
|
|
||||||
/** Never link targets, whatever Divi lists: attachments and the Divi Library (ruling Q14). */
|
/** Never link targets, whatever Divi lists: attachments and the Divi Library (ruling Q14). */
|
||||||
private const NEVER = ['attachment', 'et_pb_layout'];
|
private const NEVER = ['attachment', DiviLibraryStore::POST_TYPE];
|
||||||
|
|
||||||
/** @var Closure(string): bool */
|
/** @var Closure(string): bool */
|
||||||
private Closure $linkable;
|
private Closure $linkable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param (Closure(string): bool)|null $linkable Whether Divi offers post_link_url_<type> (tests);
|
* @param (Closure(string): bool)|null $linkable Whether Divi offers post_link_url_<type> (tests);
|
||||||
* null = Divi's et_builder_get_public_post_types(), the list its link option uses.
|
* null = DiviPages::isLinkable() (Divi's et_builder_get_public_post_types(), the list its
|
||||||
|
* link option uses).
|
||||||
*/
|
*/
|
||||||
public function __construct(?Closure $linkable = null)
|
public function __construct(?Closure $linkable = null)
|
||||||
{
|
{
|
||||||
$this->linkable = $linkable ?? self::diviLinkable(...);
|
$this->linkable = $linkable ?? DiviPages::isLinkable(...);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function postTypeOf(int $id): ?string
|
public function postTypeOf(int $id): ?string
|
||||||
@@ -50,16 +52,4 @@ final class WpLinkTargets implements LinkTargets
|
|||||||
|
|
||||||
return current_user_can('read_post', $id) ? $type : null;
|
return current_user_can('read_post', $id) ? $type : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Fail closed: without Divi's list no type has a link option. */
|
|
||||||
private static function diviLinkable(string $type): bool
|
|
||||||
{
|
|
||||||
if (! function_exists('et_builder_get_public_post_types')) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$types = et_builder_get_public_post_types();
|
|
||||||
|
|
||||||
return is_array($types) && array_key_exists($type, $types);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace LIT\MCP\Integrations\Divi\Release;
|
namespace LIT\MCP\Integrations\Divi\Release;
|
||||||
|
|
||||||
|
use LIT\MCP\Integrations\Divi\Pages\DiviPages;
|
||||||
use LIT\MCP\Integrations\Divi\Pages\DynamicContentMap;
|
use LIT\MCP\Integrations\Divi\Pages\DynamicContentMap;
|
||||||
use LIT\MCP\Integrations\Divi\Schema\DiviModules;
|
use LIT\MCP\Integrations\Divi\Schema\DiviModules;
|
||||||
|
|
||||||
@@ -14,6 +15,7 @@ final class DiviAdapters
|
|||||||
{
|
{
|
||||||
/** @var list<class-string<DiviAdapter>> */
|
/** @var list<class-string<DiviAdapter>> */
|
||||||
public const CLASSES = [
|
public const CLASSES = [
|
||||||
|
DiviPages::class,
|
||||||
DiviModules::class,
|
DiviModules::class,
|
||||||
DynamicContentMap::class,
|
DynamicContentMap::class,
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ namespace LIT\MCP\Integrations\WordPress\Content;
|
|||||||
|
|
||||||
use LIT\MCP\Abilities\JsonMap;
|
use LIT\MCP\Abilities\JsonMap;
|
||||||
use LIT\MCP\Abilities\Rev;
|
use LIT\MCP\Abilities\Rev;
|
||||||
|
use LIT\MCP\Integrations\Divi\Pages\DiviPages;
|
||||||
use LIT\MCP\Integrations\Divi\Schema\DiviModules;
|
use LIT\MCP\Integrations\Divi\Schema\DiviModules;
|
||||||
use LIT\MCP\Integrations\WordPress\Schema\ContentSchema;
|
use LIT\MCP\Integrations\WordPress\Schema\ContentSchema;
|
||||||
use LIT\MCP\Integrations\WordPress\Schema\FieldDefinition;
|
use LIT\MCP\Integrations\WordPress\Schema\FieldDefinition;
|
||||||
@@ -95,7 +96,7 @@ class PostPresenter
|
|||||||
|
|
||||||
public static function usesDivi(WP_Post $post): bool
|
public static function usesDivi(WP_Post $post): bool
|
||||||
{
|
{
|
||||||
return get_post_meta((int) $post->ID, '_et_pb_use_builder', true) === 'on'
|
return DiviPages::usesBuilder((int) $post->ID)
|
||||||
|| str_contains((string) $post->post_content, '<!-- wp:divi/');
|
|| str_contains((string) $post->post_content, '<!-- wp:divi/');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ final class GlobalEditsTest extends TestCase
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testPlainLibraryItemIsSavedWithoutConfirmAndWithoutDiviFlags(): void
|
public function testPlainLibraryItemIsSavedWithoutConfirmAndWithoutPageFlags(): void
|
||||||
{
|
{
|
||||||
LibraryFixtures::given([LibraryFixtures::item(1057)]);
|
LibraryFixtures::given([LibraryFixtures::item(1057)]);
|
||||||
|
|
||||||
@@ -563,7 +563,7 @@ final class GlobalEditsTest extends TestCase
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Ruling P1: lit-divi-replace-text saves library entries through DiviWriter::commit(). */
|
/** Ruling P1: lit-divi-replace-text saves library entries through DiviWriter::commit(). */
|
||||||
public function testReplaceTextSavesAPlainLibraryItemWithoutDiviFlags(): void
|
public function testReplaceTextSavesAPlainLibraryItemWithoutPageFlags(): void
|
||||||
{
|
{
|
||||||
LibraryFixtures::given([LibraryFixtures::item(1057)]);
|
LibraryFixtures::given([LibraryFixtures::item(1057)]);
|
||||||
|
|
||||||
|
|||||||
@@ -1,58 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace LIT\MCP\Tests\Unit\Integrations\Divi\Pages;
|
|
||||||
|
|
||||||
use Brain\Monkey\Functions;
|
|
||||||
use LIT\MCP\Integrations\Divi\Pages\DiviFlags;
|
|
||||||
use LIT\MCP\Tests\Unit\TestCase;
|
|
||||||
use RuntimeException;
|
|
||||||
|
|
||||||
final class DiviFlagsTest extends TestCase
|
|
||||||
{
|
|
||||||
public function testSetsBothFlagsAndAcceptsAnUnchangedValue(): void
|
|
||||||
{
|
|
||||||
$written = [];
|
|
||||||
// update_post_meta() is false when the value is already "on" – no failure (ruling S11).
|
|
||||||
Functions\when('update_post_meta')->alias(static function (int $id, string $key, string $value) use (&$written): bool {
|
|
||||||
$written[] = "$id:$key=$value";
|
|
||||||
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
Functions\when('get_post_meta')->alias(
|
|
||||||
static fn (int $id, string $key): string => $key === '_et_pb_show_page_creation' ? 'off' : 'on'
|
|
||||||
);
|
|
||||||
|
|
||||||
DiviFlags::set(7);
|
|
||||||
|
|
||||||
// Like Divi's own save (SyncToServerController.php:382-387), incl. the page creation flow flag.
|
|
||||||
self::assertSame(
|
|
||||||
['7:_et_pb_use_divi_5=on', '7:_et_pb_use_builder=on', '7:_et_pb_show_page_creation=off'],
|
|
||||||
$written
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testThrowsWhenAFlagDoesNotReadBack(): void
|
|
||||||
{
|
|
||||||
Functions\when('update_post_meta')->justReturn(true);
|
|
||||||
Functions\when('get_post_meta')->alias(
|
|
||||||
static fn (int $id, string $key): string => $key === '_et_pb_use_builder' ? 'off' : 'on'
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->expectException(RuntimeException::class);
|
|
||||||
$this->expectExceptionMessage('_et_pb_use_builder');
|
|
||||||
DiviFlags::set(7);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testThrowsWhenThePageCreationFlagDoesNotReadBack(): void
|
|
||||||
{
|
|
||||||
Functions\when('update_post_meta')->justReturn(true);
|
|
||||||
Functions\when('get_post_meta')->justReturn('on');
|
|
||||||
|
|
||||||
$this->expectException(RuntimeException::class);
|
|
||||||
$this->expectExceptionMessage('_et_pb_show_page_creation');
|
|
||||||
DiviFlags::set(7);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace LIT\MCP\Tests\Unit\Integrations\Divi\Pages;
|
||||||
|
|
||||||
|
use Brain\Monkey\Functions;
|
||||||
|
use LIT\MCP\Integrations\Divi\Pages\DiviPages;
|
||||||
|
use LIT\MCP\Integrations\Divi\Release\DiviAdapters;
|
||||||
|
use LIT\MCP\Integrations\Divi\Release\Manifest;
|
||||||
|
use LIT\MCP\Tests\Unit\TestCase;
|
||||||
|
use RuntimeException;
|
||||||
|
use WP_Post;
|
||||||
|
|
||||||
|
final class DiviPagesTest extends TestCase
|
||||||
|
{
|
||||||
|
public function testSetsBothFlagsAndAcceptsAnUnchangedValue(): void
|
||||||
|
{
|
||||||
|
$written = [];
|
||||||
|
// update_post_meta() is false when the value is already "on" – no failure (ruling S11).
|
||||||
|
Functions\when('update_post_meta')->alias(static function (int $id, string $key, string $value) use (&$written): bool {
|
||||||
|
$written[] = "$id:$key=$value";
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
Functions\when('get_post_meta')->alias(
|
||||||
|
static fn (int $id, string $key): string => $key === '_et_pb_show_page_creation' ? 'off' : 'on'
|
||||||
|
);
|
||||||
|
|
||||||
|
DiviPages::setFlags(7);
|
||||||
|
|
||||||
|
// Like Divi's own save (SyncToServerController::update, Mirror vb-sync-flags), incl. the page creation flag.
|
||||||
|
self::assertSame(
|
||||||
|
['7:_et_pb_use_divi_5=on', '7:_et_pb_use_builder=on', '7:_et_pb_show_page_creation=off'],
|
||||||
|
$written
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testThrowsWhenAFlagDoesNotReadBack(): void
|
||||||
|
{
|
||||||
|
Functions\when('update_post_meta')->justReturn(true);
|
||||||
|
Functions\when('get_post_meta')->alias(
|
||||||
|
static fn (int $id, string $key): string => $key === '_et_pb_use_builder' ? 'off' : 'on'
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->expectException(RuntimeException::class);
|
||||||
|
$this->expectExceptionMessage('_et_pb_use_builder');
|
||||||
|
DiviPages::setFlags(7);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testThrowsWhenThePageCreationFlagDoesNotReadBack(): void
|
||||||
|
{
|
||||||
|
Functions\when('update_post_meta')->justReturn(true);
|
||||||
|
Functions\when('get_post_meta')->justReturn('on');
|
||||||
|
|
||||||
|
$this->expectException(RuntimeException::class);
|
||||||
|
$this->expectExceptionMessage('_et_pb_show_page_creation');
|
||||||
|
DiviPages::setFlags(7);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testIsTheRegisteredPagesAdapterWithTheFlagMirror(): void
|
||||||
|
{
|
||||||
|
$manifest = DiviPages::manifest();
|
||||||
|
|
||||||
|
self::assertContains(DiviPages::class, DiviAdapters::CLASSES);
|
||||||
|
self::assertSame(Manifest::PAGES, $manifest->area);
|
||||||
|
self::assertSame(['vb-sync-flags'], array_map(static fn ($mirror): string => $mirror->id, $manifest->mirrors));
|
||||||
|
self::assertSame('SyncToServerController::update()', $manifest->mirrors[0]->label());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testUsesBuilderReadsDivisFlag(): void
|
||||||
|
{
|
||||||
|
Functions\when('get_post_meta')->alias(
|
||||||
|
static fn (int $id, string $key): string => $id === 7 && $key === '_et_pb_use_builder' ? 'on' : ''
|
||||||
|
);
|
||||||
|
|
||||||
|
self::assertTrue(DiviPages::usesBuilder(7));
|
||||||
|
self::assertFalse(DiviPages::usesBuilder(8));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testBuilderUrlOpensTheVisualBuilder(): void
|
||||||
|
{
|
||||||
|
Functions\when('get_permalink')->justReturn('https://k.de/start/');
|
||||||
|
Functions\when('add_query_arg')->alias(
|
||||||
|
static fn (string $key, string $value, string $url): string => $url . '?' . $key . '=' . $value
|
||||||
|
);
|
||||||
|
|
||||||
|
self::assertSame('https://k.de/start/?et_fb=1', DiviPages::builderUrl(new WP_Post(['ID' => 7])));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testClearPageCssRemovesThePagesStaticFiles(): void
|
||||||
|
{
|
||||||
|
\ET_Core_PageResource::$removed = [];
|
||||||
|
|
||||||
|
DiviPages::clearPageCss(7);
|
||||||
|
|
||||||
|
self::assertSame([[7, 'all', true]], \ET_Core_PageResource::$removed);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Own process (Brain Monkey's FunctionStub eval's a real global function the first time a name is
|
||||||
|
* stubbed – function_exists() would report it as permanently defined for the rest of the run
|
||||||
|
* otherwise, breaking WpLinkTargetsTest's "without Divi" case).
|
||||||
|
*
|
||||||
|
* @runInSeparateProcess
|
||||||
|
*/
|
||||||
|
public function testIsLinkableFollowsDivisPublicPostTypes(): void
|
||||||
|
{
|
||||||
|
Functions\when('et_builder_get_public_post_types')->justReturn(['page' => 'Seiten', 'post' => 'Beiträge']);
|
||||||
|
|
||||||
|
self::assertTrue(DiviPages::isLinkable('page'));
|
||||||
|
self::assertFalse(DiviPages::isLinkable('product'));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -62,7 +62,7 @@ final class DiviSaverTest extends TestCase
|
|||||||
parent::tearDown();
|
parent::tearDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testSavesWithoutKsesForFilteredUsersAndSetsDiviFlags(): void
|
public function testSavesWithoutKsesForFilteredUsersAndSetsThePageFlags(): void
|
||||||
{
|
{
|
||||||
Functions\when('current_user_can')->justReturn(false);
|
Functions\when('current_user_can')->justReturn(false);
|
||||||
Functions\when('has_filter')->justReturn(10);
|
Functions\when('has_filter')->justReturn(10);
|
||||||
@@ -269,7 +269,7 @@ final class DiviSaverTest extends TestCase
|
|||||||
(new DiviSaver())->saveNew(42, 'NEU');
|
(new DiviSaver())->saveNew(42, 'NEU');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testLibraryItemsGetNoDiviFlagsAndGlobalOnesClearEveryPage(): void
|
public function testLibraryItemsGetNoPageFlagsAndGlobalOnesClearEveryPage(): void
|
||||||
{
|
{
|
||||||
\ET_Core_PageResource::$removed = [];
|
\ET_Core_PageResource::$removed = [];
|
||||||
Functions\when('current_user_can')->justReturn(true);
|
Functions\when('current_user_can')->justReturn(true);
|
||||||
|
|||||||
@@ -30,13 +30,8 @@ final class DiviBoundaryTest extends TestCase
|
|||||||
'Integrations/Divi/Library/DiviRoles.php',
|
'Integrations/Divi/Library/DiviRoles.php',
|
||||||
'Integrations/Divi/Library/LibraryItemSpec.php',
|
'Integrations/Divi/Library/LibraryItemSpec.php',
|
||||||
'Integrations/Divi/Library/NewLibraryEntry.php',
|
'Integrations/Divi/Library/NewLibraryEntry.php',
|
||||||
'Integrations/Divi/Pages/DiviFlags.php',
|
|
||||||
'Integrations/Divi/Pages/DiviPage.php',
|
|
||||||
'Integrations/Divi/Pages/DiviSaver.php',
|
|
||||||
'Integrations/Divi/Pages/WpLinkTargets.php',
|
|
||||||
'Integrations/Divi/ThemeBuilder/DiviThemeBuilder.php',
|
'Integrations/Divi/ThemeBuilder/DiviThemeBuilder.php',
|
||||||
'Integrations/Media/MediaUsageFinder.php',
|
'Integrations/Media/MediaUsageFinder.php',
|
||||||
'Integrations/WordPress/Content/PostPresenter.php',
|
|
||||||
];
|
];
|
||||||
|
|
||||||
public function testOnlyAdaptersTouchDivi(): void
|
public function testOnlyAdaptersTouchDivi(): void
|
||||||
|
|||||||
Reference in New Issue
Block a user