# 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:///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:///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:///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:///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 root@100.112.54.2:/tmp/ # 3. Push to WordPress ssh -i /opt/hermes/config/hetzner_id_ed25519 root@100.112.54.2 ' 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'' def button_block(module_deco, button_obj): obj = { "module": {"decoration": module_deco}, "button": button_obj, "builderVersion": "5.0.3" } return f'' def section_block(module_deco, children): obj = {"module": {"decoration": module_deco}, "builderVersion": "5.0.3"} return f'\n{children}\n' def row_block(module_deco, children): obj = {"module": {"decoration": module_deco}, "builderVersion": "5.0.3"} return f'\n{children}\n' def column_block(module_advanced, module_deco, children): obj = {"module": {"advanced": module_advanced, "decoration": module_deco}, "builderVersion": "5.0.3"} return f'\n{children}\n' # 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": "

New text here

"} ) # 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("//", $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.json # 2. Write as block comment difl_block = '''''' # 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/