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

239 lines
7.8 KiB
Markdown

# 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`:
```php
// 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:
```php
// 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`:
```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`
```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
<?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:
```php
$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:
```php
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
<?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:
```bash
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 |