feat: Divi adapters for roles and library with a live compatibility check

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-27 00:51:09 +02:00
co-authored by Claude Opus 5.5
parent b389f983de
commit ce1ad7c6c3
10 changed files with 491 additions and 5 deletions
@@ -0,0 +1,56 @@
<?php
declare(strict_types=1);
namespace LIT\MCP\Integrations\Divi\Library;
use Closure;
use LIT\MCP\Abilities\Errors;
use WP_Error;
defined('ABSPATH') || exit;
/**
* Adapter for Divi's role editor (E3, E15): et_pb_is_allowed() (Divi 5.2.1 builder/core.php:1128)
* answers for the current user's role, "dangerous" options (theme_builder,
* read_dynamic_content_custom_fields) default to off for every role but administrator. When
* Divi no longer has the function, nothing is allowed – DiviCompatibility reports it.
* Not final so tests can pass a check.
*/
class DiviRoles
{
private const LABELS = [
'divi_library' => 'Divi-Bibliothek',
'save_library' => 'In der Bibliothek speichern',
'add_library' => 'Aus der Bibliothek hinzufügen',
'edit_global_library' => 'Globale Bibliothekselemente bearbeiten',
'read_dynamic_content_custom_fields' => 'Dynamic Content: benutzerdefinierte Felder lesen',
];
/** @param (Closure(string): bool)|null $check Test seam; null = Divi's et_pb_is_allowed(). */
public function __construct(private ?Closure $check = null)
{
}
public function allows(string $capability): bool
{
if ($this->check !== null) {
return ($this->check)($capability);
}
return function_exists('et_pb_is_allowed') && (bool) et_pb_is_allowed($capability);
}
/** Null when the role allows $capability, else a forbidden error naming the option. */
public function refusal(string $capability): ?WP_Error
{
if ($this->allows($capability)) {
return null;
}
return Errors::forbidden(
sprintf('Die Divi-Rolle dieses Kontos erlaubt „%s“ nicht.', self::LABELS[$capability] ?? $capability),
'Einen Administrator bitten, das Recht unter Divi → Rollen-Editor freizugeben.'
);
}
}