# Divi 5 Module API Calls — Complete Agent Reference

Everything an AI agent needs to build Divi 5 modules programmatically — every API endpoint, block attribute path, DiviOps tool, pattern, limitation, and gotcha. Compiled from 32 skill files, 2 wiki pages, and real production deployments.

Source files (all read 2026-07-05): - `/home/kaburu/.hermes/skills/infrastructure/divi-5-builder/SKILL.md` (649 lines) - `/home/kaburu/.hermes/skills/infrastructure/divi-5-builder/references/` (19 reference files) - `/home/kaburu/.hermes/skills/infrastructure/divi-5-builder/scripts/` (7 scripts) - `/home/kaburu/.hermes/skills/infrastructure/divi-5-builder/templates/page-blueprints.yaml` (361 lines) - `/home/kaburu/wiki/wiki/web/divi-5-lessons.md` (436 lines) - `/home/kaburu/wiki/wiki/projects/divi-5-builder-bot.md` (312 lines)

## 1. DiviOps MCP Tools — All 85 Free Tools

Package: `@diviops/mcp-server` v1.5.33 (MIT license, free) Plugin: `diviops-agent` v1.5.5 (free, WordPress plugin) Base REST path: `https://<site>/wp-json/diviops/v1/`

Key fact: Pro is NOT needed. All 85 execution tools ship free. Pro sells curated reference docs (boxShadow, filters, transform, sticky, scroll, animation), which can be discovered via `diviops_schema_get_module(raw=true)`.

### Page Authoring (12 tools)

Tool Purpose
—————
`diviops_page_create` Create new page with Divi block content
`diviops_page_get` Get page info + raw block content
`diviops_page_get_layout` Parsed block tree with auto_index targeting
`diviops_page_list` List pages with Divi builder status
`diviops_page_update_content` Replace entire page content
`diviops_page_update_meta` Update title, slug, parent, menu_order
`diviops_page_update_status` Publish, draft, schedule, trash
`diviops_page_trash` Trash or permanently delete
`diviops_section_append` Add section to existing page
`diviops_section_get` Get section by label or text match
`diviops_section_replace` Replace section content
`diviops_section_remove` Remove section

### Module Operations (5 tools)

Tool Purpose
—————
`diviops_module_get` Get module by auto_index, label, or text match
`diviops_module_update` Update attrs via dot notation paths
`diviops_module_clone` Duplicate module
`diviops_module_move` Reorder module (before/after target)
`diviops_module_lock` / `diviops_module_unlock` Lock/unlock for VB editing

### Design System (~15 tools)

Tool Purpose
—————
`diviops_global_color_*` Create/list/update/delete global colors
`diviops_global_font_*` Create/list/update/delete global fonts
`diviops_variable_*` Design tokens (colors, numbers, fluids)
`diviops_variable_create_fluid_system` Batch-generate typography/spacing/radius scale
`diviops_variable_used_on_page` Which variables a page emits
`diviops_preset_*` Module/group presets for reusable styles

### Validation & Preview (3 tools)

Tool Purpose
—————
`diviops_validate_blocks` Check block format (missing builderVersion, empty modules)
`diviops_render_preview` Render blocks to HTML (verify content appears)
`diviops_meta_flush_cache` Clear Divi CSS cache for a post or all

### Schema (3 tools)

Tool Purpose
—————
`diviops_schema_list_modules` List registered Divi modules (divi/\* only — NOT difl/\*)
`diviops_schema_get_module` Full attribute schema for a module (use raw=true)
`diviops_schema_get_settings` Site settings + theme options

### Theme Builder (4 tools)

Tool Purpose
—————
`diviops_tb_template_create` Create TB template with header/footer
`diviops_tb_template_list` List TB templates + conditions
`diviops_tb_layout_get` / `diviops_tb_layout_update` Read/write TB layouts
`diviops_tb_layout_block_insert` Insert blocks into TB layout

### Library, Canvas, Menu, Meta (~20 tools)

Tool Purpose
—————
`diviops_library_*` Divi Library save/get/list
`diviops_canvas_*` Off-canvas workspaces (popups, modals)
`diviops_menu_*` WordPress nav menu management
`diviops_meta_find_icon` Search FA/Divi icons
`diviops_meta_wp_cli` WP-CLI passthrough (safe allowlist)

### Templates (2 tools)

Tool Purpose
—————
`diviops_template_list` List available block patterns
`diviops_template_get` Get pre-verified block pattern markup

Pre-verified templates: `hero-centered`, `features-blurbs`, `cta-gradient`, `cards-flex`

