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 |