PluginProbe
WDesignKit – AI Templates, Widget Builder & MCP Workflow / 2.7.1
WDesignKit – AI Templates, Widget Builder & MCP Workflow v2.7.1
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 / widgets / wdesignkit-browse-widgets.php

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

163 lines 6.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Ability: Browse the WDesignKit public widget marketplace with filter support.
4 *
5 * Covers: Browse Widgets, Apply Filter, Remove Single Filter, Clear All Filters, Update Filter.
6 */
7
8 declare(strict_types=1);
9
10 if (!defined('ABSPATH')) {
11 exit();
12 }
13
14 wp_register_ability('wdesignkit/browse-widgets', [
15 'label' => __('Browse WDesignKit Marketplace Widgets', 'wdesignkit'),
16 'description' => __(
17 'Lists widgets available in the WDesignKit public marketplace. Supports the same filter knobs exposed in the WDK UI: builder, sub-builder, category, search keyword, free/pro, and pagination. All filter operations (Apply, Update, Remove single, Clear all) are just different argument combinations on this one call.',
18 'wdesignkit',
19 ),
20 'category' => 'wdesignkit',
21 'input_schema' => [
22 'type' => 'object',
23 'properties' => [
24 'builder' => [
25 'type' => 'string',
26 'description' => 'Filter by builder. Empty string includes all.',
27 'enum' => ['', 'elementor', 'gutenberg'],
28 ],
29 'sub_builder' => [
30 'type' => 'string',
31 'description' => 'Sub-builder filter (e.g. "gutenberg_core"). Leave empty for all.',
32 ],
33 'category' => [
34 'type' => 'string',
35 'description' => 'Widget category to filter by. Leave empty to include all.',
36 ],
37 'search' => [
38 'type' => 'string',
39 'description' => 'Keyword search. Pass empty string to clear the search filter.',
40 ],
41 'free_pro' => [
42 'type' => 'string',
43 'description' => 'Limit to free or pro widgets.',
44 'enum' => ['', 'free', 'pro'],
45 ],
46 'page' => [
47 'type' => 'integer',
48 'description' => 'Page number (1-based). Defaults to 1.',
49 'minimum' => 1,
50 ],
51 'per_page' => [
52 'type' => 'integer',
53 'description' => 'Items per page. Defaults to 12.',
54 'minimum' => 1,
55 'maximum' => 100,
56 ],
57 ],
58 'additionalProperties' => false,
59 ],
60 'output_schema' => [
61 'type' => 'object',
62 'properties' => [
63 'success' => ['type' => 'boolean'],
64 'message' => ['type' => 'string'],
65 'filters' => ['type' => 'object'],
66 'response' => ['type' => ['object', 'array']],
67 ],
68 ],
69 'execute_callback' => 'wdesignkit_mcp_browse_widgets',
70 'permission_callback' => 'wdesignkit_mcp_permission_callback',
71 'meta' => [
72 'public' => true,
73 'show_in_rest' => true,
74 'mcp' => ['public' => true],
75 'annotations' => [
76 'instructions' => implode("\n", [
77 'Browses the WDesignKit widget marketplace. No cloud login required for basic browsing.',
78 'All filter operations map to argument combinations:',
79 '- Apply Filter: pass builder / category / search / free_pro.',
80 '- Update Filter: re-call with the updated values.',
81 '- Remove Single Filter: re-call omitting or passing empty string for that key.',
82 '- Clear All Filters: call with no arguments.',
83 'To download a widget: use wdesignkit/download-widget with widget_id = the numeric "id" field, and u_id = the "user_id" field from this response.',
84 'NOTE: "w_unique" (string code) is NOT the download identifier — always use the numeric "id" field as widget_id.',
85 ]),
86 'readonly' => true,
87 'destructive' => false,
88 'idempotent' => true,
89 ],
90 ],
91 ]);
92
93 function wdesignkit_mcp_browse_widgets(array $input): array {
94 // Timeout guard: marketplace HTTP call uses a 30s timeout; guard PHP execution with a comfortable buffer.
95 set_time_limit(60);
96
97 if (!defined('WDKIT_SERVER_API_URL')) {
98 return ['success' => false, 'message' => 'WDesignKit plugin is not active.'];
99 }
100
101 $builder = sanitize_text_field((string) ($input['builder'] ?? ''));
102 $sub_builder = sanitize_text_field((string) ($input['sub_builder'] ?? ''));
103 $category = sanitize_text_field((string) ($input['category'] ?? ''));
104 $search = sanitize_text_field((string) ($input['search'] ?? ''));
105 $free_pro = sanitize_text_field((string) ($input['free_pro'] ?? ''));
106 $page = max(1, (int) ($input['page'] ?? 1));
107 $per_page = min(100, max(1, (int) ($input['per_page'] ?? 12)));
108
109 // The cloud API expects 'builder' as a JSON-encoded array (e.g. '["elementor"]'),
110 // matching the format the WDesignKit JS front-end sends. An empty string means "all builders".
111 $args = [
112 'CurrentPage' => $page,
113 'builder' => ($builder !== '') ? wp_json_encode([$builder]) : '',
114 'sub_builder' => $sub_builder,
115 'category' => $category,
116 'ParPage' => $per_page,
117 'search' => $search,
118 'free_pro' => $free_pro,
119 ];
120
121 $response = wp_remote_post(
122 WDKIT_SERVER_API_URL . 'api/wp/browse_widget',
123 [
124 'method' => 'POST',
125 'body' => $args,
126 'timeout' => 30,
127 ]
128 );
129
130 if (is_wp_error($response)) {
131 return ['success' => false, 'message' => $response->get_error_message()];
132 }
133
134 $status = wp_remote_retrieve_response_code($response);
135 $body = wp_remote_retrieve_body($response);
136 $data = json_decode($body, true);
137
138 if (200 !== (int) $status) {
139 return ['success' => false, 'message' => "WDesignKit marketplace returned status {$status}."];
140 }
141
142 // Unwrap nested data envelope
143 $payload = $data;
144 if (isset($data['success']) && $data['success'] && isset($data['data'])) {
145 $payload = is_array($data['data']) ? $data['data'] : $data;
146 }
147
148 return [
149 'success' => !empty($data['success']),
150 'message' => $data['message'] ?? $data['massage'] ?? '',
151 'filters' => [
152 'builder' => $builder,
153 'sub_builder' => $sub_builder,
154 'category' => $category,
155 'search' => $search,
156 'free_pro' => $free_pro,
157 'page' => $page,
158 'per_page' => $per_page,
159 ],
160 'response' => $payload,
161 ];
162 }
163