### Site-connected MCP Servers (as of 2026-07-04)

MCP server name Site Divi DiviOps DiviFlash
—————–——————————–
`diviops` kaburu.co 5.8.0 1.5.5 5.2.0
`diviops-l8` l8.kaburu.co.uk 5.8.1 1.5.5 5.2.0
`diviops-chippy` thechippyvan.co.uk 5.8.1 1.5.5
`diviops-llmtest` llmtest.kaburu.co 5.8.1 1.5.5 1.4.14

## 2. WordPress REST API Endpoints

### DiviOps Plugin REST API All paths under `https://<site>/wp-json/diviops/v1/`:

Endpoint Purpose
———-———
`POST /pages` Create page
`GET /pages/{id}` Get page
`PUT /pages/{id}/content` Update page content
`PUT /pages/{id}/meta` Update page meta
`PUT /pages/{id}/status` Update page status
`DELETE /pages/{id}` Trash/delete
`GET /pages` List pages
`POST /pages/{id}/sections` Append section
`GET /pages/{id}/sections/{label}` Get section
`PUT /pages/{id}/sections/{label}` Replace section
`DELETE /pages/{id}/sections/{label}` Remove section
`GET /pages/{id}/modules/{auto_index}` Get module
`PUT /pages/{id}/modules/{auto_index}` Update module
`POST /pages/{id}/modules/{auto_index}/clone` Clone module
`POST /pages/{id}/modules/{auto_index}/move` Move module
`POST /pages/{id}/modules/{auto_index}/lock` Lock module
`POST /pages/{id}/modules/{auto_index}/unlock` Unlock module
`GET /schema/settings` Site settings
`GET /schema/modules` List modules (divi/* only)
`GET /schema/modules/{name}` Get module schema
`POST /validate/blocks` Validate block markup
`POST /render/preview` Render blocks preview
`POST /cache/flush` Flush CSS cache
`GET /templates` List templates
`GET /templates/{name}` Get template
`GET /globals/colors` List global colors
`POST /globals/colors` Create global color
`PUT /globals/colors/{id}` Update global color
`DELETE /globals/colors/{id}` Delete global color
`GET /globals/fonts` List global fonts
`POST /globals/fonts` Create global font
`PUT /globals/fonts/{id}` Update global font
`DELETE /globals/fonts/{id}` Delete global font
`GET /variables` List design tokens
`POST /variables` Create variable
`PUT /variables/{id}` Update variable
`DELETE /variables/{id}` Delete variable
`POST /variables/fluid-system` Generate fluid scale
`GET /presets` List presets
`POST /presets` Create preset
`GET /tb/templates` List TB templates
`POST /tb/templates` Create TB template
`GET /tb/templates/{id}/layout` Get TB layout
`PUT /tb/templates/{id}/layout` Update TB layout
`POST /tb/templates/{id}/blocks` Insert blocks into TB layout
`GET /library` List library items
`POST /library` Save to library
`GET /meta/icons` Find icon
`POST /meta/wp-cli` Run safe WP-CLI command

### RankMath REST API Base: `https://<site>/wp-json/rankmath/v1/` — Auth: WordPress app password (Basic Auth)

Endpoint Method Purpose
———-——–———
`/updateMeta` POST Set focus keyword, SEO title, meta desc, OG tags
`/updateSchemas` POST Set Article/FAQ/Service/LocalBusiness schema
`/searchIntent` POST Check keyword intent (informational/commercial/transactional)
`/updateSeoScore` POST Update SEO score
`/updateRedirection` POST Create 301/302/307/410/451 redirects
`/saveModule` POST Enable/disable RankMath modules
`/dashboardWidget` GET SEO overview
`/links/posts` GET Posts with SEO scores, filter by orphans/score
`/links/links` GET Internal/external links
`/links/posts-stats` GET Overall link stats
`/links/links-stats` GET Overall link stats

RankMath postmeta keys (settable via `wp post meta update`): `rank_math_focus_keyword`, `rank_math_title`, `rank_math_description`, `rank_math_facebook_title`, `rank_math_facebook_description`, `rank_math_facebook_image`, `rank_math_twitter_title`, `rank_math_twitter_description`, `rank_math_twitter_image`, `rank_math_canonical_url`, `rank_math_robots`

Note: RankMath has NO WP-CLI commands — REST API or direct postmeta writes only.

### RankWatch API Base: `https://apiv2.rankwatch.com/{path}/{json|xml}/{params}/` Auth: Basic HTTP (`token:password`). All paths require trailing slash.

Endpoint Method Purpose
———-——–———
`/user/profile/json/` GET User profile, plan, keyword limit
`/project/list/json/count/{N}/offset/{N}` GET List projects
`/project/detail/json/p_id/{id}` GET Project details
`/project/ranking/json/p_id/{id}/s_id/{se}/k_id/{kw}/from/{date}/to/{date}/` GET Keyword rankings (max 3mo range)
`/project/add/json/` POST Add project
`/project/edit/json/` POST Edit project
`/project/delete/json/p_id/{id}` DELETE Delete project
`/project/keyword/add/json/` POST Add keywords
`/project/keyword/delete/json/p_id/{id}/k_id/{kw}` DELETE Delete keyword
`/project/webstats/json/p_id/{id}` GET Webstats
`/project/rankcalc/json/p_id/{id}` GET Initiate rank calculations
`/project/multiple-rankings/json/p_id/{id}/` GET Multiple keyword rankings
`/project/suburl/json/p_id/{id}` GET Sub-URLs
`/searchengine/list/json/` GET Search engine IDs

### WordPress Core REST API `POST https://<site>/wp-json/wp/v2/media` — Upload media (used for image pipeline)

### chippy-bridge Custom REST API Namespace: `chippy/v1` (public read access)

Endpoint Method Purpose
———-——–———
`/route/today` GET Today's route + stops
`/position` GET Current van GPS position
`/status` GET Overall status
`/preferences` GET/POST User day preferences
`/stops/nearest` GET Nearest stop to lat/lng
`/routes` GET List all routes

### ComfyUI Local API - `POST http://localhost:8188/prompt` — Send workflow (returns prompt_id) - `GET http://localhost:8188/history/{prompt_id}` — Poll for completion - `GET http://localhost:8188/view?filename=…` — Fetch output image

## 3. Divi Block JSON Attribute Paths

### Block Structure (Every Block) ```python {

  "module": {
      "decoration": { ... },   # Visual styling
      "advanced": { ... },     # Advanced settings
      "content": { ... }       # Some modules
  },
  "builderVersion": "5.0.3"   # BLOCK SPEC version, NOT theme version

} ```

### Module Decoration Paths

CSS Property Divi Attribute Path
————-——————-
`background-color` `module.decoration.background.desktop.value.color`
`background-image` `module.decoration.background.desktop.value.image`
`background: linear-gradient(…)` `module.decoration.background.desktop.value.gradient`
`padding` `module.decoration.spacing.desktop.value.padding`
`margin` `module.decoration.spacing.desktop.value.margin`
`max-width` `module.decoration.sizing.desktop.value.maxWidth`
`border-radius` `module.decoration.border.desktop.value.radius`
`display` `module.decoration.layout.desktop.value.display`
`box-shadow` (Pro) `module.decoration.boxShadow.desktop.value`
`filter` (Pro) `module.decoration.filter.desktop.value`
`transform` (Pro) `module.decoration.transform.desktop.value`

### Padding/Margin Sub-paths ``` module.decoration.spacing.desktop.value.padding.top module.decoration.spacing.desktop.value.padding.right module.decoration.spacing.desktop.value.padding.bottom module.decoration.spacing.desktop.value.padding.left module.decoration.spacing.desktop.value.padding.syncVertical module.decoration.spacing.desktop.value.padding.syncHorizontal ```

### Gradient Sub-paths ``` module.decoration.background.desktop.value.gradient.enabled # “on”/“off” module.decoration.background.desktop.value.gradient.direction # “180deg” module.decoration.background.desktop.value.gradient.stops[] # [{color, position}] ```

### Content Decoration Paths (Text Module)

Property Path
———-——
Body text font family `content.decoration.bodyFont.body.font.desktop.value.family`
Body text color `content.decoration.bodyFont.body.font.desktop.value.color`
Body text size `content.decoration.bodyFont.body.font.desktop.value.size`
Body text weight `content.decoration.bodyFont.body.font.desktop.value.weight`
Body text line height `content.decoration.bodyFont.body.font.desktop.value.lineHeight`
Body text align `content.decoration.bodyFont.body.font.desktop.value.textAlign`
Body text transform `content.decoration.bodyFont.body.font.desktop.value.textTransform`
Body text letter spacing `content.decoration.bodyFont.body.font.desktop.value.letterSpacing`
H1 font family `content.decoration.headingFont.h1.font.desktop.value.family`
H1 font size `content.decoration.headingFont.h1.font.desktop.value.size`
H1 color `content.decoration.headingFont.h1.font.desktop.value.color`
H1 weight `content.decoration.headingFont.h1.font.desktop.value.weight`
H1 line height `content.decoration.headingFont.h1.font.desktop.value.lineHeight`
H1 letter spacing `content.decoration.headingFont.h1.font.desktop.value.letterSpacing`
H2 font `content.decoration.headingFont.h2.font.desktop.value.*`
Tablet overrides `*.headingFont.h1.font.tablet.value.*`
Phone overrides `*.headingFont.h1.font.phone.value.*`

### Text Content Path `content.innerContent.desktop.value` — The HTML string for text modules. This is the single most common path error.

### Button Module Paths

Property Path
———-——
Button text `button.innerContent.desktop.value.text`
Button URL `button.innerContent.desktop.value.link.url`
Button color `button.decoration.font.font.desktop.value.color`
Button bg color `button.decoration.background.desktop.value.color`
Button padding `module.decoration.spacing.desktop.value.padding`
Button icon enable `button.decoration.button.desktop.value.icon.enable`

### Image Module Paths

Property Path
———-——
Image src `content.decoration.image.desktop.value.src`
Image alt `content.decoration.image.desktop.value.alt`
Background image `module.decoration.background.desktop.value.image`
Background size `module.decoration.background.desktop.value.size`
Background position `module.decoration.background.desktop.value.position`

### Advanced Module Paths ``` module.advanced.text.text.desktop.value.color # Text color module.advanced.text.font.desktop.value.fontSize # Font size module.advanced.text.font.desktop.value.font # Font family module.advanced.type.desktop.value # Column width (e.g. “4_4”, “1_2”) ```

### headingFont Nesting Trap (CRITICAL) ```python # WRONG — bodyFont ends up inside h1, missing closing braces: {“headingFont”: {“h1”: {“font”: {“desktop”: {…}, “tablet”: {…}, “phone”: {…}}}, “bodyFont”: {…}}}

# CORRECT — bodyFont is sibling of h1, proper closing: {“headingFont”: {“h1”: {“font”: {“desktop”: {…}, “tablet”: {…}, “phone”: {…}}}}, “bodyFont”: {…}} ```

### Unicode Escapes in innerContent

Character Escape Notes
———–——–——-
`<` `\u003c` Must remain as literal in JSON
`>` `\u003e` Store as string, don't decode
`“` `\u0022` Inside JSON string values
`&` `\u0026` For HTML entities

## 4. Create vs Modify Rules — THE CARDINAL RULE

### MODIFY existing VB-created blocks via REST API = WORKS ✅ - Batch text updates across many pages - Style migration (spacing, colors, typography) - Content replacement (placeholder text → real copy) - Stripping inline styles → moving to block JSON attributes - VB reads updated block JSON on next open and renders correctly

### CREATE new blocks via REST API = INVISIBLE in VB ❌ - Content renders on frontend (perfectly) - VB Layers panel shows only a single empty “section” - Client CANNOT select, move, or edit programmatically-created blocks - Why: Divi 5 blocks do NOT register in Divi's internal React state. VB loads content into its own state management layer; blocks not created there are invisible.

### Workflow Decision Matrix

Task Tool Works?
——————–
Change text, colors, spacing on existing blocks REST API / DiviOps MCP
Add new section, row, or module VB (browser automation) or human Required
Create entire page programmatically REST API / DiviOps MCP Only if page NEVER needs VB editing
Batch style changes across 50+ pages REST API ✅ (create structure in VB first, then bulk modify)

### Page Build Architecture (for programmatic pages) The `gen-divi-page.py` script generates block markup with `json.dumps()` (guarantees correct JSON), writes to file, SCPs to Hetzner, and pushes via `wp post update`. Pages render on frontend. For pages that need VB editing, create structure manually in VB first.

L8 Water Hygiene deployment (proven): 62 blocks, 6 sections, 21/22 content strings verified, `wp post update` → `wp post meta update` → `wp cache flush`.

## 5. Visual Builder Architecture

### Dual-Frame Layout ``` Parent Window (React app) ├── Sidebar, settings panel, toolbar, layers panel, TinyMCE ├── Iframe: #et-vb-app-frame │ ├── Page canvas/preview DOM │ ├── wp.* (WordPress core — NO wp.data) │ ├── DIVI object (builder config, item counts, selectors) │ ├── ET_Builder object (API, Frames, Misc) │ └── window.divi.data (read-only state registry) └── React root: #et-vb-app-frame-wrapper ```

### window.divi.data — Read-Only State Registry ```javascript var store = window.divi.data.select('divi/edit-post');

store.getAllModuleIds(); // Array of all module IDs on page store.getModuleName(id); // 'divi/text', 'divi/section', etc. store.getModuleType(id); // 'module', 'section', 'row', 'column' store.getModuleAttrs(id); // Full attributes object ```

Key characteristics: - READ ONLY — no public API for writing state - Module IDs are EPHEMERAL — change on every page reload - `wp.data.select()` and `wp.data.dispatch()` are NOT available - `window.divi.data` is the ONLY way to programmatically read VB state

### State Management Rules 1. Read — via `window.divi.data.select('divi/edit-post')` 2. Write — ONLY via UI interaction (clicks, keyboard input in VB) 3. Modify existing blocks — via REST API (modifying block JSON in post_content) 4. Create new blocks — ONLY via Playwright browser automation (VB UI) 5. Verify — use `window.divi.data` to confirm state after UI actions 6. Never hardcode module IDs — they're ephemeral per session

### Playwright VB Automation (reference — not primary workflow) ``` # Open VB: https://site.com/?p={page_id}&et_fb=1&PageSpeed=off # Structure Shortcut: press 's' then '1' = section with 1 row # Save: Meta+s (Cmd+S) ```

### Browser Automation Tool: Web MCP Web MCP (`chrome://flags/#web-mcp-for-testing`) replaces Playwright for browser-dependent tasks: - Login to WordPress admin - Open Visual Builder manually - Take screenshots of live pages - Interact with non-Divi UI (settings, plugins)

Hosted on kaburu-laptop (192.168.0.142), flag enabled as of 2026-07-04. MCP server: `chromium-webmcp` (disable — needs Chromium running).

## 6. Auth Patterns

### Pattern 1: WordPress Application Password (PRIMARY) ```bash # Create wp user application-password create kaburu “diviops-mcp” –allow-root # Returns: Password: XXXXXXXXXXXXXXXX ``` Used for: DiviOps MCP, RankMath REST API, ComfyUI image uploads

API usage: ```python import base64 credentials = base64.b64encode(f”username:app_password“.encode()).decode() headers = {“Authorization”: f”Basic {credentials}“} ```

### Pattern 2: Cookie Auth (for browser-based access) Generate auth cookies server-side to bypass login restrictions (Wordfence, LiteSpeed, Cloudflare): ```bash php -r ' require_once(“wp-load.php”); $user = get_user_by(“login”, “USERNAME”); $hash = COOKIEHASH; $logged_in = wp_generate_auth_cookie($user→ID, time()+7200, “logged_in”); $auth = wp_generate_auth_cookie($user→ID, time()+7200, “auth”); echo “COOKIEHASH=”.$hash.”\nLOGGED_IN=“.$logged_in.”\nAUTH=“.$auth.”\n“; ' ```

Inject into browser: `wordpress_{hash}`, `wordpress_logged_in_{hash}`, `wordpress_sec_{hash}` cookies.

### Pattern 3: WP-CLI Application Password Lifecycle Old app passwords can start returning 401. Create fresh ones if uploads fail: ```bash wp –path=/home/{site}/public_html –allow-root user application-password create kaburu “divi-bot-pipeline” ```

### Pattern 4: wpApiSettings.nonce (for VB context) ```javascript // Inside VB iframe, use wpApiSettings.nonce for authenticated REST calls // Avoids Authorization header issues specific to VB context wp.apiRequest({ path: '/wp/v2/pages/' + pageId, method: 'PUT', data: { … } }); ```

### Known Active App Passwords

Site User Password Name Purpose
———————-—————
kaburu.co kaburu `qPAxzp9fegmvRE3yKRDO6LNq` diviops-mcp DiviOps MCP + RankMath
l8.kaburu.co.uk kaburu `khajJiBbhnmUM9kVZW7JWHWM` divi-bot-pipeline Image upload pipeline
l8.kaburu.co.uk kaburu `tPnNTT6R7DEhHgoFkP4XPYhM` rankmath-api RankMath REST API
thechippyvan.co.uk kaburu `2aa0lGkrotBif2EhsH7ACueH` diviops-mcp DiviOps MCP

## 7. Known Limitations & Gotchas

### HARD RULES (Never Violate)

# Rule Detail
————–
1 ❌ NEVER create new VB content via REST API REST-injected blocks are invisible in VB. Use VB UI for structure.
2 ❌ NEVER hand-write Divi 5 block JSON Use Python `json.dumps()`. One missing `}` breaks ALL text modules.
3 ❌ NEVER set builderVersion to theme version Use `”5.0.3“` (block spec version), NOT “5.8.1”.
4 ❌ NEVER regex-extract block JSON `–>` can appear inside JSON strings. Use brace-depth parser.
5 ❌ NEVER call WordPress REST API in parallel from same session Requests hang indefinitely. Chain sequentially.
6 ❌ NEVER SSH as root for WordPress operations Creates root-owned files. Use MCP/CyberPanel tools.
7 ❌ NEVER use `wp cron event run –allow-root` Creates root-owned cache files. Use wget crons.
8 ❌ NEVER embed base64 images in SSH command-line args Use stdin pipe for images >~100KB.
9 ❌ TinyMCE `setContent()` doesn't persist Divi reads from React state on save. Type via keyboard events.
10 ❌ Testimonial blocks drop Author/JobTitle in SSR Append as plain text: `”Text…\n— Author, Company“`

### SOFT RULES (Breaking These Wastes Time)

# Rule Detail
————–
11 `innerContent` at wrong path → empty modules Must be at `content.innerContent.desktop.value`, not `module.content`
12 `builderVersion` wrong → validator reports errors Always `”5.0.3“`
13 FastPixel active → VB returns 500 Deactivate `fastpixel-website-accelerator` before VB work
14 Page created but frontend blank Check `_et_pb_use_builder=on` and `_et_pb_page_layout=et_full_width_page` postmeta
15 DiviFlash modules not in DiviOps schema Expected — `difl/*` not registered. Read `module.json` directly from server
16 `render_preview` shows content but frontend doesn't Flush cache: `diviops_meta_flush_cache(post_id=N)`
17 `flush_cache` wrong parameter format Pass `post_id` as integer, not `page_id`
18 Unicode escapes decoded before storage Keep `\u003c` as literal string — don't let json.dumps decode
19 MCP double-escapes backslashes on >7 blocks Write to file, SCP, `wp post update` — bypass MCP transport
20 `headingFont.h1.font` nesting trap Close `font` with `}}}` before `bodyFont`
21 `wp media import` fails — no ImageMagick/GD Install `php-imagick` or use cross-origin URL
22 New MCP servers need session restart `/reset` — no live reload
23 LiteSpeed ignores vhost phpIniOverride and .user.ini Edit system php.ini: `/usr/local/lsws/lsphp83/etc/php/8.3/litespeed/php.ini`
24 Theme copy inherits 750/640 perms → 403 `find … -exec chmod 755/644`
25 LiteSpeed .htaccess ignored → permalinks 404 Embed rewrite rules in vhost config
26 CSS specificity is unusually deep Need `.et_pb_section .et_pb_row .et_pb_module .et_pb_text_inner`
27 Row width vs section width Rows default to ~1080px constrained. Set maxWidth: 100% for full-bleed.
28 Desktop-first breakpoints (max-width) NOT mobile-first
29 wp.data NOT available in VB iframe Don't suggest wp.data.select()
30 Application passwords may 401 Some hosts strip Authorization header. Use cookie auth instead.
31 Module UUIDs change on every reload Search by unique text content, not UUID
32 Use wp.apiRequest NOT wp.apiFetch wp.apiFetch throws TypeError in VB context
33 Chain REST calls sequentially Parallel calls hang. Use .done() callbacks.
34 Use site variables (database icon) Don't hardcode shared design tokens
35 Section bg images may not render via JSON Set solid color fallback + use inline CSS in text block
36 No public Divi 5 JSON schema Don't suggest export+modify. Use VB automation.

### Server/Infrastructure Gotchas

# Pitfall Fix
————–
37 LiteSpeed wp-json routing returns HTML instead of JSON Add `RewriteRule wp-json/(.*)$ /index.php?rest_route=/$1 [L,QSA]` in vhost
38 Cloudflare blocks REST API from kaburuaibox (error 1010) Relay via Hetzner (SSH stdin pipe → decode → curl)
39 FastPixel caches REST 404s Deactivate FastPixel, move object-cache.php aside, flush, then reactivate
40 WP-CLI created page has no permalink Run `wp rewrite structure '/%postname%/'`
41 wp-install.sh doesn't set permalink or Divi meta Manual post-wizard steps required
42 FluentSMTP half-configured kills `wp user update` Use `wp eval` with `$wpdb→update()` instead
43 Divi theme bundles the builder — no separate plugin Just activate Divi theme; no separate “Divi Builder” plugin exists
44 `wp menu item add-page` doesn't exist Use `wp menu item add-post MENU_ID PAGE_ID`
45 `cp -a` preserves restrictive permissions Fix with `find … -exec chmod`
46 CyberPanel `ssl` is reserved word in MariaDB Backtick-escape: `` `ssl` `` in SQL queries

## 8. Agent Cheat Sheet

### Build a Page (Complete Pipeline) ```bash # 1. Generate blocks with Python (guarantees correct JSON) python3 gen-divi-page.py # Output: /tmp/divi-page-output.html

# 2. SCP to Hetzner via Tailscale scp -i /opt/hermes/config/hetzner_id_ed25519 /tmp/divi-page-output.html [email protected]:/tmp/

# 3. Push to WordPress ssh -i /opt/hermes/config/hetzner_id_ed25519 [email protected] '

cd /home/{site}/public_html
PAGE_ID=$(wp post create --post_type=page --post_title="Page Title" --post_status=draft --porcelain --allow-root)
wp post update $PAGE_ID /tmp/divi-page-output.html --allow-root
wp post meta update $PAGE_ID _et_pb_use_builder on --allow-root
wp post meta update $PAGE_ID _et_pb_page_layout et_full_width_page --allow-root
wp post update $PAGE_ID --post_status=publish --allow-root
wp cache flush --allow-root

'

# 4. Verify curl -sL https://{site}/?page_id={ID} | grep -o 'expected text' | sort -u

# 5. Visual QA (skip for auth-walled pages) python3 /home/kaburu/scripts/vision-check.py https://{site}/{slug} ```

### Python Block Generator Template ```python import json

def text_block(module_deco, content_deco, inner_content):

  obj = {
      "module": {"decoration": module_deco},
      "content": {
          "decoration": content_deco,
          "innerContent": {"desktop": {"value": inner_content}}
      },
      "builderVersion": "5.0.3"
  }
  return f'<!-- wp:divi/text {json.dumps(obj, ensure_ascii=False)} /-->'

def button_block(module_deco, button_obj):

  obj = {
      "module": {"decoration": module_deco},
      "button": button_obj,
      "builderVersion": "5.0.3"
  }
  return f'<!-- wp:divi/button {json.dumps(obj, ensure_ascii=False)} /-->'

def section_block(module_deco, children):

  obj = {"module": {"decoration": module_deco}, "builderVersion": "5.0.3"}
  return f'<!-- wp:divi/section {json.dumps(obj, ensure_ascii=False)} -->\n{children}\n<!-- /wp:divi/section -->'

def row_block(module_deco, children):

  obj = {"module": {"decoration": module_deco}, "builderVersion": "5.0.3"}
  return f'<!-- wp:divi/row {json.dumps(obj, ensure_ascii=False)} -->\n{children}\n<!-- /wp:divi/row -->'

def column_block(module_advanced, module_deco, children):

  obj = {"module": {"advanced": module_advanced, "decoration": module_deco}, "builderVersion": "5.0.3"}
  return f'<!-- wp:divi/column {json.dumps(obj, ensure_ascii=False)} -->\n{children}\n<!-- /wp:divi/column -->'

# Presets LAYOUT_BLOCK = {“layout”: {“desktop”: {“value”: {“display”: “block”}}}} def bg_color(color):

  return {"background": {"desktop": {"value": {"color": color}}}}

def padding(top=”“, right=”“, bottom=”“, left=”“):

  return {"spacing": {"desktop": {"value": {"padding": {
      "top": top, "right": right, "bottom": bottom, "left": left,
      "syncVertical": "off", "syncHorizontal": "off"
  }}}}}

```

### Modify Existing Block via DiviOps MCP ```python # Update text color on a specific module diviops_module_update(

  page_id=123,
  auto_index=5,
  attrs={"module.advanced.text.text.desktop.value.color": "#333333"}

)

# Update text content diviops_module_update(

  page_id=123,
  auto_index=3,
  attrs={"content.innerContent.desktop.value": "<p>New text here</p>"}

)

# Flush cache after changes diviops_meta_flush_cache(post_id=123) ```

### WP-CLI Quick Reference ```bash # Create app password wp user application-password create kaburu “diviops-mcp” –allow-root

# Set Divi postmeta wp post meta update PAGE_ID _et_pb_use_builder on –allow-root wp post meta update PAGE_ID _et_pb_page_layout et_full_width_page –allow-root

# Set home page wp option update page_on_front PAGE_ID –allow-root wp option update show_on_front page –allow-root

# Set permalinks wp rewrite structure '/%postname%/' –allow-root

# Set RankMath SEO meta wp post meta update PAGE_ID rank_math_focus_keyword “keyword here” –allow-root wp post meta update PAGE_ID rank_math_title “SEO Title” –allow-root wp post meta update PAGE_ID rank_math_description “Meta description” –allow-root

# Flush all caches wp cache flush –allow-root

# Debug block JSON wp eval ' $c = get_post_field(“post_content”, PAGE_ID); preg_match(”/<!– wp:divi\/text.*?\/–>/“, $c, $m); $s = substr($m[0], 18, -4); $d = json_decode($s, true); echo ($d === null) ? “FAIL: ”.json_last_error_msg() : “OK”; ' –allow-root

# Build a new MCP server wp –path=/home/{site}/public_html –allow-root plugin install /tmp/diviops-agent.zip –activate wp –path=/home/{site}/public_html –allow-root user application-password create kaburu “diviops-mcp” # Then register in ~/.hermes/config.yaml via Python YAML manipulation ```

### DiviFlash Module Usage Pattern ```python # 1. Read schema from server # cat wp-content/plugins/diviflash/Builder/Server/modules-json/<Module>/module.json

# 2. Write as block comment difl_block = '<!– wp:difl/faq {“module”: { “decoration”: { “background”: {“desktop”: {“value”: {“color”: ”#ffffff“}}}, “spacing”: {“desktop”: {“value”: {“padding”: {“top”: “40px”, “bottom”: “40px”}}}} } }, “faq_que_text_tab”: “Question here”, “faq_ans_text_tab”: “Answer here”, “builderVersion”: “5.0.3”} /–>'

# 3. Save via DiviOps (may not preview — VERIFY on frontend) diviops_page_update_content(page_id=123, content=difl_block) # Verify: curl -sL https://site.com/?page_id=123 ```

### Image Upload Pipeline ```bash # Full generate+upload (ComfyUI primary, DALL-E 3 fallback) python3 /home/kaburu/.hermes/skills/infrastructure/divi-5-builder/scripts/comfyui-generate.py \

  1. -prompt “professional description of image” \
  2. -output /tmp/hero.png \
  3. -width 1280 –height 720 \
  4. -upload-site l8.kaburu.co.uk \
  5. -alt-text “Image description” \
  6. -title “Image Title”

# Returns: attachment_id + URL ```

### SEO After Page Build ```bash # Set meta python3 /home/kaburu/.hermes/skills/infrastructure/divi-5-builder/scripts/rankmath-seo.py \

set-meta --site kaburu.co --post-id 100 --keyword "keyword" \
--title "SEO Title Here" --description "Meta description here"

# Set schema python3 /home/kaburu/.hermes/skills/infrastructure/divi-5-builder/scripts/rankmath-seo.py \

set-schema --site kaburu.co --post-id 100 --type Service

# Full SEO (all-in-one) python3 /home/kaburu/.hermes/skills/infrastructure/divi-5-builder/scripts/rankmath-seo.py \

full-seo --site kaburu.co --post-id 100 --keyword "keyword" \
--title "SEO Title" --description "Meta desc"

```

### Schema Discovery (Replaces DiviOps Pro) ```python # Get full attribute tree for any module diviops_schema_get_module(module_name=“divi/text”, raw=True) # Returns: boxShadow, filters, transform, sticky, scroll, animation, # transition, zIndex, and every decoration path

# Dump all schemas diviops_schema_get_module(mode=“dump_all”) # Returns every module's schema + schema_version hash ```

### MCP Server Registration (Hermes Config) ```python # CRITICAL: Do NOT use `hermes mcp add` — it mangles multi-arg commands import yaml with open('/home/kaburu/.hermes/config.yaml', 'r') as f:

  config = yaml.safe_load(f)

config['mcp_servers']['diviops-{site-name}'] = {

  'command': 'npx',
  'args': ['-y', '--package', '@diviops/mcp-server', 'diviops-mcp'],
  'env': {
      'WP_URL': 'https://{site-domain}',
      'WP_USER': 'kaburu',
      'WP_APP_PASSWORD': '{password}'
  },
  'enabled': True

}

with open('/home/kaburu/.hermes/config.yaml', 'w') as f:

  yaml.dump(config, f, default_flow_style=False, sort_keys=False)

# Then: hermes mcp test diviops-{site-name} # Then: /reset session — no live reload exists ```

## External References - 16wells Divi 5 Docs: https://16wells.github.io/divi-docs/ - DiviOps GitHub: https://github.com/oaris-dev/diviops - DiviOps npm: `@diviops/mcp-server` - RankWatch API Docs: https://www.rankwatch.com/rwapi/doc.html - OpenLiteSpeed + Wordfence: https://openlitespeed.org/kb/enable-wordfence-on-openlitespeed/