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 / code-snippets / wdesignkit-download-snippet.php

wdesignkit-download-snippet.php in WDesignKit – AI Templates, Widget Builder & MCP Workflow 2.7.0, at includes/abilities/code-snippets/wdesignkit-download-snippet.php

281 lines 12.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Ability: Download and install a WDesignKit marketplace snippet to the local WordPress site.
4 */
5
6 declare(strict_types=1);
7
8 if (!defined('ABSPATH')) {
9 exit();
10 }
11
12 wp_register_ability('wdesignkit/download-snippet', [
13 'label' => __('Download WDesignKit Marketplace Snippet', 'wdesignkit'),
14 'description' => __(
15 'Downloads a code snippet from the WDesignKit marketplace and installs it as a local nxt-code-snippet WordPress post. Free snippets do not require login; pro snippets require cloud login and an active licence. Returns the new post ID on success.',
16 'wdesignkit',
17 ),
18 'category' => 'wdesignkit',
19 'input_schema' => [
20 'type' => 'object',
21 'properties' => [
22 'snippet_id' => [
23 'type' => 'string',
24 'description' => 'Cloud snippet ID to download (the "id" field from wdesignkit/browse-snippets response).',
25 ],
26 'w_unique' => [
27 'type' => 'string',
28 'description' => 'Unique identifier for the snippet (the "w_unique" field from wdesignkit/browse-snippets response).',
29 ],
30 'free_pro' => [
31 'type' => 'string',
32 'description' => '"free" for free snippets (no login needed), "pro" for pro snippets (requires login and active licence).',
33 'enum' => ['free', 'pro'],
34 ],
35 ],
36 'required' => ['snippet_id'],
37 'additionalProperties' => false,
38 ],
39 'output_schema' => [
40 'type' => 'object',
41 'properties' => [
42 'success' => ['type' => 'boolean'],
43 'message' => ['type' => 'string'],
44 'post_id' => ['type' => ['integer', 'null']],
45 'file_id' => ['type' => ['string', 'null']],
46 'name' => ['type' => ['string', 'null']],
47 'response' => ['type' => ['object', 'array']],
48 ],
49 ],
50 'execute_callback' => 'wdesignkit_mcp_download_snippet',
51 'permission_callback' => 'wdesignkit_mcp_permission_callback',
52 'meta' => [
53 'public' => true,
54 'show_in_rest' => true,
55 'mcp' => ['public' => true],
56 'annotations' => [
57 'instructions' => implode("\n", [
58 'Downloads a snippet from the WDesignKit marketplace and installs it locally.',
59 'Get snippet_id and w_unique from wdesignkit/browse-snippets.',
60 'free_pro "free": no login required. free_pro "pro": cloud login + active licence required.',
61 'Storage type depends on the active plugin: file-based (Nexter Pro) returns file_id (string) and post_id=null; legacy post-based returns post_id (integer) and file_id=null.',
62 'Use wdesignkit/list-local-snippets to see all installed snippets and their IDs after download.',
63 'Use wdesignkit/get-snippet-info with file_id (file-based) or post_id (post-based) to inspect the downloaded snippet.',
64 ]),
65 'readonly' => false,
66 'destructive' => false,
67 'idempotent' => false,
68 ],
69 ],
70 ]);
71
72 function wdesignkit_mcp_download_snippet(array $input): array {
73 // Timeout guard: cloud download call + optional local DB writes.
74 set_time_limit(90);
75
76 if (!defined('WDKIT_SERVER_API_URL')) {
77 return ['success' => false, 'message' => 'WDesignKit plugin is not active.'];
78 }
79
80 $snippet_id = sanitize_text_field((string) ($input['snippet_id'] ?? ''));
81 $w_unique = sanitize_text_field((string) ($input['w_unique'] ?? ''));
82 $free_pro = sanitize_text_field((string) ($input['free_pro'] ?? 'free'));
83
84 if ($snippet_id === '') {
85 return ['success' => false, 'message' => 'snippet_id is required.'];
86 }
87
88 $array_data = [
89 'id' => $snippet_id,
90 'unique_id' => (string) get_option('wdkit_unique_id', ''),
91 ];
92
93 // Pro snippets require login
94 if ($free_pro === 'pro') {
95 $auth = wdesignkit_mcp_template_get_auth();
96 if (empty($auth['logged_in'])) {
97 return ['success' => false, 'message' => $auth['message'] ?? 'Cloud login required for pro snippets.'];
98 }
99 $array_data['token'] = $auth['token'];
100
101 // Indicate Nexter Pro is active if available
102 if (defined('NXT_PRO_EXT') && class_exists('Nexter_Pro_Ext_Activate')) {
103 $array_data['pro_active'] = 'yes';
104 }
105
106 $endpoint = 'snippet/import';
107 } else {
108 $endpoint = 'snippet/import/free';
109 }
110
111 $cloud = wdesignkit_mcp_template_cloud_call($endpoint, $array_data, 'form');
112
113 if (empty($cloud['success'])) {
114 return [
115 'success' => false,
116 'message' => $cloud['message'] ?? $cloud['massage'] ?? 'Failed to download snippet from server.',
117 'post_id' => null,
118 'file_id' => null,
119 'name' => null,
120 'response' => $cloud,
121 ];
122 }
123
124 if (isset($cloud['data']) && $cloud['data'] === 'error') {
125 return [
126 'success' => false,
127 'message' => $cloud['message'] ?? 'Server returned an error.',
128 'post_id' => null,
129 'file_id' => null,
130 'name' => null,
131 'response' => $cloud,
132 ];
133 }
134
135 $content = $cloud['content'] ?? null;
136 if (empty($content)) {
137 return [
138 'success' => false,
139 'message' => 'No snippet content received from server.',
140 'post_id' => null,
141 'file_id' => null,
142 'name' => null,
143 'response' => $cloud,
144 ];
145 }
146
147 $json = json_decode((string) $content, true);
148 if (!$json || empty($json['snippets']) || !is_array($json['snippets'])) {
149 return [
150 'success' => false,
151 'message' => 'Invalid snippet file received from server.',
152 'post_id' => null,
153 'file_id' => null,
154 'name' => null,
155 'response' => $cloud,
156 ];
157 }
158
159 $snippet = $json['snippets'][0];
160
161 if (empty($snippet['post_type']) || $snippet['post_type'] !== 'nxt-code-snippet') {
162 return [
163 'success' => false,
164 'message' => 'Invalid snippet type in downloaded content.',
165 'post_id' => null,
166 'file_id' => null,
167 'name' => null,
168 'response' => $cloud,
169 ];
170 }
171
172 // Try file-based import via hook (Nexter Pro)
173 $file_based = null;
174 $import_result = null;
175
176 if (class_exists('Nexter_Code_Snippets_File_Based')) {
177 $file_based = new \Nexter_Code_Snippets_File_Based();
178 $import_result = apply_filters('nexter_before_import_snippet_file_based', null, $snippet, $file_based);
179 }
180
181 if ($import_result === null && class_exists('Nexter_Builder_Code_Snippets_Render')) {
182 $render = \Nexter_Builder_Code_Snippets_Render::get_instance();
183 if (method_exists($render, 'import_single_snippet_file_based')) {
184 $import_result = $render->import_single_snippet_file_based($snippet, $file_based);
185 }
186 }
187
188 if (is_wp_error($import_result)) {
189 return [
190 'success' => false,
191 'message' => $import_result->get_error_message(),
192 'post_id' => null,
193 'file_id' => null,
194 'name' => null,
195 'response' => $cloud,
196 ];
197 }
198
199 if (isset($import_result['success']) && $import_result['success']) {
200 if ($file_based && method_exists($file_based, 'snippetIndexData')) {
201 $file_based->snippetIndexData();
202 }
203 // import_single_snippet_file_based returns id = filename-without-.php (string file key),
204 // NOT a WordPress post ID. Convert any scalar (including integers) to string so
205 // callers can always pass file_id to wdesignkit/get-snippet-info and wdesignkit/save-snippet.
206 $raw_id = $import_result['id'] ?? null;
207 $file_id = ($raw_id !== null && $raw_id !== '' && $raw_id !== false)
208 ? (string) $raw_id
209 : null;
210 return [
211 'success' => true,
212 'message' => 'Snippet downloaded and installed (file-based). Use file_id with wdesignkit/get-snippet-info and wdesignkit/save-snippet.',
213 'post_id' => null,
214 'file_id' => $file_id,
215 'name' => $import_result['name'] ?? null,
216 'response' => $cloud,
217 ];
218 }
219
220 // Fallback: post-based insert
221 $snippet_name = sanitize_text_field(html_entity_decode((string) ($snippet['name'] ?? 'Snippet')));
222 $post_id = wp_insert_post([
223 'post_title' => $snippet_name,
224 'post_type' => 'nxt-code-snippet',
225 'post_status' => 'publish',
226 ]);
227
228 if (is_wp_error($post_id)) {
229 return [
230 'success' => false,
231 'message' => $post_id->get_error_message(),
232 'post_id' => null,
233 'file_id' => null,
234 'name' => null,
235 'response' => $cloud,
236 ];
237 }
238
239 $type = sanitize_text_field((string) ($snippet['type'] ?? ''));
240 $tags = isset($snippet['tags'])
241 ? array_map('sanitize_text_field', is_array($snippet['tags']) ? $snippet['tags'] : explode(',', (string) $snippet['tags']))
242 : [];
243
244 update_post_meta($post_id, 'nxt-code-type', $type);
245 update_post_meta($post_id, 'nxt-code-note', sanitize_text_field((string) ($snippet['description'] ?? '')));
246 update_post_meta($post_id, 'nxt-code-tags', $tags);
247 update_post_meta($post_id, 'nxt-code-execute', sanitize_text_field((string) ($snippet['codeExecute'] ?? '')));
248 update_post_meta($post_id, 'nxt-code-status', (int) ($snippet['status'] ?? 0));
249 update_post_meta($post_id, 'nxt-' . $type . '-code', wp_unslash((string) ($snippet['langCode'] ?? '')));
250 update_post_meta($post_id, 'nxt-code-html-hooks', wp_unslash((string) ($snippet['htmlHooks'] ?? '')));
251 update_post_meta($post_id, 'nxt-code-hooks-priority', sanitize_text_field((string) ($snippet['hooksPriority'] ?? '')));
252 update_post_meta($post_id, 'nxt-add-display-rule', sanitize_text_field((string) ($snippet['include_data'] ?? '')));
253 update_post_meta($post_id, 'nxt-exclude-display-rule', sanitize_text_field((string) ($snippet['exclude_data'] ?? '')));
254 update_post_meta($post_id, 'nxt-in-sub-rule', sanitize_text_field((string) ($snippet['in_sub_data'] ?? '')));
255 update_post_meta($post_id, 'nxt-ex-sub-rule', sanitize_text_field((string) ($snippet['ex_sub_data'] ?? '')));
256 update_post_meta($post_id, 'nxt-insert-word-count', sanitize_text_field((string) ($snippet['word_count'] ?? 100)));
257 update_post_meta($post_id, 'nxt-insert-word-interval', sanitize_text_field((string) ($snippet['word_interval'] ?? 200)));
258 update_post_meta($post_id, 'nxt-post-number', sanitize_text_field((string) ($snippet['post_number'] ?? 1)));
259 update_post_meta($post_id, 'nxt-css-selector', wp_unslash((string) ($snippet['css_selector'] ?? '')));
260 update_post_meta($post_id, 'nxt-element-index', sanitize_text_field((string) ($snippet['element_index'] ?? 0)));
261 update_post_meta($post_id, 'nxt-code-insertion', sanitize_text_field((string) ($snippet['insertion'] ?? '')));
262 update_post_meta($post_id, 'nxt-code-location', sanitize_text_field((string) ($snippet['location'] ?? '')));
263 update_post_meta($post_id, 'nxt-code-customname', sanitize_text_field((string) ($snippet['customname'] ?? '')));
264 update_post_meta($post_id, 'nxt-code-compresscode', sanitize_text_field((string) ($snippet['compresscode'] ?? '')));
265 update_post_meta($post_id, 'nxt-code-startdate', sanitize_text_field((string) ($snippet['startDate'] ?? '')));
266 update_post_meta($post_id, 'nxt-code-enddate', sanitize_text_field((string) ($snippet['endDate'] ?? '')));
267 update_post_meta($post_id, 'nxt-code-shortcodeattr', wp_unslash((string) ($snippet['shortcodeattr'] ?? '')));
268 update_post_meta($post_id, 'nxt-smart-conditional-logic', wp_unslash((string) ($snippet['smart_conditional_logic'] ?? '')));
269 update_post_meta($post_id, 'nxt-code-php-hidden-execute', sanitize_text_field((string) ($snippet['php_hidden_execute'] ?? '')));
270 update_post_meta($post_id, 'nxt-wdkit-unique-sid', $w_unique);
271
272 return [
273 'success' => true,
274 'message' => "Snippet '{$snippet_name}' downloaded and installed (post-based).",
275 'post_id' => (int) $post_id,
276 'file_id' => null,
277 'name' => $snippet_name,
278 'response' => $cloud,
279 ];
280 }
281