From 53825f5bfe4412d223656602fc0325afef4cd1cf Mon Sep 17 00:00:00 2001 From: colorlink Date: Thu, 15 Oct 2026 17:42:04 +0000 Subject: [PATCH] feat(batch1): net-new Elementor completeness tools (section, column, global font, delete color/template) via extension hook --- includes/Extensions/Batch1.php | 148 +++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 includes/Extensions/Batch1.php diff --git a/includes/Extensions/Batch1.php b/includes/Extensions/Batch1.php new file mode 100644 index 0000000..14c5017 --- /dev/null +++ b/includes/Extensions/Batch1.php @@ -0,0 +1,148 @@ + 'object', 'properties' => $props]; + if ($required) $schema['required'] = $required; + return ['name' => $name, 'description' => $desc, 'scope' => $scope, + 'handler' => 'AskTamMCP\\Extensions\\Batch1::' . $method, 'inputSchema' => $schema]; + }; + + $registry->register($def('elementor_add_section', + 'Add a classic Elementor section (legacy row layout). Optional parent_id nests it; settings accepts gap, content_width, background_color, padding, etc.', + ['post_id' => ['type' => 'integer'], 'parent_id' => ['type' => 'string'], 'position' => ['type' => 'integer'], 'settings' => ['type' => 'object']], + ['post_id'], 'write', 'addSection')); + + $registry->register($def('elementor_add_column', + 'Add a column inside a section. size is the column width in percent (1-100, default 100).', + ['post_id' => ['type' => 'integer'], 'section_id' => ['type' => 'string'], 'size' => ['type' => 'integer', 'default' => 100], 'position' => ['type' => 'integer'], 'settings' => ['type' => 'object']], + ['post_id', 'section_id'], 'write', 'addColumn')); + + $registry->register($def('elementor_set_global_font', + 'Add or update a typography entry in the Elementor global font palette (system_typography).', + ['id' => ['type' => 'string'], 'title' => ['type' => 'string'], 'font_family' => ['type' => 'string'], 'font_weight' => ['type' => 'string']], + ['title', 'font_family'], 'write', 'setGlobalFont')); + + $registry->register($def('elementor_delete_global_color', + 'Remove a colour from the Elementor global palette by its id.', + ['id' => ['type' => 'string']], + ['id'], 'write', 'deleteGlobalColor')); + + $registry->register($def('elementor_delete_template', + 'Delete a saved Elementor library template permanently.', + ['template_id' => ['type' => 'integer']], + ['template_id'], 'write', 'deleteTemplate')); + } + + private static function data(): \AskTamMCP\Elementor\Data\ElementorData { + return new \AskTamMCP\Elementor\Data\ElementorData(); + } + + private static function activeKitId(): int { + return (int) get_option('elementor_active_kit', 0); + } + + public static function addSection(array $args): array { + $post_id = (int) ($args['post_id'] ?? 0); + $parent_id = $args['parent_id'] ?? ''; + $position = (int) ($args['position'] ?? -1); + $settings = is_array($args['settings'] ?? null) ? $args['settings'] : []; + $ed = self::data(); + $data = $ed->get_page_data($post_id); + if (is_wp_error($data)) throw new \RuntimeException($data->get_error_message()); + $id = $ed->generate_id(); + $section = ['id' => $id, 'elType' => 'section', 'settings' => $settings, 'elements' => [], 'isInner' => !empty($parent_id)]; + $ed->insert_element($data, $parent_id, $section, $position); + $saved = $ed->save_page_data($post_id, $data); + if (is_wp_error($saved)) throw new \RuntimeException($saved->get_error_message()); + return ['element_id' => $id, 'post_id' => $post_id]; + } + + public static function addColumn(array $args): array { + $post_id = (int) ($args['post_id'] ?? 0); + $section_id = $args['section_id'] ?? ''; + $size = max(1, min(100, (int) ($args['size'] ?? 100))); + $position = (int) ($args['position'] ?? -1); + $settings = is_array($args['settings'] ?? null) ? $args['settings'] : []; + if (empty($section_id)) throw new \RuntimeException('section_id is required.'); + $ed = self::data(); + $data = $ed->get_page_data($post_id); + if (is_wp_error($data)) throw new \RuntimeException($data->get_error_message()); + $id = $ed->generate_id(); + $column = ['id' => $id, 'elType' => 'column', + 'settings' => array_merge(['_column_size' => $size, '_inline_size' => $size], $settings), + 'elements' => [], 'isInner' => false]; + $ok = $ed->insert_element($data, $section_id, $column, $position); + if (!$ok) throw new \RuntimeException("Section not found: {$section_id}"); + $saved = $ed->save_page_data($post_id, $data); + if (is_wp_error($saved)) throw new \RuntimeException($saved->get_error_message()); + return ['element_id' => $id, 'post_id' => $post_id, 'section_id' => $section_id]; + } + + public static function setGlobalFont(array $args): array { + $kit = self::activeKitId(); + if (!$kit) throw new \RuntimeException('No active Elementor kit found.'); + $s = get_post_meta($kit, '_elementor_page_settings', true) ?: []; + $fonts = $s['system_typography'] ?? []; + $id = $args['id'] ?? ('font_' . substr(md5(($args['title'] ?? '') . uniqid()), 0, 6)); + $entry = [ + '_id' => $id, + 'title' => $args['title'] ?? $id, + 'typography_typography' => 'custom', + 'typography_font_family' => $args['font_family'] ?? '', + 'typography_font_weight' => $args['font_weight'] ?? '', + ]; + $found = false; + foreach ($fonts as &$f) { + if (($f['_id'] ?? '') === $id) { $f = array_merge($f, $entry); $found = true; break; } + } + unset($f); + if (!$found) $fonts[] = $entry; + $s['system_typography'] = $fonts; + update_post_meta($kit, '_elementor_page_settings', $s); + return ['success' => true, 'id' => $id, 'kit_id' => $kit]; + } + + public static function deleteGlobalColor(array $args): array { + $kit = self::activeKitId(); + if (!$kit) throw new \RuntimeException('No active Elementor kit found.'); + $id = (string) ($args['id'] ?? ''); + $s = get_post_meta($kit, '_elementor_page_settings', true) ?: []; + $colors = $s['system_colors'] ?? []; + $before = count($colors); + $colors = array_values(array_filter($colors, fn($c) => ($c['_id'] ?? '') !== $id)); + if (count($colors) === $before) throw new \RuntimeException("Global colour not found: {$id}"); + $s['system_colors'] = $colors; + update_post_meta($kit, '_elementor_page_settings', $s); + return ['success' => true, 'deleted_id' => $id, 'kit_id' => $kit]; + } + + public static function deleteTemplate(array $args): array { + $tid = (int) ($args['template_id'] ?? 0); + $p = $tid ? get_post($tid) : null; + if (!$p || $p->post_type !== 'elementor_library') { + throw new \RuntimeException("Not an Elementor template: {$tid}"); + } + $res = wp_delete_post($tid, true); + if (!$res) throw new \RuntimeException("Failed to delete template {$tid}"); + return ['success' => true, 'deleted_template_id' => $tid]; + } +}