PluginProbe
WDesignKit – AI Templates, Widget Builder & MCP Workflow / 2.7.0
WDesignKit – AI Templates, Widget Builder & MCP Workflow v2.7.0
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 1.0.16 All 129 releases
wdesignkit / includes / abilities / widgets / wdesignkit-list-widgets.php

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

236 lines 8.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Ability: List all local WDesignKit widgets across all builders.
4 */
5
6 declare(strict_types=1);
7
8 if (!defined('ABSPATH')) {
9 exit();
10 }
11
12 wp_register_ability('wdesignkit/list-widgets', [
13 'label' => __('List WDesignKit Widgets', 'wdesignkit'),
14 'description' => __(
15 'Lists all locally created widgets across all page builders (Elementor, Gutenberg, Gutenberg Core, Bricks). Shows widget name, builder type, version, status, and folder path.',
16 'wdesignkit',
17 ),
18 'category' => 'wdesignkit',
19 'input_schema' => [
20 'type' => 'object',
21 'properties' => [
22 'builder' => [
23 'type' => 'string',
24 'description' => 'Filter by builder type. Leave empty for all builders.',
25 'enum' => ['', 'elementor', 'gutenberg', 'gutenberg_core', 'bricks'],
26 ],
27 'page' => [
28 'type' => 'integer',
29 'description' => 'Page number for pagination (1-based). Defaults to 1.',
30 'minimum' => 1,
31 ],
32 'per_page' => [
33 'type' => 'integer',
34 'description' => 'Number of widgets per page. Defaults to 50. Max 200.',
35 'minimum' => 1,
36 'maximum' => 200,
37 ],
38 ],
39 'additionalProperties' => false,
40 ],
41 'output_schema' => [
42 'type' => 'object',
43 'properties' => [
44 'success' => ['type' => 'boolean'],
45 'total' => ['type' => 'integer'],
46 'page' => ['type' => 'integer'],
47 'per_page' => ['type' => 'integer'],
48 'total_pages' => ['type' => 'integer'],
49 'widgets' => ['type' => 'array'],
50 'execution_time_ms' => ['type' => 'number'],
51 ],
52 ],
53 'execute_callback' => 'wdesignkit_mcp_list_widgets',
54 'permission_callback' => 'wdesignkit_mcp_permission_callback',
55 'meta' => [
56 'public' => true,
57 'show_in_rest' => true,
58 'mcp' => ['public' => true],
59 'annotations' => [
60 'instructions' => implode("\n", [
61 'Lists all locally installed WDesignKit widgets.',
62 'Widgets are stored as files in wp-content/uploads/wdesignkit/{builder_type}/{widget_folder}/',
63 'Each widget folder contains: .json (config), .php (code), .css (styles), .js (scripts).',
64 'Supported builders: elementor, gutenberg, gutenberg_core, bricks.',
65 'Use the builder parameter to filter by a specific page builder.',
66 'Use page/per_page for pagination when there are many widgets.',
67 'Does NOT require WDesignKit cloud login.',
68 ]),
69 'readonly' => true,
70 'destructive' => false,
71 'idempotent' => true,
72 ],
73 ],
74 ]);
75
76 function wdesignkit_mcp_list_widgets(array $input): array {
77 $start_time = microtime(true);
78
79 if (!defined('WDKIT_BUILDER_PATH')) {
80 return [
81 'success' => false,
82 'message' => 'WDesignKit plugin is not active. Please activate it first.',
83 'total' => 0,
84 'page' => 1,
85 'per_page' => 50,
86 'total_pages' => 0,
87 'widgets' => [],
88 'execution_time_ms' => 0,
89 ];
90 }
91
92 $filter_builder = !empty($input['builder']) ? $input['builder'] : '';
93 $page = max(1, (int) ($input['page'] ?? 1));
94 $per_page = min(200, max(1, (int) ($input['per_page'] ?? 50)));
95
96 $builders = ['elementor', 'gutenberg', 'gutenberg_core', 'bricks'];
97 if ($filter_builder !== '') {
98 $builders = [$filter_builder];
99 }
100
101 $deactivated = get_option('wkit_deactivate_widgets', []);
102 $deactivated_ids = [];
103 if (is_array($deactivated)) {
104 foreach ($deactivated as $dw) {
105 if (!empty($dw['w_unique'])) {
106 $deactivated_ids[] = $dw['w_unique'];
107 }
108 }
109 }
110
111 $widgets = [];
112
113 foreach ($builders as $builder_name) {
114 $builder_dir = WDKIT_BUILDER_PATH . '/' . $builder_name;
115
116 if (!is_dir($builder_dir)) {
117 continue;
118 }
119
120 $folders = @scandir($builder_dir);
121 if (!is_array($folders)) {
122 // Cannot read builder directory — skip this builder instead of fataling
123 continue;
124 }
125 $folders = array_diff($folders, ['.', '..']);
126
127 foreach ($folders as $folder) {
128 $folder_path = $builder_dir . '/' . $folder;
129
130 if (!is_dir($folder_path)) {
131 continue;
132 }
133
134 $sub_files = @scandir($folder_path);
135 if (!is_array($sub_files)) {
136 // Unreadable widget folder — record a placeholder and move on
137 $widgets[] = [
138 'folder' => $folder,
139 'builder' => $builder_name,
140 'name' => $folder,
141 'status' => 'unknown',
142 'message' => 'Widget folder is not readable',
143 ];
144 continue;
145 }
146
147 // Find the JSON config file
148 $json_file = null;
149 foreach ($sub_files as $sf) {
150 if (pathinfo($sf, PATHINFO_EXTENSION) === 'json') {
151 $json_file = $folder_path . '/' . $sf;
152 break;
153 }
154 }
155
156 if (!$json_file || !file_exists($json_file)) {
157 $widgets[] = [
158 'folder' => $folder,
159 'builder' => $builder_name,
160 'name' => $folder,
161 'status' => 'unknown',
162 'message' => 'No JSON config file found',
163 ];
164 continue;
165 }
166
167 $raw_json = @file_get_contents($json_file);
168 $json_data = ($raw_json !== false) ? json_decode($raw_json, true) : null;
169 if ($json_data === null || json_last_error() !== JSON_ERROR_NONE) {
170 $widgets[] = [
171 'folder' => $folder,
172 'builder' => $builder_name,
173 'name' => $folder,
174 'status' => 'unknown',
175 'message' => 'Corrupted JSON config file',
176 ];
177 continue;
178 }
179
180 $widget_data = $json_data['widget_data']['widgetdata'] ?? [];
181 $widget_id = $widget_data['widget_id'] ?? '';
182 $is_active = !in_array($widget_id, $deactivated_ids, true);
183
184 // Collect file extensions present in this folder (deduplicated)
185 $file_types = [];
186 foreach (array_diff($sub_files, ['.', '..']) as $f) {
187 $ext = pathinfo($f, PATHINFO_EXTENSION);
188 if ($ext) {
189 $file_types[] = $ext;
190 }
191 }
192 $file_types = array_values(array_unique($file_types));
193
194 $mtime = @filemtime($folder_path);
195
196 $widgets[] = [
197 'folder' => $folder,
198 'builder' => $builder_name,
199 'name' => $widget_data['name'] ?? $folder,
200 'widget_id' => $widget_id,
201 'version' => $widget_data['widget_version'] ?: '1.0.0',
202 'description' => $widget_data['description'] ?? '',
203 'category' => $widget_data['category'] ?? 'WDesignKit',
204 'publish_type' => $widget_data['publish_type'] ?? '',
205 'status' => $is_active ? 'active' : 'deactivated',
206 'files' => $file_types,
207 'last_modified' => $mtime !== false ? wp_date('Y-m-d H:i:s', $mtime) : null,
208 ];
209 }
210 }
211
212 // Sort by last_modified descending (null values sort last)
213 usort($widgets, function ($a, $b) {
214 $a_mod = $a['last_modified'] ?? '';
215 $b_mod = $b['last_modified'] ?? '';
216 return strcmp($b_mod, $a_mod);
217 });
218
219 $total = count($widgets);
220 $total_pages = $per_page > 0 ? (int) ceil($total / $per_page) : 1;
221 $offset = ($page - 1) * $per_page;
222 $page_items = array_slice($widgets, $offset, $per_page);
223
224 $elapsed_ms = round((microtime(true) - $start_time) * 1000, 2);
225
226 return [
227 'success' => true,
228 'total' => $total,
229 'page' => $page,
230 'per_page' => $per_page,
231 'total_pages' => $total_pages,
232 'widgets' => $page_items,
233 'execution_time_ms' => $elapsed_ms,
234 ];
235 }
236