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-delete-snippet-everywhere.php

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

296 lines 12.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Ability: Atomically delete a code snippet from both local site storage and WDesignKit cloud.
4 */
5
6 declare(strict_types=1);
7
8 if (!defined('ABSPATH')) {
9 exit();
10 }
11
12 wp_register_ability('wdesignkit/delete-snippet-everywhere', [
13 'label' => __('Delete WDesignKit Snippet Everywhere', 'wdesignkit'),
14 'description' => __(
15 'Atomically deletes a code snippet from both local site storage (file-based or post-based) AND the WDesignKit cloud marketplace in a single call. Requires confirm: true and cloud login for the cloud side. Supports dry_run preview.',
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 delete from WDesignKit marketplace. Resolved automatically from local snippet if omitted.',
25 ],
26 'file_id' => [
27 'type' => 'string',
28 'description' => 'Local file-based snippet key (from wdesignkit/list-local-snippets). Use for Nexter Pro file-based storage.',
29 ],
30 'post_id' => [
31 'type' => 'integer',
32 'description' => 'Local WordPress post ID of the nxt-code-snippet post. Use for post-based storage.',
33 ],
34 'name' => [
35 'type' => 'string',
36 'description' => 'Snippet title/name. Used to look up local and cloud IDs if omitted.',
37 ],
38 'confirm' => [
39 'type' => 'boolean',
40 'description' => 'Must be true to execute deletion. Omit or false for a dry-run preview.',
41 ],
42 'dry_run' => [
43 'type' => 'boolean',
44 'description' => 'When true, returns preview of target local and cloud snippets to be deleted without modifying files/records.',
45 ],
46 ],
47 'additionalProperties' => false,
48 ],
49 'output_schema' => [
50 'type' => 'object',
51 'properties' => [
52 'success' => ['type' => 'boolean'],
53 'message' => ['type' => 'string'],
54 'dry_run' => ['type' => 'boolean'],
55 'local_deleted' => ['type' => ['boolean', 'null']],
56 'cloud_deleted' => ['type' => ['boolean', 'null']],
57 'local_target' => ['type' => ['object', 'null']],
58 'cloud_target' => ['type' => ['object', 'null']],
59 ],
60 ],
61 'execute_callback' => 'wdesignkit_mcp_delete_snippet_everywhere',
62 'permission_callback' => 'wdesignkit_mcp_permission_callback',
63 'meta' => [
64 'public' => false,
65 'show_in_rest' => true,
66 'mcp' => ['public' => false],
67 'annotations' => [
68 'instructions' => implode("\n", [
69 'Deletes a code snippet from both local site storage AND the WDesignKit cloud marketplace in one call.',
70 'confirm: true is required to execute. Without it the call returns a dry-run preview.',
71 'Identify by snippet_id (cloud), file_id / post_id (local), or snippet name.',
72 'Reports exact execution results for both local and cloud targets.',
73 ]),
74 'readonly' => false,
75 'destructive' => true,
76 'idempotent' => false,
77 ],
78 ],
79 ]);
80
81 function wdesignkit_mcp_delete_snippet_everywhere(array $input): array {
82 set_time_limit(90);
83
84 $snippet_id = sanitize_text_field((string) ($input['snippet_id'] ?? ''));
85 $file_id = sanitize_text_field((string) ($input['file_id'] ?? ''));
86 $post_id = (int) ($input['post_id'] ?? 0);
87 $name = sanitize_text_field((string) ($input['name'] ?? ''));
88 $confirm = !empty($input['confirm']);
89 $dry_run = !empty($input['dry_run']);
90
91 $auth = function_exists('wdesignkit_mcp_template_get_auth') ? wdesignkit_mcp_template_get_auth() : [];
92
93 $local_target = null;
94 $cloud_target = null;
95
96 // ── 1. Resolve Local Target ───────────────────────────────────────────────
97 if ($file_id !== '' || $post_id > 0) {
98 if (function_exists('wdesignkit_mcp_get_snippet_info')) {
99 $info = wdesignkit_mcp_get_snippet_info(['file_id' => $file_id, 'post_id' => $post_id]);
100 if (!empty($info['success']) && !empty($info['data'])) {
101 $d = $info['data'];
102 $local_target = [
103 'file_id' => (string) ($d['file_id'] ?? $file_id ?: ''),
104 'post_id' => (int) ($d['post_id'] ?? $post_id ?: 0),
105 'name' => (string) ($d['title'] ?? $name),
106 'storage' => (string) ($info['source'] ?? ($file_id !== '' ? 'file' : 'post')),
107 ];
108 }
109 }
110 }
111
112 if (!$local_target && function_exists('wdesignkit_mcp_list_local_snippets')) {
113 $local_list = wdesignkit_mcp_list_local_snippets(['search' => $name]);
114 if (!empty($local_list['success']) && !empty($local_list['snippets'])) {
115 foreach ($local_list['snippets'] as $item) {
116 $item_name = (string) ($item['name'] ?? '');
117 if ($name !== '' && strtolower($item_name) === strtolower($name)) {
118 $local_target = [
119 'file_id' => (string) ($item['file_id'] ?? ''),
120 'post_id' => (int) ($item['post_id'] ?? 0),
121 'name' => $item_name,
122 'storage' => (string) ($item['storage'] ?? ''),
123 ];
124 break;
125 }
126 }
127 }
128 }
129
130 // ── 2. Resolve Cloud Target ───────────────────────────────────────────────
131 if ($snippet_id !== '') {
132 $cloud_target = [
133 'snippet_id' => $snippet_id,
134 'title' => $name ?: ($local_target['name'] ?? $snippet_id),
135 ];
136 } elseif (!empty($auth['logged_in'])) {
137 $search_term = $name ?: ($local_target['name'] ?? '');
138 if ($search_term !== '' && function_exists('wdesignkit_mcp_template_cloud_call')) {
139 $cloud_list = wdesignkit_mcp_template_cloud_call('snippet/save/get_exist', [
140 'token' => $auth['token'],
141 'search' => $search_term,
142 ], 'form');
143
144 $rows = $cloud_list['data']['snippets'] ?? $cloud_list['data'] ?? [];
145 if (is_array($rows)) {
146 foreach ($rows as $row) {
147 if (!is_array($row)) {
148 continue;
149 }
150 $row_title = (string) ($row['title'] ?? $row['name'] ?? '');
151 if (strtolower($row_title) === strtolower($search_term)) {
152 $cloud_target = [
153 'snippet_id' => (string) ($row['id'] ?? $row['snippet_id'] ?? ''),
154 'title' => $row_title,
155 ];
156 break;
157 }
158 }
159 }
160 }
161 }
162
163 if (!$local_target && !$cloud_target) {
164 return [
165 'success' => false,
166 'message' => 'No matching local or cloud snippet found to delete. Specify snippet_id, file_id, post_id, or snippet name.',
167 'dry_run' => $dry_run,
168 'local_target' => null,
169 'cloud_target' => null,
170 ];
171 }
172
173 // ── 3. Dry Run / Confirmation Check ───────────────────────────────────────
174 if ($dry_run) {
175 return [
176 'success' => true,
177 'message' => 'Dry run: Preview of snippet deletion everywhere.',
178 'dry_run' => true,
179 'local_deleted' => null,
180 'cloud_deleted' => null,
181 'local_target' => $local_target,
182 'cloud_target' => $cloud_target,
183 ];
184 }
185
186 if (!$confirm) {
187 $target_desc = [];
188 if ($local_target) {
189 $target_desc[] = "local snippet '{$local_target['name']}'";
190 }
191 if ($cloud_target) {
192 $target_desc[] = "cloud snippet ID '{$cloud_target['snippet_id']}'";
193 }
194 return [
195 'success' => false,
196 'message' => 'Deleting snippet everywhere will permanently remove ' . implode(' and ', $target_desc) . '. Re-send request with confirm: true to proceed, or use dry_run: true to preview.',
197 'dry_run' => true,
198 'local_deleted' => null,
199 'cloud_deleted' => null,
200 'local_target' => $local_target,
201 'cloud_target' => $cloud_target,
202 ];
203 }
204
205 // ── 4. Execute Deletion ───────────────────────────────────────────────────
206 $local_deleted = null;
207 $cloud_deleted = null;
208 $errors = [];
209
210 // Local deletion
211 if ($local_target) {
212 $storage = $local_target['storage'] ?? '';
213 $fid = $local_target['file_id'] ?? '';
214 $pid = (int) ($local_target['post_id'] ?? 0);
215
216 if ($storage === 'file' || ($fid !== '' && $fid !== '0')) {
217 if (class_exists('Nexter_Code_Snippets_File_Based')) {
218 $file_based = new \Nexter_Code_Snippets_File_Based();
219 $snippet_data = $file_based->get_all_snippets([], $fid, true);
220 if (!empty($snippet_data['file']) && file_exists($snippet_data['file'])) {
221 if (@unlink($snippet_data['file'])) {
222 if (method_exists($file_based, 'snippetIndexData')) {
223 $file_based->snippetIndexData();
224 }
225 $local_deleted = true;
226 } else {
227 $local_deleted = false;
228 $errors[] = "Failed to delete local snippet file '{$fid}'.";
229 }
230 } else {
231 $local_deleted = false;
232 $errors[] = "Local snippet file '{$fid}' not found on disk.";
233 }
234 } else {
235 $local_deleted = false;
236 $errors[] = 'Nexter_Code_Snippets_File_Based class not available.';
237 }
238 } elseif ($pid > 0) {
239 if (get_post($pid)) {
240 $del_res = wp_delete_post($pid, true);
241 $local_deleted = (false !== $del_res && null !== $del_res);
242 if (!$local_deleted) {
243 $errors[] = "Failed to delete local snippet post ID {$pid}.";
244 }
245 } else {
246 $local_deleted = false;
247 $errors[] = "Local snippet post ID {$pid} not found.";
248 }
249 }
250 }
251
252 // Cloud deletion
253 if ($cloud_target && !empty($cloud_target['snippet_id'])) {
254 $cid = $cloud_target['snippet_id'];
255 if (empty($auth['logged_in'])) {
256 $cloud_deleted = false;
257 $errors[] = 'Cloud login required to delete cloud snippet record.';
258 } elseif (function_exists('wdesignkit_mcp_template_cloud_call')) {
259 $cloud_res = wdesignkit_mcp_template_cloud_call('snippet/delete', [
260 'token' => $auth['token'],
261 'id' => $cid,
262 ], 'form');
263
264 $cloud_deleted = !empty($cloud_res['success']);
265 if (!$cloud_deleted) {
266 $errors[] = 'Cloud error: ' . ($cloud_res['message'] ?? $cloud_res['massage'] ?? 'Failed to delete cloud snippet.');
267 }
268 }
269 }
270
271 // Determine overall success
272 $all_ok = ($local_deleted !== false) && ($cloud_deleted !== false);
273
274 if (!$all_ok) {
275 $msg = 'Partial snippet deletion. ' . implode(' ', $errors);
276 } elseif ($local_deleted === true && $cloud_deleted === true) {
277 $msg = 'Snippet successfully deleted everywhere (local and cloud).';
278 } elseif ($local_deleted === true && $cloud_deleted === null) {
279 $msg = 'Snippet deleted locally. No linked cloud copy was found.';
280 } elseif ($local_deleted === null && $cloud_deleted === true) {
281 $msg = 'Cloud snippet deleted. No linked local copy was found.';
282 } else {
283 $msg = 'Nothing to delete — no linked local or cloud copy was found.';
284 }
285
286 return [
287 'success' => $all_ok,
288 'message' => $msg,
289 'dry_run' => false,
290 'local_deleted' => $local_deleted,
291 'cloud_deleted' => $cloud_deleted,
292 'local_target' => $local_target,
293 'cloud_target' => $cloud_target,
294 ];
295 }
296