Skip to content

Third-party Divi 5 modules are readable but not editable through the agent API #11

Description

@rubicon

Description

On a Divi 5 page that uses a third-party module (Divi Flash's difl/*, and I would expect any third-party namespace such as decm/* or d5bgo/*), page_get_layout reports the module and hands back a targeting identifier that carries its namespace, for example difl/faq:1. Every write and targeting path then rejects that same identifier, because those paths assume the divi/ namespace. The result is a read/write asymmetry: the plugin gives you a target it will not accept back.

In practice the page can be inspected through the API but its third-party modules cannot be edited through it. The only workaround is to rebuild the raw block comment by hand outside the plugin, which gets fragile fast once a page has more than a couple of modules.

Environment

  • WordPress: 7.0.2
  • Divi: 5.9.0
  • diviops-agent plugin: 1.5.10
  • PHP: 8.5.8

The bug is in the plugin's REST layer, so it reproduces independently of the @diviops/mcp-server version, and it surfaces the same way through the MCP tools that call these routes.

Steps to reproduce

  1. On a Divi 5 page, add any third-party module, for example Divi Flash's FAQ (difl/faq) or Counter (difl/counter).
  2. Read the page with page_get_layout (GET /diviops/v1/page/get-layout/<id>). The third-party module is reported with an auto_index that keeps its namespace, e.g. difl/faq:1.
  3. Pass that exact identifier to module_get, module_update, or module_move (or the corresponding MCP tools).
  4. Do the same with a Theme Builder insert whose content is a third-party module.

Expected

The identifier that page_get_layout returns resolves in every operation, the same way a divi/* identifier does.

Actual

module_get / module_update / module_move fail to resolve difl/faq:1, and parse_divi_blocks_for_insert() returns a 400 for a non-divi/ top-level block. schema_get_module also 404s for difl/faq, because the name gets a divi/ prefix and becomes divi/difl/faq.

Root cause

The read path is namespace-agnostic but the write and targeting paths are not. The raw block-comment scanners behind module_update, find_block (used by module_get and module_move), and the section scanners find the end of a block name by scanning to the first space or slash after <!-- wp:, which truncates a namespaced name (difl/faq becomes difl, since the name contains a slash). page_get_layout derives its identifier with a plain str_replace('divi/', '', $name), which leaves a third-party name intact, so the two halves disagree. Theme Builder insert and parse_tb_parent_selector() additionally require the literal divi/ prefix, and schema_get_module prepends it unconditionally.

A couple of related points that matter for a complete fix: the write-safety marker counting and the block-attribute normalization also key off divi/, so a namespace-agnostic fix has to widen those too without letting them touch unrelated Gutenberg blocks. Scoping normalization to Divi modules is not as simple as a registry lookup, because Divi's own core modules (divi/text, divi/section) are largely not present in WP_Block_Type_Registry, while third-party modules are. Namespace has to be trusted first, with the module/child-module block category as the fallback signal for third-party modules.

Offer

I have a fix that makes targeting namespace-agnostic end to end: a single identifier mapping used by both the read and the write paths, scanners that match the actual block-name grammar so a namespaced name is not truncated, the self-closing and depth-pairing scans made namespace-aware, and normalization scoped to Divi modules by namespace or block category. It is verified against a live page carrying difl/* and d5bgo/* modules alongside native Divi ones, with the native divi/* behavior unchanged. Happy to share the patch or walk through the reasoning in whatever form is easiest for your upstream workflow.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions