# 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 \
- -prompt “professional description of image” \
- -output /tmp/hero.png \
- -width 1280 –height 720 \
- -upload-site l8.kaburu.co.uk \
- -alt-text “Image description” \
- -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/
