docs: add known issues and working patterns
This commit is contained in:
@@ -0,0 +1,238 @@
|
|||||||
|
# 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 |
|
||||||
Reference in New Issue
Block a user