From 1907f4b1897465829b83f52d2397d5a926ad2f82 Mon Sep 17 00:00:00 2001 From: colorlink Date: Fri, 16 Oct 2026 02:06:12 +0000 Subject: [PATCH] =?UTF-8?q?feat(batch13):=20Woodmart=20functionality=20?= =?UTF-8?q?=E2=80=94=20widgets,=20layout=20builder,=20HTML=20blocks=20(lis?= =?UTF-8?q?t/get/create)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01Q8t9GEyyLZbUQu26na1JQg --- includes/Extensions/Batch13.php | 146 ++++++++++++++++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 includes/Extensions/Batch13.php diff --git a/includes/Extensions/Batch13.php b/includes/Extensions/Batch13.php new file mode 100644 index 0000000..aefb220 --- /dev/null +++ b/includes/Extensions/Batch13.php @@ -0,0 +1,146 @@ + 'object', 'properties' => $props]; + if ($required) $schema['required'] = $required; + return ['name' => $name, 'description' => $desc, 'scope' => $scope, + 'handler' => 'AskTamMCP\\Extensions\\Batch13::' . $method, 'inputSchema' => $schema]; + }; + + $registry->register($def('woodmart_list_widgets', 'List Woodmart Elementor widgets (wd_* and Woodmart WP widgets) with name and title. group = wd | wp | all (default all).', + ['group' => ['type' => 'string', 'enum' => ['wd', 'wp', 'all']]], [], 'read', 'listWidgets')); + + $registry->register($def('woodmart_list_layouts', 'List Woodmart Layout Builder entries (woodmart_layout CPT: headers, footers, page/shop layouts). Returns id, title, status, and the meta keys present on each.', + ['status' => ['type' => 'string'], 'per_page' => ['type' => 'integer', 'default' => 50]], [], 'read', 'listLayouts')); + + $registry->register($def('woodmart_list_html_blocks', 'List Woodmart HTML Blocks (cms_block CPT), each with its id, title, status, and ready-to-use shortcode.', + ['status' => ['type' => 'string'], 'per_page' => ['type' => 'integer', 'default' => 50]], [], 'read', 'listBlocks')); + + $registry->register($def('woodmart_get_block', 'Get one Woodmart HTML Block or Layout by id: title, status, whether it is Elementor-built, a content/length summary, and its shortcode.', + ['id' => ['type' => 'integer']], ['id'], 'read', 'getBlock')); + + $registry->register($def('woodmart_create_html_block', 'Create a Woodmart HTML Block (cms_block). Returns the new id and its [woodmart_html_block] shortcode. content is classic HTML/shortcode markup; status defaults to publish.', + ['title' => ['type' => 'string'], 'content' => ['type' => 'string'], 'status' => ['type' => 'string', 'enum' => ['publish', 'draft']]], ['title'], 'write', 'createBlock')); + } + + private static function isWoodmart(): bool { + if (function_exists('woodmart_get_opt')) return true; + $t = wp_get_theme(); + $cands = [$t->get('TextDomain'), $t->get_template(), strtolower((string) $t->get('Name'))]; + return in_array('woodmart', array_map('strtolower', array_filter($cands)), true); + } + + public static function listWidgets(array $args): array { + $group = isset($args['group']) ? (string) $args['group'] : 'all'; + if (!class_exists('\Elementor\Plugin')) { + throw new \RuntimeException('Elementor is not active; Woodmart Elementor widgets are unavailable.'); + } + $types = \Elementor\Plugin::instance()->widgets_manager->get_widget_types(); + $out = []; + foreach ($types as $name => $w) { + $isWd = strpos($name, 'wd_') === 0 || strpos($name, 'woodmart') !== false; + $isWpWd = strpos($name, 'wp-widget-woodmart') === 0; + if (!$isWd && !$isWpWd) continue; + $kind = $isWpWd ? 'wp' : 'wd'; + if ($group !== 'all' && $group !== $kind) continue; + $title = ''; + if (is_object($w) && method_exists($w, 'get_title')) { try { $title = (string) $w->get_title(); } catch (\Throwable $e) {} } + $out[] = ['name' => $name, 'title' => $title, 'kind' => $kind]; + } + usort($out, fn($a, $b) => strcmp($a['name'], $b['name'])); + return ['count' => count($out), 'widgets' => $out]; + } + + private static function queryCpt(string $cpt, array $args): array { + $q = get_posts([ + 'post_type' => $cpt, + 'post_status' => isset($args['status']) ? (string) $args['status'] : ['publish', 'draft', 'pending', 'private'], + 'numberposts' => (int) ($args['per_page'] ?? 50), + 'orderby' => 'date', + 'order' => 'DESC', + ]); + return is_array($q) ? $q : []; + } + + public static function listLayouts(array $args): array { + if (!post_type_exists('woodmart_layout')) { + return ['supported' => false, 'note' => 'woodmart_layout CPT not registered on this site.', 'count' => 0, 'layouts' => []]; + } + $posts = self::queryCpt('woodmart_layout', $args); + $out = []; + foreach ($posts as $p) { + $meta = get_post_meta($p->ID); + $keys = array_values(array_filter(array_keys($meta), fn($k) => $k !== '' && strpos($k, '_edit') !== 0)); + $out[] = ['id' => $p->ID, 'title' => $p->post_title, 'status' => $p->post_status, 'meta_keys' => $keys]; + } + return ['supported' => true, 'count' => count($out), 'layouts' => $out]; + } + + public static function listBlocks(array $args): array { + if (!post_type_exists('cms_block')) { + return ['supported' => false, 'note' => 'cms_block CPT not registered on this site.', 'count' => 0, 'blocks' => []]; + } + $posts = self::queryCpt('cms_block', $args); + $out = []; + foreach ($posts as $p) { + $out[] = [ + 'id' => $p->ID, 'title' => $p->post_title, 'status' => $p->post_status, + 'shortcode' => '[woodmart_html_block id="' . $p->ID . '"]', + ]; + } + return ['supported' => true, 'count' => count($out), 'blocks' => $out]; + } + + public static function getBlock(array $args): array { + $id = (int) ($args['id'] ?? 0); + $p = get_post($id); + if (!$p) throw new \RuntimeException('Post not found: ' . $id); + $isElementor = get_post_meta($id, '_elementor_edit_mode', true) === 'builder'; + $content = (string) $p->post_content; + $shortcode = $p->post_type === 'cms_block' ? '[woodmart_html_block id="' . $id . '"]' : null; + return [ + 'id' => $id, + 'post_type' => $p->post_type, + 'title' => $p->post_title, + 'status' => $p->post_status, + 'elementor_built' => $isElementor, + 'content_length' => strlen($content), + 'content_preview' => mb_substr(wp_strip_all_tags($content), 0, 300), + 'shortcode' => $shortcode, + ]; + } + + public static function createBlock(array $args): array { + if (!post_type_exists('cms_block')) { + throw new \RuntimeException('cms_block CPT not registered; Woodmart HTML Blocks unavailable on this site.'); + } + $title = trim((string) ($args['title'] ?? '')); + if ($title === '') throw new \RuntimeException('title required.'); + $status = ($args['status'] ?? 'publish') === 'draft' ? 'draft' : 'publish'; + $id = wp_insert_post([ + 'post_type' => 'cms_block', + 'post_title' => $title, + 'post_content' => (string) ($args['content'] ?? ''), + 'post_status' => $status, + ], true); + if (is_wp_error($id)) throw new \RuntimeException('Create failed: ' . $id->get_error_message()); + return ['id' => $id, 'title' => $title, 'status' => $status, 'shortcode' => '[woodmart_html_block id="' . $id . '"]']; + } +}