Files
advanced-mcp-plugin/docs/05-known-issues.md
T

7.8 KiB

Known Issues & Working Patterns

Critical bugs discovered, diagnosed, and fixed during development. Read before touching Elementor or page builds.


1. ElementorData WP Object Cache Bug (FIXED)

File: includes/Elementor/Data/ElementorData.php

Problem: In long-running PHP CLI scripts, WP object cache caused stale reads. After wp_insert_post(), WP caches _elementor_data as empty. Subsequent update_post_meta() calls write correctly to the DB but get_post_meta() within the same process returns the cached empty value. Each elementor_add_container() call then read the stale empty cache, added one element to an empty array, and overwrote the DB — only ever saving a single-element array instead of accumulating.

Symptom: Page shows 0 root sections after a full build. DB row for _elementor_data is [] or contains only the last element added.

Fix: Both save_page_data() and get_page_data() use raw $wpdb queries — bypassing WP object cache entirely — when PHP_SAPI === 'cli' OR defined('DOING_CRON') && DOING_CRON:

// save_page_data (CLI branch)
$exists = $wpdb->get_var($wpdb->prepare(
    "SELECT meta_id FROM {$table} WHERE post_id=%d AND meta_key='_elementor_data' LIMIT 1",
    $post_id
));
if ($exists) {
    $wpdb->query($wpdb->prepare("UPDATE {$table} SET meta_value=%s WHERE meta_id=%d", $json, (int)$exists));
} else {
    $wpdb->query($wpdb->prepare("INSERT INTO {$table} (post_id, meta_key, meta_value) VALUES (%d, '_elementor_data', %s)", $post_id, $json));
}
wp_cache_delete($post_id, 'post_meta');

// get_page_data (CLI branch)
$raw = $wpdb->get_var($wpdb->prepare(
    "SELECT meta_value FROM {$wpdb->postmeta} WHERE post_id=%d AND meta_key='_elementor_data' LIMIT 1",
    $post_id
));

Rule: Always include define('DOING_CRON', true) at the top of any CLI script that builds Elementor pages.


2. Page Template Validation in CLI (FIXED)

File: includes/Tools/PageTools.php

