fix(security): no direct HTTP access to plugin PHP files (audit L2, cheap part)
Every file under src/ exits outside WordPress (defined('ABSPATH') ||
exit; after the use block, so a direct request no longer prints a fatal
error with the server path); divi-convert-fixture.php gets the WP_CLI
guard the other integration scripts have. A unit test keeps both true;
PSR1 side-effects warning excluded for the guard.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7
This commit is contained in:
@@ -6,6 +6,8 @@ namespace LIT\MCP\Abilities;
|
||||
|
||||
use WP_Error;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* One capability of the MCP server, registered with the WordPress Abilities API.
|
||||
*/
|
||||
|
||||
@@ -11,6 +11,8 @@ use LIT\MCP\Server\RequestContext;
|
||||
use Throwable;
|
||||
use WP_Error;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Registers all abilities of available integrations with the Abilities API and
|
||||
* wraps them with the role gate and neutral error handling.
|
||||
|
||||
@@ -4,6 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace LIT\MCP\Abilities;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* The MCP annotations of an ability (Ability::annotations()), in three presets. "readonly"
|
||||
* drives the "nur lesen" group switch (ExposurePolicy::disabledByReadonly()) and, with
|
||||
|
||||
@@ -6,6 +6,8 @@ namespace LIT\MCP\Abilities;
|
||||
|
||||
use WP_Error;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Opaque offset cursor for list tools (spec §8.1, §11.3).
|
||||
*/
|
||||
|
||||
@@ -6,6 +6,8 @@ namespace LIT\MCP\Abilities;
|
||||
|
||||
use WP_Error;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Factory for the error objects abilities return.
|
||||
*
|
||||
|
||||
@@ -4,6 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace LIT\MCP\Abilities;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Decides per ability whether it is a direct MCP tool, only reachable through the
|
||||
* adapter's meta-tools, or disabled (spec §4.3). Ability::isDirect() is the default.
|
||||
|
||||
@@ -7,6 +7,8 @@ namespace LIT\MCP\Abilities;
|
||||
use LIT\MCP\Log;
|
||||
use Throwable;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Runs a step after a write has already succeeded (listeners, change log): a failure
|
||||
* there must not turn the saved change into an error. It is logged and reported as warning.
|
||||
|
||||
@@ -6,6 +6,8 @@ namespace LIT\MCP\Abilities;
|
||||
|
||||
use stdClass;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* PHP encodes an empty array as JSON [] – for schema type "object" the client
|
||||
* must see {}. WordPress' output validation accepts stdClass for objects.
|
||||
|
||||
@@ -6,6 +6,8 @@ namespace LIT\MCP\Abilities;
|
||||
|
||||
use WP_Post;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Short hash used as optimistic-lock handle ("rev", spec §5.3).
|
||||
*/
|
||||
|
||||
@@ -6,6 +6,8 @@ namespace LIT\MCP\Abilities;
|
||||
|
||||
use Throwable;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Runs the undo steps of a failed write. Every step runs, even after an earlier one failed;
|
||||
* a step fails by throwing. The caller turns the collected messages into the log detail and
|
||||
|
||||
@@ -4,6 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace LIT\MCP\Abilities;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Small text helper shared by every summary that must stay bounded in size (outlines, node
|
||||
* summaries, the rendered-page excerpt): extracts are a fixed-size preview, never an unbounded
|
||||
|
||||
@@ -6,6 +6,8 @@ namespace LIT\MCP\Abilities;
|
||||
|
||||
use InvalidArgumentException;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Uniform success result of every writing ability (spec §8.1).
|
||||
* The adapter returns it as structuredContent plus JSON text.
|
||||
|
||||
@@ -8,6 +8,8 @@ use RuntimeException;
|
||||
use Throwable;
|
||||
use WP_Error;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Thrown by write paths when saving failed after something may already have been
|
||||
* written. getMessage() is the internal detail for the PHP error log; $reason is the
|
||||
|
||||
@@ -6,6 +6,8 @@ namespace LIT\MCP;
|
||||
|
||||
use WP_User;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Role gate: only users whose role is allowed get the lit_mcp_use capability.
|
||||
*
|
||||
|
||||
@@ -6,6 +6,8 @@ namespace LIT\MCP\Admin;
|
||||
|
||||
use LIT\MCP\Access;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Tab "Zugriff": roles allowed to use LIT MCP and the active OAuth connections
|
||||
* with revocation (spec §8.4).
|
||||
|
||||
@@ -4,6 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace LIT\MCP\Admin;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Admin notices for administrators (Etappe-0 follow-up d). Uses only cached check
|
||||
* results so no HTTP request runs on ordinary admin page loads.
|
||||
|
||||
@@ -4,6 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace LIT\MCP\Admin;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* The frame of an admin-post.php handler of the settings page: only administrators
|
||||
* (manage_options, else 403), and after the action a redirect back to the tab with a notice.
|
||||
|
||||
@@ -4,6 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace LIT\MCP\Admin;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* One tab of the settings page "Einstellungen → LIT MCP".
|
||||
*/
|
||||
|
||||
@@ -6,6 +6,8 @@ namespace LIT\MCP\Admin;
|
||||
|
||||
use WPMedia\MCP\OAuth\Auth\TokenEndpoint;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* OAuth connections created by mcp-oauth (v1.1.2, TokenEndpoint): for every grant it
|
||||
* creates one application password (name = client name, app_id = the CIMD client_id,
|
||||
|
||||
@@ -9,6 +9,8 @@ use WP\MCP\Core\McpAdapter;
|
||||
use WPMedia\MCP\OAuth\Auth\Discovery\HealthCheck;
|
||||
use WPMedia\MCP\OAuth\Context as OAuthContext;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Connection checks for the settings page, admin notices and Site Health.
|
||||
* Not final so notices and Site Health can be tested with a mock.
|
||||
|
||||
@@ -4,6 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace LIT\MCP\Admin;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
final class ConnectionTab implements AdminTab
|
||||
{
|
||||
public function __construct(private ConnectionStatus $status)
|
||||
|
||||
@@ -10,6 +10,8 @@ use WP_REST_Request;
|
||||
use WPMedia\MCP\OAuth\Auth\JWT;
|
||||
use WPMedia\MCP\OAuth\Auth\SecretManager;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Records when an OAuth connection was last used, for "Zuletzt genutzt" in the tab "Zugriff".
|
||||
*
|
||||
|
||||
@@ -6,6 +6,8 @@ namespace LIT\MCP\Admin;
|
||||
|
||||
use LIT\MCP\Limits;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Tab "Limits": upload/download size and log retention (spec §8.4). The snapshot count is
|
||||
* kept as a hidden field until the design system feature that uses it exists.
|
||||
|
||||
@@ -7,6 +7,8 @@ namespace LIT\MCP\Admin;
|
||||
use LIT\MCP\ChangeLog\ChangeLog;
|
||||
use WP_Post;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
// phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps -- method names are defined by WP_List_Table.
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,6 +7,8 @@ namespace LIT\MCP\Admin;
|
||||
use WP_Post;
|
||||
use WP_Term;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Human names for the objects in the change log ("Seite: Kontakt" instead of "page 834"),
|
||||
* linked to their edit screen where one exists and the current user may use it. prime()
|
||||
|
||||
@@ -8,6 +8,8 @@ use LIT\MCP\ChangeLog\ChangeLog;
|
||||
use LIT\MCP\Integrations\IntegrationRegistry;
|
||||
use LIT\MCP\Limits;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Tab "Protokoll": filterable list of change log entries, links to revisions, and
|
||||
* "Protokoll leeren" (spec §8.3). Page size and visible columns via WordPress'
|
||||
|
||||
@@ -4,6 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace LIT\MCP\Admin;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Settings page "Einstellungen → LIT MCP" with tabs (spec §8.4). Settings API, no JS framework.
|
||||
*/
|
||||
|
||||
@@ -4,6 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace LIT\MCP\Admin;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Site Health test for our MCP endpoint (401 + WWW-Authenticate without a token).
|
||||
* The discovery documents are covered by mcp-oauth's own Site Health test.
|
||||
|
||||
@@ -8,6 +8,8 @@ use LIT\MCP\Abilities\Ability;
|
||||
use LIT\MCP\Abilities\ExposurePolicy;
|
||||
use LIT\MCP\Integrations\IntegrationRegistry;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Tab "Tools": direct/indirect/disabled exposure per ability (spec §8.4), grouped by the
|
||||
* integration the ability comes from. Each group has its own mode (inherited by its tools)
|
||||
|
||||
@@ -8,6 +8,8 @@ use LIT\MCP\Abilities\FollowUp;
|
||||
use LIT\MCP\Log;
|
||||
use LIT\MCP\Server\RequestContext;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Change log table {prefix}lit_mcp_log (spec §8.3). Stores references only,
|
||||
* never content. Deliberately not final so abilities can be unit-tested with a mock.
|
||||
|
||||
@@ -6,6 +6,8 @@ namespace LIT\MCP\ChangeLog;
|
||||
|
||||
use LIT\MCP\Limits;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Daily WP-Cron job that removes log rows older than the configured retention.
|
||||
*/
|
||||
|
||||
@@ -4,6 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace LIT\MCP\ChangeLog;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Creates/updates the change log table via dbDelta. Runs on activation and –
|
||||
* because plugin updates never fire the activation hook – whenever the stored
|
||||
|
||||
@@ -4,6 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace LIT\MCP;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Checks that the libraries WP-LIT-MCP builds on are loadable.
|
||||
*/
|
||||
|
||||
@@ -4,6 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace LIT\MCP\Guides;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Guide topics: markdown files from one directory (the default), extended or overridden
|
||||
* by the site via the filter `lit_mcp_guides` (spec §9.2), which returns
|
||||
|
||||
@@ -8,6 +8,8 @@ use LIT\MCP\Abilities\ExposurePolicy;
|
||||
use LIT\MCP\Integrations\Integration;
|
||||
use LIT\MCP\Integrations\IntegrationRegistry;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Builds the short server instructions every MCP client loads on connect.
|
||||
* Keep this text short: it occupies context in every conversation.
|
||||
|
||||
@@ -8,6 +8,8 @@ use LIT\MCP\Access;
|
||||
use LIT\MCP\Guides\GuideRepository;
|
||||
use LIT\MCP\Integrations\Integration;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
final class CoreIntegration implements Integration
|
||||
{
|
||||
public function __construct(private string $guidesDirectory)
|
||||
|
||||
@@ -4,6 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace LIT\MCP\Integrations\Core;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Detects the themes/plugins LIT MCP integrates with.
|
||||
*/
|
||||
|
||||
@@ -10,6 +10,8 @@ use LIT\MCP\Abilities\Errors;
|
||||
use LIT\MCP\Guides\GuideRepository;
|
||||
use WP_Error;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
final class GuideAbility implements Ability
|
||||
{
|
||||
private const DEFAULT_TOPIC = 'overview';
|
||||
|
||||
@@ -9,6 +9,8 @@ use LIT\MCP\Abilities\Annotations;
|
||||
use LIT\MCP\Access;
|
||||
use WP_Error;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
final class SiteStatusAbility implements Ability
|
||||
{
|
||||
public function __construct(private EnvironmentProbe $probe, private Access $access)
|
||||
|
||||
@@ -7,6 +7,8 @@ namespace LIT\MCP\Integrations\Divi\BlockTree;
|
||||
use InvalidArgumentException;
|
||||
use stdClass;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Divi 5 attributes addressed by dotted paths ("title.decoration.font.font"). The value at
|
||||
* a path is a breakpoint map: {"desktop": {"value": …, "hover": …}, "phone": {"value": …}}.
|
||||
|
||||
@@ -8,6 +8,8 @@ use InvalidArgumentException;
|
||||
use LogicException;
|
||||
use stdClass;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* One block of the tree. A parsed block keeps its original opener/closer bytes; they are
|
||||
* dropped only when the block itself changes (setAttrs(), a void block getting children),
|
||||
|
||||
@@ -7,6 +7,8 @@ namespace LIT\MCP\Integrations\Divi\BlockTree;
|
||||
use InvalidArgumentException;
|
||||
use LogicException;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Ordered parts of a document or of a block's inner content: blocks and the raw text
|
||||
* between them (whitespace, freeform HTML, Divi 4 shortcodes). Keeping every byte of that
|
||||
|
||||
@@ -4,6 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace LIT\MCP\Integrations\Divi\BlockTree;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* The parsed post_content: top-level blocks and the text between them.
|
||||
*/
|
||||
|
||||
@@ -7,6 +7,8 @@ namespace LIT\MCP\Integrations\Divi\BlockTree;
|
||||
use JsonException;
|
||||
use stdClass;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* JSON of block attributes. PHP arrays cannot tell an empty JSON object from an empty list,
|
||||
* nor an object with the keys "0", "1", … from a list. decodeObject() therefore keeps such
|
||||
|
||||
@@ -6,6 +6,8 @@ namespace LIT\MCP\Integrations\Divi\BlockTree;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* post_content is no balanced block markup (closer without opener, unclosed block, PCRE
|
||||
* failure). The Divi tools then refuse to read or write the entry – nothing is guessed.
|
||||
|
||||
@@ -4,6 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace LIT\MCP\Integrations\Divi\BlockTree;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Path IDs of a Document (spec §5.3): s0, s0.r1, s0.r1.c0.m2. One letter per role –
|
||||
* s section, r row / row-inner, c column / column-inner, m module (incl. group and child
|
||||
|
||||
@@ -6,6 +6,8 @@ namespace LIT\MCP\Integrations\Divi\BlockTree;
|
||||
|
||||
use LIT\MCP\Abilities\Text;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Short human-readable facts about a node for the outline: admin label, first text,
|
||||
* preset IDs, column layout. Pure PHP.
|
||||
|
||||
@@ -4,6 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace LIT\MCP\Integrations\Divi\BlockTree;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* The page tree as rows and as compact text (lit-divi-outline, spec §5.3/§5.7; also the
|
||||
* "outline" of write results). Preset IDs are shown with their names when known.
|
||||
|
||||
@@ -4,6 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace LIT\MCP\Integrations\Divi\BlockTree;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Parses block markup into a Document without WordPress (spec §4.4, §5.2). Uses the
|
||||
* block-delimiter pattern of WP_Block_Parser, but records the exact bytes of every
|
||||
|
||||
@@ -4,6 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace LIT\MCP\Integrations\Divi\BlockTree;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Turns a Document back into block markup. Unchanged blocks reuse their original
|
||||
* delimiters; changed or new blocks get delimiters generated exactly like WordPress'
|
||||
|
||||
@@ -8,6 +8,8 @@ use InvalidArgumentException;
|
||||
use LIT\MCP\Integrations\Divi\BlockTree\AttrMap;
|
||||
use LIT\MCP\Integrations\Divi\Schema\ModuleCatalog;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Applies full-form changes (spec §5.4): attribute path => breakpoint map. Paths are checked
|
||||
* against the catalog (invalid_attr_path with suggestions), placeholders resolved, strings
|
||||
|
||||
@@ -8,6 +8,8 @@ use LIT\MCP\Integrations\Divi\BlockTree\AttrMap;
|
||||
use LIT\MCP\Integrations\Divi\BlockTree\Block;
|
||||
use LIT\MCP\Integrations\Divi\BlockTree\NodeIndex;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Column widths of Divi rows (pure, static): the "columns" input of new rows
|
||||
* ("1_3,2_3" → flexTypes, ruling S34) and the flexType checks on update (rulings S41, S43,
|
||||
|
||||
@@ -11,6 +11,8 @@ use LIT\MCP\Integrations\Divi\Design\DesignSystem;
|
||||
use LIT\MCP\Integrations\Divi\Schema\ModuleCatalog;
|
||||
use LIT\MCP\Integrations\Divi\Schema\ShortformMap;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Builds new Divi blocks from node descriptions (spec §5.4): short form, full form ("attrs")
|
||||
* or both; sections with rows ("columns": "1_3,2_3") and modules; parent modules with
|
||||
|
||||
@@ -4,6 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace LIT\MCP\Integrations\Divi\Compose;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Removes C0 control characters except tab, LF and CR, and DEL (rulings S32/S32a). Applied to
|
||||
* RAW values only, before the marker check and the sanitizer: the WordPress sanitizers keep them
|
||||
|
||||
@@ -7,6 +7,8 @@ namespace LIT\MCP\Integrations\Divi\Compose;
|
||||
use InvalidArgumentException;
|
||||
use LIT\MCP\Integrations\Divi\Design\DesignSystem;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* The allow list of content references ($variable({"type":"content",…})$) that VariableRef
|
||||
* delegates to: which names exist and how each of their settings is cleaned. Pure PHP.
|
||||
|
||||
@@ -4,6 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace LIT\MCP\Integrations\Divi\Compose;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* An independent second scan of an HTML fragment (ruling S45): a small state machine after the
|
||||
* HTML tokenizer rules, written separately from the regex tokenizer HtmlTokens so a mistake in
|
||||
|
||||
@@ -4,6 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace LIT\MCP\Integrations\Divi\Compose;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Ruling S45 tokenizer of lit/divi-replace-text (spec §5.7, rulings S8/S45): splits a string into
|
||||
* tags (quote-aware – a ">" inside a quoted attribute value does not end the tag), comments,
|
||||
|
||||
@@ -4,6 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace LIT\MCP\Integrations\Divi\Compose;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Looks up media library images for short-form fields like image_id (spec §6.3: Divi image
|
||||
* modules reference images by attachment ID plus URL). WpMediaResolver is the WordPress side.
|
||||
|
||||
@@ -7,6 +7,8 @@ namespace LIT\MCP\Integrations\Divi\Compose;
|
||||
use InvalidArgumentException;
|
||||
use LIT\MCP\Integrations\Divi\Design\DesignSystem;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Translates the placeholders of spec §5.4 into Divi's $variable(…)$ syntax:
|
||||
* {{color:primary|<Name>|gcid-…}}, {{var:<Name>|gvid-…}}, {{font:heading|body}},
|
||||
|
||||
@@ -8,6 +8,8 @@ use InvalidArgumentException;
|
||||
use LIT\MCP\Integrations\Divi\BlockTree\AttrMap;
|
||||
use LIT\MCP\Integrations\Divi\Schema\ShortformMap;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Writes short-form fields (spec §5.4, ShortformMap) into Divi attributes: checks the value per
|
||||
* kind, resolves placeholders (not for code) and sets it at "<path>.desktop.value[.<sub>]";
|
||||
|
||||
@@ -6,6 +6,8 @@ namespace LIT\MCP\Integrations\Divi\Compose;
|
||||
|
||||
use LIT\MCP\Integrations\Divi\BlockTree\Serializer;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* The forms a search text can take in stored block markup – the database prefilter of
|
||||
* lit/divi-replace-text and the check for global modules it does not edit. Only a prefilter:
|
||||
|
||||
@@ -8,6 +8,8 @@ use LIT\MCP\Integrations\Divi\BlockTree\AttrMap;
|
||||
use LIT\MCP\Integrations\Divi\BlockTree\Block;
|
||||
use LIT\MCP\Integrations\Divi\Schema\ModuleCatalog;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Which node may sit where (spec §5.4 "Struktur"): page → sections; regular section → rows;
|
||||
* fullwidth section → fullwidth modules (catalog category "fullwidth-module"); column/group →
|
||||
|
||||
@@ -8,6 +8,8 @@ use InvalidArgumentException;
|
||||
use LIT\MCP\Integrations\Divi\BlockTree\AttrMap;
|
||||
use LIT\MCP\Integrations\Divi\BlockTree\NodeSummary;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Replaces visible text in the attributes of one block (lit/divi-replace-text, spec §5.7, D10):
|
||||
* only in content (…innerContent) – plain values and the text keys of object values (text,
|
||||
|
||||
@@ -9,6 +9,8 @@ use LIT\MCP\Integrations\Divi\BlockTree\Container;
|
||||
use LIT\MCP\Integrations\Divi\BlockTree\Document;
|
||||
use LIT\MCP\Integrations\Divi\BlockTree\NodeIndex;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Structural changes on a parsed page (spec §5.7): where to insert (parent / before / after,
|
||||
* optional index), move, remove, duplicate – always checked against StructureRules. Works on
|
||||
|
||||
@@ -7,6 +7,8 @@ namespace LIT\MCP\Integrations\Divi\Compose;
|
||||
use InvalidArgumentException;
|
||||
use LIT\MCP\Integrations\Divi\Schema\ModuleCatalog;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* The single choke point through which every client string reaches Divi post_content. Divi
|
||||
* saves bypass kses (D7), so this pipeline is the guarantee. Pure PHP.
|
||||
|
||||
@@ -4,6 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace LIT\MCP\Integrations\Divi\Compose;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
// The installed PHPCompatibility sniffs predate enums (PHP 8.1) and read their methods as plain functions.
|
||||
// phpcs:disable PHPCompatibility.Variables.ForbiddenThisUseContexts.OutsideObjectContext
|
||||
// phpcs:disable PHPCompatibility.FunctionDeclarations.NewParamTypeDeclarations.SelfOutsideClassScopeFound
|
||||
|
||||
@@ -4,6 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace LIT\MCP\Integrations\Divi\Compose;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Cleans values before they go into Divi attributes (spec §5.6/§10: wp_kses_post for rich
|
||||
* text, sanitize_text_field for simple fields, esc_url_raw for URLs). Divi saves bypass kses
|
||||
|
||||
@@ -10,6 +10,8 @@ use LIT\MCP\Integrations\Divi\BlockTree\Json;
|
||||
use LIT\MCP\Integrations\Divi\Design\DesignSystem;
|
||||
use stdClass;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Divi's $variable({…})$ references (global colors, global variables, theme fonts, dynamic
|
||||
* content). Divi saves bypass kses (D7), Divi resolves references anywhere in a string with
|
||||
|
||||
@@ -11,6 +11,8 @@ use LIT\MCP\Integrations\Divi\BlockTree\NodeSummary;
|
||||
use LIT\MCP\Integrations\Divi\Design\DesignSystem;
|
||||
use LIT\MCP\Integrations\Divi\Schema\ShortformMap;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Quality warnings of a Divi write (spec §5.5) – only about the nodes this call created or
|
||||
* changed (and their children): fixed colors/fonts where a global one fits, images without
|
||||
|
||||
@@ -6,6 +6,8 @@ namespace LIT\MCP\Integrations\Divi\Design;
|
||||
|
||||
use InvalidArgumentException;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* The site's Divi design system as read live from Divi (spec §2 principle 2, §5.7): global
|
||||
* colors, global variables, theme fonts and sizes, module and group presets. Pure PHP –
|
||||
|
||||
@@ -7,6 +7,8 @@ namespace LIT\MCP\Integrations\Divi\Design;
|
||||
use ET\Builder\Packages\GlobalData\GlobalData;
|
||||
use ET\Builder\Packages\GlobalData\GlobalPreset;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Reads the design system from Divi's own APIs once per request (spec §2 principle 2 – no
|
||||
* copy is ever stored). Not final so abilities can be unit-tested with a mock.
|
||||
|
||||
@@ -9,6 +9,8 @@ use LIT\MCP\Abilities\Annotations;
|
||||
use LIT\MCP\Abilities\Errors;
|
||||
use WP_Error;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* lit/divi-design-system: global colors, variables, theme fonts/sizes and presets with the
|
||||
* placeholder to use for each (spec §5.4, §5.7). Read live from Divi; writing follows in
|
||||
|
||||
@@ -27,6 +27,8 @@ use LIT\MCP\Integrations\Integration;
|
||||
use LIT\MCP\Integrations\WordPress\Content\ContentComposer;
|
||||
use LIT\MCP\Integrations\WordPress\Schema\ContentSchema;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Divi 5 pages (spec §5, Etappe 2). Only available when the Divi 5 builder is loaded
|
||||
* (spec §2 principle 4); Divi 4 is never edited (spec §3.4). The write abilities share one
|
||||
|
||||
@@ -8,6 +8,8 @@ use LIT\MCP\Integrations\Divi\BlockTree\Block;
|
||||
use LIT\MCP\Integrations\Divi\BlockTree\NodeIndex;
|
||||
use LIT\MCP\Integrations\Divi\BlockTree\NodeSummary;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* What a Divi write did to the tree: summary, changed nodes (for ToolResult::changed – IDs of
|
||||
* surviving nodes are resolved after the change), touched nodes (for the quality warnings)
|
||||
|
||||
@@ -18,6 +18,8 @@ use LIT\MCP\Integrations\Divi\Compose\Warnings;
|
||||
use LIT\MCP\Integrations\Divi\Design\DesignSystemReader;
|
||||
use LIT\MCP\Integrations\Divi\Schema\DiviModules;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Wires the pure Compose classes with the live catalog, design system, Divi's dynamic content
|
||||
* registry and the WordPress sanitizer/media lookup – once per request and entry. Ruling S31:
|
||||
|
||||
@@ -17,6 +17,8 @@ use LIT\MCP\Integrations\WordPress\Content\ContentComposer;
|
||||
use LIT\MCP\Integrations\WordPress\Schema\ContentSchema;
|
||||
use WP_Error;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
||||
@@ -10,6 +10,8 @@ use LIT\MCP\Integrations\Divi\BlockTree\Block;
|
||||
use LIT\MCP\Integrations\Divi\BlockTree\NodeSummary;
|
||||
use WP_Error;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* lit/divi-delete: removes nodes with everything inside (spec §5.7, destructive). Needs
|
||||
* confirm: true after asking the user; without it the answer lists what would be removed –
|
||||
|
||||
@@ -8,6 +8,8 @@ use LIT\MCP\Abilities\Annotations;
|
||||
use LIT\MCP\Integrations\Divi\BlockTree\AttrMap;
|
||||
use WP_Error;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* lit/divi-duplicate-node: copies a node with everything inside right behind the original
|
||||
* (spec §5.7). The copy's admin label gets " (Kopie)"; read-only nodes (global modules,
|
||||
|
||||
@@ -8,6 +8,8 @@ use LIT\MCP\Abilities\Errors;
|
||||
use WP_Error;
|
||||
use WP_Post;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/** The client errors the Divi tools share. */
|
||||
final class DiviErrors
|
||||
{
|
||||
|
||||
@@ -6,6 +6,8 @@ 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
|
||||
|
||||
@@ -8,6 +8,8 @@ use LIT\MCP\Abilities\Annotations;
|
||||
use LIT\MCP\Abilities\Errors;
|
||||
use WP_Error;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* lit/divi-insert: inserts nodes in short and/or full form – modules, rows or whole sections –
|
||||
* at parent / before / after (spec §5.7). All or nothing (ruling S39): the whole input is
|
||||
|
||||
@@ -8,6 +8,8 @@ use LIT\MCP\Abilities\Annotations;
|
||||
use LIT\MCP\Abilities\Errors;
|
||||
use WP_Error;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* lit/divi-move: moves a node (with everything inside) to parent / before / after – also into
|
||||
* another row or section, as long as the structure rules allow it (spec §5.7). Read-only
|
||||
|
||||
@@ -16,6 +16,8 @@ use LIT\MCP\Integrations\Divi\Design\DesignSystemReader;
|
||||
use LIT\MCP\Integrations\Divi\Schema\ShortformMap;
|
||||
use WP_Error;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* lit/divi-node-get: all attributes of one node in the full form (spec §5.4, §5.7) –
|
||||
* attribute path => breakpoint map – plus the current short-form values.
|
||||
|
||||
@@ -13,6 +13,8 @@ use LIT\MCP\Integrations\Divi\BlockTree\Outline;
|
||||
use LIT\MCP\Integrations\Divi\Design\DesignSystemReader;
|
||||
use WP_Error;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* lit/divi-outline: the page tree with path IDs, types, admin labels, text excerpts and
|
||||
* preset names plus tree_rev (spec §5.3, §5.7). Every Divi write needs this tree_rev.
|
||||
|
||||
@@ -9,6 +9,8 @@ use LIT\MCP\Integrations\Divi\BlockTree\Document;
|
||||
use LIT\MCP\Integrations\Divi\BlockTree\NodeIndex;
|
||||
use WP_Post;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* An entry loaded for the Divi tools: the post, its parsed tree, the path index and the
|
||||
* tree_rev (hash of post_content – the optimistic lock of the Divi tools, ruling P16; the
|
||||
|
||||
@@ -13,6 +13,8 @@ use LIT\MCP\Integrations\WordPress\Schema\ContentSchema;
|
||||
use LIT\MCP\Log;
|
||||
use WP_Error;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Loads an entry for the Divi tools: rights and status via PostGuard (spec §4.5), then the
|
||||
* block tree. Divi 4 shortcode content and unbalanced markup are refused with a hint –
|
||||
|
||||
@@ -19,6 +19,8 @@ use LIT\MCP\Log;
|
||||
use Throwable;
|
||||
use WP_Error;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* lit/divi-replace-text: replaces visible text across the Divi pages of one content type
|
||||
* (spec §5.7, D10). dry_run (default true) only lists the hits with their tree_rev; the real run
|
||||
|
||||
@@ -15,6 +15,8 @@ use Throwable;
|
||||
use WP_Error;
|
||||
use WP_Post;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
||||
@@ -4,6 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace LIT\MCP\Integrations\Divi\Pages;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/** Input schema properties the Divi write tools share. */
|
||||
final class DiviSchema
|
||||
{
|
||||
|
||||
@@ -13,6 +13,8 @@ use LIT\MCP\Integrations\Divi\Compose\ValueCleaner;
|
||||
use LIT\MCP\Integrations\WordPress\PostGuard;
|
||||
use LIT\MCP\Integrations\WordPress\PostStatuses;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* The search part of lit/divi-replace-text (D10): the SQL prefilter for candidate pages and
|
||||
* the hits of one page, computed without changing it. The replacement is cleaned per place by
|
||||
|
||||
@@ -10,6 +10,8 @@ use LIT\MCP\Integrations\Divi\BlockTree\Block;
|
||||
use LIT\MCP\Integrations\Divi\Compose\ColumnWidths;
|
||||
use WP_Error;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* lit/divi-update: sets or removes values of existing nodes – short-form fields ("set"), full
|
||||
* form ("attrs", null removes a path or breakpoint), preset and admin label (spec §5.7). Several
|
||||
|
||||
@@ -8,6 +8,8 @@ use LIT\MCP\Abilities\Ability;
|
||||
use LIT\MCP\Abilities\ToolResult;
|
||||
use WP_Error;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* The frame of the Divi write tools (spec §5.6): permission and execute both load the page
|
||||
* through DiviWriter::page() (rights, Divi layout, tree_rev lock – execute never trusts state
|
||||
|
||||
@@ -16,6 +16,8 @@ use LIT\MCP\Integrations\Divi\Design\DesignSystemReader;
|
||||
use LIT\MCP\Integrations\WordPress\PostSaveFollowUp;
|
||||
use WP_Error;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* The shared frame of every Divi write (spec §5.6): load with rights and the tree_rev lock
|
||||
* (ruling P16; a mismatch is rev_mismatch and nothing is written), let the ability change the
|
||||
|
||||
@@ -10,6 +10,8 @@ use LIT\MCP\Integrations\Divi\Compose\DynamicContentRules;
|
||||
use LIT\MCP\Log;
|
||||
use Throwable;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* DynamicContentRules' dynamic content allow map (ruling S22) from Divi's live registry
|
||||
* DynamicContentOptions::get_options($postId, 'edit') – the options the Visual Builder offers
|
||||
|
||||
@@ -6,6 +6,8 @@ namespace LIT\MCP\Integrations\Divi\Pages;
|
||||
|
||||
use LIT\MCP\Integrations\Divi\Compose\MediaResolver;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Media library images for short-form fields (image_id, portrait_id, image_ids): only images
|
||||
* the current user may read. URL and alt text are cleaned by ShortformWriter like client input.
|
||||
|
||||
@@ -6,6 +6,8 @@ namespace LIT\MCP\Integrations\Divi\Pages;
|
||||
|
||||
use LIT\MCP\Integrations\Divi\Compose\ValueSanitizer;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* WordPress sanitizing of Divi values (spec §5.6/§10). Because DiviSaver bypasses kses for the
|
||||
* page as a whole (kses would re-serialize every untouched block, D7), every value this plugin
|
||||
|
||||
@@ -6,6 +6,8 @@ namespace LIT\MCP\Integrations\Divi\Schema;
|
||||
|
||||
use LIT\MCP\Integrations\Divi\BlockTree\AttrMap;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Known attribute paths of one module, derived from Divi's module metadata (settings of
|
||||
* every attribute group, attrName references) and its default attributes (spec §5.4:
|
||||
|
||||
@@ -10,6 +10,8 @@ use LIT\MCP\Abilities\Errors;
|
||||
use LIT\MCP\Abilities\JsonMap;
|
||||
use WP_Error;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* lit/divi-catalog: the modules of this Divi installation with their short-form fields;
|
||||
* with "module" the details of one module incl. all known attribute paths (spec §5.7).
|
||||
|
||||
@@ -6,6 +6,8 @@ namespace LIT\MCP\Integrations\Divi\Schema;
|
||||
|
||||
use ET\Builder\Packages\ModuleLibrary\ModuleRegistration;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Reads Divi's module metadata once per request (Divi 5 only). Not final so abilities can be
|
||||
* unit-tested with a mock.
|
||||
|
||||
@@ -4,6 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace LIT\MCP\Integrations\Divi\Schema;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* The modules this Divi installation knows (spec §5.7 lit-divi-catalog), built from
|
||||
* ModuleRegistration::get_all_core_modules_metadata() – always live, never a copy.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user