Files
advanced-mcp-plugin/includes/Extensions/Batch9.php
T

127 lines
6.9 KiB
PHP

<?php
/**
* Batch 9 — Backup / export / portability (Pro-equivalent, net-new).
*
* Export & import Elementor page data and global styles, and duplicate pages.
* Elementor-only (inert without it). GPL-2.0-or-later. See NOTICE.md.
* Registered via the asktam_mcp_register_tools hook (glob auto-loader).
*/
namespace AskTamMCP\Extensions;
defined('ABSPATH') || exit;
class Batch9 {
public static function register($registry): void {
if (!defined('ELEMENTOR_VERSION')) return; // Elementor-only batch.
$def = function (string $name, string $desc, array $props, array $required, string $scope, string $method) {
$schema = ['type' => 'object', 'properties' => $props];
if ($required) $schema['required'] = $required;
return ['name' => $name, 'description' => $desc, 'scope' => $scope,
'handler' => 'AskTamMCP\\Extensions\\Batch9::' . $method, 'inputSchema' => $schema];
};
$registry->register($def('export_elementor_page', 'Export a page\'s Elementor data: parsed elements, page settings, and template. Use as a backup or to clone into another page.',
['post_id' => ['type' => 'integer']], ['post_id'], 'read', 'exportPage'));
$registry->register($def('import_elementor_page', 'Import Elementor data into a target post. Provide elementor_data (JSON string or array). regenerate_ids=true gives every element a fresh id.',
['post_id' => ['type' => 'integer'], 'elementor_data' => ['type' => ['array', 'string']], 'regenerate_ids' => ['type' => 'boolean', 'default' => false]],
['post_id', 'elementor_data'], 'write', 'importPage'));
$registry->register($def('export_global_styles', 'Export the active Elementor kit\'s global styles (colors, typography, and other page settings).', [], [], 'read', 'exportStyles'));
$registry->register($def('import_global_styles', 'Write global styles into the active Elementor kit. merge=true (default) merges into existing settings; false replaces them.',
['settings' => ['type' => 'object'], 'merge' => ['type' => 'boolean', 'default' => true]],
['settings'], 'write', 'importStyles'));
$registry->register($def('duplicate_elementor_page', 'Duplicate a page including its Elementor data into a new post (default draft).',
['source_id' => ['type' => 'integer'], 'title' => ['type' => 'string'], 'status' => ['type' => 'string', 'default' => 'draft']],
['source_id'], 'write', 'duplicatePage'));
}
private static function regenerateIds(array $elements): array {
foreach ($elements as &$el) {
if (isset($el['id'])) $el['id'] = substr(md5(uniqid('', true)), 0, 7);
if (!empty($el['elements']) && is_array($el['elements'])) $el['elements'] = self::regenerateIds($el['elements']);
}
unset($el);
return $elements;
}
public static function exportPage(array $args): array {
$id = (int) ($args['post_id'] ?? 0);
$post = $id ? get_post($id) : null;
if (!$post) throw new \RuntimeException("Post not found: {$id}");
$raw = get_post_meta($id, '_elementor_data', true);
$data = is_string($raw) && $raw !== '' ? json_decode($raw, true) : [];
return [
'post_id' => $id,
'title' => $post->post_title,
'template' => get_post_meta($id, '_wp_page_template', true),
'page_settings' => get_post_meta($id, '_elementor_page_settings', true) ?: [],
'elementor_data' => is_array($data) ? $data : [],
'element_count' => is_array($data) ? count($data) : 0,
];
}
public static function importPage(array $args): array {
$id = (int) ($args['post_id'] ?? 0);
$post = $id ? get_post($id) : null;
if (!$post) throw new \RuntimeException("Post not found: {$id}");
$data = $args['elementor_data'] ?? null;
if (is_string($data)) $data = json_decode($data, true);
if (!is_array($data)) throw new \RuntimeException('elementor_data must be a JSON array/string of elements.');
if (!empty($args['regenerate_ids'])) $data = self::regenerateIds($data);
$json = wp_json_encode($data);
update_post_meta($id, '_elementor_data', wp_slash($json));
update_post_meta($id, '_elementor_edit_mode', 'builder');
if (defined('ELEMENTOR_VERSION')) update_post_meta($id, '_elementor_version', ELEMENTOR_VERSION);
if (class_exists('\Elementor\Plugin')) {
try { \Elementor\Plugin::$instance->files_manager->clear_cache(); } catch (\Throwable $e) {}
}
return ['post_id' => $id, 'elements_imported' => count($data), 'regenerated_ids' => !empty($args['regenerate_ids'])];
}
private static function activeKit(): int {
return (int) get_option('elementor_active_kit', 0);
}
public static function exportStyles(array $args): array {
$kit = self::activeKit();
if (!$kit) throw new \RuntimeException('No active Elementor kit.');
return ['kit_id' => $kit, 'settings' => get_post_meta($kit, '_elementor_page_settings', true) ?: []];
}
public static function importStyles(array $args): array {
$kit = self::activeKit();
if (!$kit) throw new \RuntimeException('No active Elementor kit.');
$incoming = is_array($args['settings'] ?? null) ? $args['settings'] : [];
if (!$incoming) throw new \RuntimeException('settings (object) is required.');
$merge = !isset($args['merge']) || !empty($args['merge']);
$current = get_post_meta($kit, '_elementor_page_settings', true) ?: [];
$new = $merge ? array_merge((array) $current, $incoming) : $incoming;
update_post_meta($kit, '_elementor_page_settings', $new);
return ['kit_id' => $kit, 'merged' => $merge, 'keys_written' => array_keys($incoming)];
}
public static function duplicatePage(array $args): array {
$src = (int) ($args['source_id'] ?? 0);
$post = $src ? get_post($src) : null;
if (!$post) throw new \RuntimeException("Source post not found: {$src}");
$title = sanitize_text_field((string) ($args['title'] ?? ($post->post_title . ' (copy)')));
$status = in_array(($args['status'] ?? 'draft'), ['draft', 'publish', 'pending', 'private'], true) ? $args['status'] : 'draft';
$new = wp_insert_post([
'post_title' => $title, 'post_status' => $status, 'post_type' => $post->post_type,
'post_content' => $post->post_content,
], true);
if (is_wp_error($new)) throw new \RuntimeException($new->get_error_message());
foreach (['_elementor_data', '_elementor_page_settings', '_wp_page_template', '_elementor_edit_mode', '_elementor_version'] as $k) {
$v = get_post_meta($src, $k, true);
if ($v !== '') update_post_meta($new, $k, is_string($v) ? wp_slash($v) : $v);
}
return ['new_post_id' => (int) $new, 'source_id' => $src, 'title' => $title, 'status' => $status];
}
}