PluginProbe
WDesignKit – AI Templates, Widget Builder & MCP Workflow / 2.7.0
WDesignKit – AI Templates, Widget Builder & MCP Workflow v2.7.0
2.7.1 2.7.0 2.6.6 2.6.5 2.6.4 2.6.3 2.6.2 2.6.1 2.6.0 2.5.5 2.5.4 2.5.3 2.5.2 2.5.1 2.5.0 2.4.0 2.3.3 2.3.2 2.3.1 1.0.10 1.0.11 1.0.12 1.0.13 1.0.14 1.0.15 All 130 releases
wdesignkit / includes / abilities / templates / wdesignkit-import-template.php

wdesignkit-import-template.php in WDesignKit – AI Templates, Widget Builder & MCP Workflow 2.7.0, at includes/abilities/templates/wdesignkit-import-template.php

179 lines 8.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Ability: Import a saved/marketplace WDesignKit template's content into the current site.
4 */
5
6 declare(strict_types=1);
7
8 if (!defined('ABSPATH')) {
9 exit();
10 }
11
12 wp_register_ability('wdesignkit/import-template', [
13 'label' => __('Import WDesignKit Template', 'wdesignkit'),
14 'description' => __(
15 'Downloads a saved or marketplace template\'s content from the WDesignKit cloud and returns it for insertion. Set with_dummy_data: true to fetch any post/page/product fixtures bundled with the template. Set custom_meta: true to restore nxt-* post meta onto the current post when the response includes it.',
16 'wdesignkit',
17 ),
18 'category' => 'wdesignkit',
19 'input_schema' => [
20 'type' => 'object',
21 'properties' => [
22 'template_id' => [
23 'type' => 'string',
24 'description' => 'Template ID to import (from wdesignkit/list-templates, wdesignkit/find-template, or wdesignkit/browse-presets).',
25 ],
26 'editor' => [
27 'type' => 'string',
28 'description' => 'Target editor for the imported content.',
29 'enum' => ['elementor', 'gutenberg'],
30 ],
31 'api_type' => [
32 'type' => 'string',
33 'description' => 'Cloud API endpoint variant. Defaults to "import_template". Use "import_kit_template" or similar when targeting a different cloud route.',
34 ],
35 'website_kit' => [
36 'type' => 'string',
37 'description' => 'Optional website kit identifier when importing as part of a full-site kit.',
38 ],
39 'with_dummy_data' => [
40 'type' => 'boolean',
41 'description' => 'When true, asks the cloud to include any dummy posts/products/media bundled with the template. Maps to the "Import Template — Dummy Data" UI action.',
42 ],
43 'custom_meta' => [
44 'type' => 'boolean',
45 'description' => 'When true, restores nxt-* post meta from the response onto the current post (only meaningful when called inside an editor context with a current post).',
46 ],
47 'site_title' => [
48 'type' => 'string',
49 'description' => 'Destination site name. Passed to the cloud for personalisation.',
50 ],
51 'site_description' => [
52 'type' => 'string',
53 'description' => 'Short description of the destination site. Passed to the cloud for personalisation.',
54 ],
55 'site_type' => [
56 'type' => 'string',
57 'description' => 'Industry / vertical of the destination site (e.g. "saas", "restaurant"). Passed to the cloud for personalisation.',
58 ],
59 'global_colors' => [
60 'type' => 'string',
61 'description' => 'JSON-encoded global colour palette override to apply to the imported template.',
62 ],
63 'global_typography' => [
64 'type' => 'string',
65 'description' => 'JSON-encoded global typography settings override to apply to the imported template.',
66 ],
67 'plugins' => [
68 'type' => 'string',
69 'description' => 'JSON-encoded array of required plugin slugs for this template. Sent to the cloud for compatibility checks.',
70 ],
71 ],
72 'required' => ['template_id'],
73 'additionalProperties' => false,
74 ],
75 'output_schema' => [
76 'type' => 'object',
77 'properties' => [
78 'success' => ['type' => 'boolean'],
79 'message' => ['type' => 'string'],
80 'response' => ['type' => ['object', 'array']],
81 ],
82 ],
83 'execute_callback' => 'wdesignkit_mcp_import_template',
84 'permission_callback' => 'wdesignkit_mcp_permission_callback',
85 'meta' => [
86 'public' => true,
87 'show_in_rest' => true,
88 'mcp' => ['public' => true],
89 'annotations' => [
90 'instructions' => implode("\n", [
91 'Imports a template\'s content (returns it; insertion into a builder must be done by the caller).',
92 'Requires WDesignKit cloud login.',
93 'with_dummy_data covers the "Import Template — Dummy Data" flow; the corresponding "Import Template — AI Import" flow lives in wdesignkit/ai-import-template.',
94 'custom_meta only takes effect when a current post context exists (e.g. running inside an editor request).',
95 ]),
96 'readonly' => false,
97 'destructive' => false,
98 'idempotent' => true,
99 ],
100 ],
101 ]);
102
103 function wdesignkit_mcp_import_template(array $input): array {
104 set_time_limit(90);
105
106 $auth = wdesignkit_mcp_template_get_auth();
107 if (empty($auth['logged_in'])) {
108 return ['success' => false, 'message' => $auth['message'] ?? 'Not logged in.'];
109 }
110
111 $template_id = sanitize_text_field((string) ($input['template_id'] ?? ''));
112 if ($template_id === '') {
113 return ['success' => false, 'message' => 'template_id is required.'];
114 }
115
116 $api_type = sanitize_text_field((string) ($input['api_type'] ?? 'import_template'));
117 $editor = sanitize_text_field((string) ($input['editor'] ?? ''));
118 $website_kit = sanitize_text_field((string) ($input['website_kit'] ?? ''));
119 $with_dummy_data = !empty($input['with_dummy_data']);
120 $custom_meta = !empty($input['custom_meta']);
121 $site_title = sanitize_text_field((string) ($input['site_title'] ?? ''));
122 $site_description = sanitize_text_field((string) ($input['site_description'] ?? ''));
123 $site_type = sanitize_text_field((string) ($input['site_type'] ?? ''));
124 $global_colors = (string) ($input['global_colors'] ?? '');
125 $global_typography = (string) ($input['global_typography'] ?? '');
126 $plugins = (string) ($input['plugins'] ?? '');
127
128 $args = [
129 'token' => $auth['token'],
130 'template_id' => $template_id,
131 'editor' => $editor,
132 'website_kit' => $website_kit,
133 'unique_id' => get_option('wdkit_unique_id', ''),
134 'dummy_data' => $with_dummy_data ? 'yes' : 'no',
135 'with_dummy_data' => $with_dummy_data,
136 'site_title' => $site_title,
137 'site_desc' => $site_description,
138 'site_type' => $site_type,
139 'global_colors' => $global_colors,
140 'global_typography' => $global_typography,
141 'plugins' => $plugins,
142 ];
143
144 $response = wdesignkit_mcp_template_cloud_call($api_type, $args, 'json');
145
146 if ($custom_meta && !empty($response['content'])) {
147 $current_post_id = get_the_ID();
148 $decoded = json_decode((string) $response['content'], true);
149
150 if ($current_post_id && is_array($decoded) && !empty($decoded['custom_meta'])) {
151 foreach ($decoded['custom_meta'] as $meta_key => $meta_val) {
152 $value = $meta_val[0] ?? null;
153 if (is_string($value) && is_serialized($value)) {
154 // allowed_classes => false: $value comes from the imported template body, so a
155 // serialized object here would be instantiated and could fire a POP gadget
156 // chain in any loaded plugin or theme (CWE-502, ClickUp 86d41zauw).
157 //
158 // maybe_unserialize() cannot express this — WP core declares it as
159 // maybe_unserialize( $data ) and calls @unserialize( trim( $data ) ) with no
160 // options, so an options array passed to it is silently ignored. The
161 // is_serialized() check above already gates this call.
162 $value = unserialize($value, ['allowed_classes' => false]);
163 }
164 if (get_post_meta($current_post_id, $meta_key, true) === '') {
165 add_post_meta($current_post_id, $meta_key, $value);
166 } else {
167 update_post_meta($current_post_id, $meta_key, $value);
168 }
169 }
170 }
171 }
172
173 return [
174 'success' => (bool) ($response['success'] ?? !empty($response['content'])),
175 'message' => $response['message'] ?? '',
176 'response' => $response,
177 ];
178 }
179