Problem: Passing page_template to wp_update_post() in CLI context throws WP_Error: Invalid page template. WordPress validates the template slug against registered templates, which only exist during HTTP requests (themes register them on the init hook, which doesn't fully fire in CLI).

Symptom:

Publish error: Invalid page template.

Page status reverts or publish fails when template is set via wp_update_post().

Fix: Never pass page_template to wp_update_post(). Set it via update_post_meta() after the wp_update_post() call:

// WRONG
wp_update_post(['ID' => $pid, 'post_status' => 'publish', 'page_template' => 'elementor-full-width']);

// CORRECT
wp_update_post(['ID' => $pid, 'post_status' => 'publish']);
update_post_meta($pid, '_wp_page_template', 'elementor-full-width');

PageTools.php has this fix applied. The template is set via meta in both createPage() and updatePage().


3. wp_mail / sendmail Not Available in Container (FIXED)

Problem: The mainwp Docker container has no sendmail binary. Any wp_mail() call in CLI context throws a PHP fatal (sendmail process fails).

Fix applied: PHP ini override at /usr/local/etc/php/conf.d/mcp-mail.ini:

sendmail_path = /bin/true

This routes all mail to /dev/null in CLI context. Web requests are unaffected (Apache/PHP-FPM reads the ini on startup).

Also deployed as a mu-plugin: /var/www/html/wp-content/mu-plugins/null_sendmail.php

if (PHP_SAPI === 'cli') {
    ini_set('sendmail_path', '/bin/true');
}

4. Standard CLI Script Header

Every PHP script that bootstraps WordPress for CLI use must include:

<?php
$_SERVER['HTTP_HOST'] = 'mainwp.asktam.net';
$_SERVER['REQUEST_URI'] = '/';
define('WP_ADMIN', true);
define('DOING_CRON', true);   // ← required for ElementorData CLI fix
require '/var/www/html/wp-load.php';

Without DOING_CRON, the ElementorData CLI fix does not activate and data will not accumulate correctly.


5. Calling Tools Directly in Scripts

To call MCP tools from a PHP CLI script:

$reg = new \AskTamMCP\MCP\Registry();
$result = call_user_func($reg->getHandler('tool_name'), ['arg' => 'value']);

Errors thrown by tools are PHP exceptions. Wrap in try/catch if needed:

try {
    $r = call_user_func($reg->getHandler('elementor_add_container'), [
        'post_id'  => $pid,
        'settings' => ['background_color' => '#1e293b'],
    ]);
    $container_id = $r['element_id'];
} catch (\Throwable $e) {
    echo "Error: " . $e->getMessage() . "\n";
}

6. Gitea Commits via Script

The gitea_create_or_update_file MCP tool sends content as a literal string — it does NOT read files from the VPS. Always provide the full file content directly in the content parameter.

For multi-file commits, use a Node.js script that reads files from /tmp/ and calls the Gitea API via HTTPS.


7. Elementor Build — Complete Working Pattern

Full pattern for building a page with Elementor tools from a CLI script:

<?php
$_SERVER['HTTP_HOST'] = 'mainwp.asktam.net';
$_SERVER['REQUEST_URI'] = '/';
define('WP_ADMIN', true);
define('DOING_CRON', true);
require '/var/www/html/wp-load.php';

// Intercept wp_die (optional — turns fatal into exception)
add_filter('wp_die_handler', function() {
    return function($msg, $title='', $args=[]) {
        $m = is_wp_error($msg) ? $msg->get_error_message() : strip_tags((string)$msg);
        throw new \RuntimeException("wp_die: $m");
    };
}, 1);

$reg = new \AskTamMCP\MCP\Registry();

// 1. Create page (draft, no template yet)
$pid = wp_insert_post([
    'post_title'  => 'My Page',
    'post_status' => 'draft',
    'post_type'   => 'page',
    'meta_input'  => ['_elementor_edit_mode' => 'builder'],
]);

// 2. Build with Elementor tools
$hero = call_user_func($reg->getHandler('elementor_add_container'), [
    'post_id'  => $pid,
    'settings' => ['background_color' => '#1e293b', 'min_height' => ['size' => 100, 'unit' => 'vh']],
]);
$hid = $hero['element_id'];

call_user_func($reg->getHandler('elementor_add_heading'), [
    'post_id'      => $pid,
    'container_id' => $hid,
    'title'        => 'Hello World',
    'tag'          => 'h1',
    'settings'     => ['title_color' => '#ffffff'],
]);

// 3. Publish — NO page_template in wp_update_post
wp_update_post(['ID' => $pid, 'post_status' => 'publish']);

// 4. Set template via meta AFTER publish
update_post_meta($pid, '_wp_page_template', 'elementor-full-width');

// 5. Regenerate Elementor CSS
if (class_exists('\Elementor\Core\Files\CSS\Post')) {
    (new \Elementor\Core\Files\CSS\Post($pid))->update();
}

echo "Done: " . get_permalink($pid) . "\n";

8. Test Suite

Two test scripts on VPS at /tmp/:

Script Coverage Expected
test_93.php Original 93 tools 74 OK / 2 test-data errors / 16 safe skips
test_new_tools.php 30 new tools 24 OK / 3 test-data errors / 2 safe skips

Run:

docker cp /tmp/test_93.php mainwp:/tmp/test_93.php
docker exec mainwp php /tmp/test_93.php

"test-data errors" = tools that need real data (an existing order, a real product ID) to test. Not bugs. "safe skips" = destructive tools (delete page content, etc.) skipped intentionally.


9. Key Files to Check Before Making Changes

File Why
includes/Tools/ToolHandlers.php All 123 tools with schemas — check before adding a new tool
includes/MCP/Registry.php How tools are dispatched — check before changing routing
includes/Core/Auth.php Full auth flow — check before changing security
includes/Elementor/Data/ElementorData.php CLI cache fix — do not revert without understanding issue #1
includes/Tools/PageTools.php Template fix — do not pass page_template to wp_update_post
includes/Elementor/Abilities/ElementorTools.php All 30 Elementor tool implementations