PluginProbe
WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell / 3.13.1
WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell v3.13.1
3.13.1 3.13.0 3.12.13 3.12.12 3.12.11 3.12.10 3.12.9 3.12.8 3.12.7 3.12.6 3.12.5 3.12.4 3.12.3 3.12.1 3.12.2 3.12.0 3.11.1 3.11.0 3.10.9 3.10.8 3.10.7 3.10.6 2.8.16 2.8.17 2.8.18 All 259 releases
wpfunnels / includes / core / MCP / Tools / LegacyAutomationTools.php

LegacyAutomationTools.php in WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell 3.13.1, at includes/core/MCP/Tools/LegacyAutomationTools.php

387 lines 14.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * LegacyAutomationTools — the free plugin's "Automation" CRUD
4 * (includes/core/rest-api/Controllers/class-automation-controller.php,
5 * REST namespace `wpfnl/v1`, `WpfnlAutomationController`).
6 *
7 * This is a DIFFERENT feature from the Mail Mint automation *canvas* already
8 * covered by WPFunnels Pro's own `AutomationTools.php` (funnel-scoped CRM
9 * triggers like Zapier/Pabbly/ActiveCampaign wired up per-funnel, backed by
10 * wpfunnels-pro/includes/core/rest-api/controllers/AutomationController.php
11 * and driven by admin/src/components/Automation/*.vue). This class does not
12 * touch that feature or duplicate its abilities.
13 *
14 * `WpfnlAutomationController` itself is a thin CRUD proxy in front of Mail
15 * Mint's own automation engine
16 * (`MintMail\App\Internal\Automation\AutomationModel`) — every method here
17 * requires Mail Mint active, exactly like the REST controller does, and every
18 * write goes through the same controller methods the REST routes call so
19 * this never re-implements Mail Mint's validation.
20 *
21 * A "Test Zapier" ability was considered (per Drawer.vue's `testZapier()`,
22 * which POSTs to `wpfunnels/v1/automation/wpfnl-test-zapier/{funnelId}`) and
23 * deliberately dropped: that endpoint, and the Zapier/Pabbly CRM automation
24 * UI around it (Automation.vue, Drawer.vue, Trigger.vue — all of which read
25 * `get_data_by_index`/`delete` from `wpfunnels/v1/automation`), belong to
26 * WPFunnels Pro's `AutomationController.php`, not to anything in this free
27 * plugin. A grep for "zapier" (case-insensitive) across this plugin's
28 * `includes/` turned up no route registration and no handler — only UI
29 * copy/labels and the marketing comparison table. There is no free-plugin
30 * backend to wrap, so none is invented here.
31 *
32 * @package WPFunnels\MCP
33 * @since 3.14.0
34 */
35
36 namespace WPFunnels\MCP\Tools;
37
38 defined( 'ABSPATH' ) || exit;
39
40 use WPFunnels\MCP\Helpers\MCPHelper;
41 use WPFunnels\Rest\Controllers\WpfnlAutomationController;
42
43 /**
44 * Class LegacyAutomationTools
45 */
46 class LegacyAutomationTools {
47
48 /**
49 * Ability definitions for this domain.
50 *
51 * @return array
52 */
53 public static function definitions() {
54 return [
55 'wpfunnels/list-legacy-automations' => [
56 'label' => __( 'List Legacy Automations', 'wpfnl' ),
57 'description' => 'List automations created through WPFunnels\' legacy Automation CRUD (a Mail Mint-backed feature, separate from the Automation Canvas). Requires Mail Mint active. Note: the underlying endpoint only returns automations tagged as Mail Mint-native — see the response\'s "note" field.',
58 'input_schema' => [
59 'type' => 'object',
60 'properties' => array_merge(
61 MCPHelper::paginationSchema(),
62 []
63 ),
64 ],
65 'execute_callback' => [ __CLASS__, 'listLegacyAutomations' ],
66 'permission_callback' => MCPHelper::currentUserCan( 'manage_options' ),
67 'annotations' => [ 'readonly' ],
68 ],
69 'wpfunnels/create-legacy-automation' => [
70 'label' => __( 'Create Legacy Automation', 'wpfnl' ),
71 'description' => 'Create a legacy (Mail Mint-backed) automation. Requires Mail Mint active. `data` must include `name` and `trigger_name`; `status` defaults to "draft" ("active" to enable immediately) and `author` defaults to the current user.',
72 'input_schema' => [
73 'type' => 'object',
74 'properties' => [
75 'data' => [
76 'type' => 'object',
77 'description' => 'Automation payload. At minimum: {name, trigger_name}. Optional: {status: "draft"|"active", author, steps: [...]} — see wpfunnels/list-legacy-automations output for the shape of an existing automation.',
78 ],
79 ],
80 'required' => [ 'data' ],
81 ],
82 'execute_callback' => [ __CLASS__, 'createLegacyAutomation' ],
83 'permission_callback' => MCPHelper::currentUserCan( 'manage_options' ),
84 'annotations' => [],
85 ],
86 'wpfunnels/update-legacy-automation' => [
87 'label' => __( 'Update Legacy Automation', 'wpfnl' ),
88 'description' => 'Update a legacy (Mail Mint-backed) automation. Requires Mail Mint active. The underlying engine only accepts the write when `data` includes `name`, `trigger_name` and `status` together with any changed fields — a partial patch missing one of those three will fail. Read wpfunnels/list-legacy-automations first and send back the full record with your changes merged in.',
89 'input_schema' => [
90 'type' => 'object',
91 'properties' => [
92 'automation_id' => [
93 'type' => 'integer',
94 'description' => 'Automation ID.',
95 ],
96 'data' => [
97 'type' => 'object',
98 'description' => 'Full automation payload including name, trigger_name and status (see this ability\'s description).',
99 ],
100 ],
101 'required' => [ 'automation_id', 'data' ],
102 ],
103 'execute_callback' => [ __CLASS__, 'updateLegacyAutomation' ],
104 'permission_callback' => MCPHelper::currentUserCan( 'manage_options' ),
105 'annotations' => [ 'destructive' ],
106 ],
107 'wpfunnels/bulk-delete-legacy-automations' => [
108 'label' => __( 'Bulk Delete Legacy Automations', 'wpfnl' ),
109 'description' => 'Permanently delete one or more legacy automations, including their steps, logs and scheduled emails. Requires Mail Mint active. This cannot be undone.',
110 'input_schema' => [
111 'type' => 'object',
112 'properties' => [
113 'automation_ids' => [
114 'type' => 'array',
115 'description' => 'Automation IDs to delete.',
116 'items' => [ 'type' => 'integer' ],
117 ],
118 ],
119 'required' => [ 'automation_ids' ],
120 ],
121 'execute_callback' => [ __CLASS__, 'bulkDeleteLegacyAutomations' ],
122 'permission_callback' => MCPHelper::currentUserCan( 'manage_options' ),
123 'annotations' => [ 'destructive' ],
124 ],
125 'wpfunnels/toggle-legacy-automation' => [
126 'label' => __( 'Toggle Legacy Automation', 'wpfnl' ),
127 'description' => 'Activate or deactivate a legacy automation by flipping its `status` between "active" and "draft" (the real active/inactive flag Mail Mint stores for it). Requires Mail Mint active.',
128 'input_schema' => [
129 'type' => 'object',
130 'properties' => [
131 'automation_id' => [
132 'type' => 'integer',
133 'description' => 'Automation ID.',
134 ],
135 'active' => [
136 'type' => 'boolean',
137 'description' => 'true to set status "active", false to set status "draft".',
138 ],
139 ],
140 'required' => [ 'automation_id', 'active' ],
141 ],
142 'execute_callback' => [ __CLASS__, 'toggleLegacyAutomation' ],
143 'permission_callback' => MCPHelper::currentUserCan( 'manage_options' ),
144 'annotations' => [ 'destructive' ],
145 ],
146 ];
147 }
148
149 /**
150 * Whether Mail Mint's automation engine and this plugin's automation
151 * REST controller are both available.
152 *
153 * @return bool
154 */
155 private static function mailMintAvailable() {
156 return class_exists( '\MintMail\App\Internal\Automation\AutomationModel' )
157 && class_exists( '\WPFunnels\Rest\Controllers\WpfnlAutomationController' );
158 }
159
160 /**
161 * Standard error for when Mail Mint isn't available.
162 *
163 * @return \WP_Error
164 */
165 private static function mailMintUnavailableError() {
166 return MCPHelper::error(
167 'mail_mint_required',
168 'Legacy automations require Mail Mint. Install and activate it first — see wpfunnels/activate-mail-mint.'
169 );
170 }
171
172 /**
173 * List legacy automations, reusing the real REST controller method.
174 *
175 * @param array $input Tool input.
176 * @return array|\WP_Error
177 */
178 public static function listLegacyAutomations( $input = [] ) {
179 if ( ! self::mailMintAvailable() ) {
180 return self::mailMintUnavailableError();
181 }
182
183 $page = isset( $input['page'] ) ? max( 1, (int) $input['page'] ) : 1;
184 $per_page = MCPHelper::perPage( isset( $input['per_page'] ) ? $input['per_page'] : MCPHelper::DEFAULT_PER_PAGE );
185
186 $controller = new WpfnlAutomationController();
187 $request = new \WP_REST_Request( 'GET', '/wpfnl/v1/automation' );
188 $request->set_param( 'page', $page );
189 $request->set_param( 'per_page', $per_page );
190
191 $response = $controller->get_items( $request );
192 if ( is_wp_error( $response ) ) {
193 return $response;
194 }
195
196 $data = $response->get_data();
197
198 return [
199 'automations' => isset( $data['data'] ) ? $data['data'] : [],
200 'pagination' => [
201 'page' => $page,
202 'per_page' => $per_page,
203 'total' => isset( $data['count'] ) ? (int) $data['count'] : 0,
204 'total_pages' => isset( $data['total_pages'] ) ? (int) $data['total_pages'] : 0,
205 ],
206 'note' => 'The underlying endpoint only returns automations whose "source" meta is "mint". Automations created via wpfunnels/create-legacy-automation are tagged source="wpf" and may not appear in this list — this mirrors an existing mismatch in the underlying REST endpoint, not something this tool introduces.',
207 ];
208 }
209
210 /**
211 * Create a legacy automation, reusing the real REST controller method.
212 *
213 * @param array $input Tool input.
214 * @return array|\WP_Error
215 */
216 public static function createLegacyAutomation( $input = [] ) {
217 if ( ! self::mailMintAvailable() ) {
218 return self::mailMintUnavailableError();
219 }
220
221 $data = isset( $input['data'] ) && is_array( $input['data'] ) ? $input['data'] : [];
222
223 if ( empty( $data['name'] ) || empty( $data['trigger_name'] ) ) {
224 return MCPHelper::error( 'missing_fields', 'Provide at least data.name and data.trigger_name.' );
225 }
226
227 if ( empty( $data['status'] ) ) {
228 $data['status'] = 'draft';
229 }
230
231 $controller = new WpfnlAutomationController();
232 $request = new \WP_REST_Request( 'POST', '/wpfnl/v1/automation' );
233 $request->set_body( wp_json_encode( $data ) );
234
235 $response = $controller->create_item( $request );
236 if ( is_wp_error( $response ) ) {
237 return $response;
238 }
239
240 $result = $response->get_data();
241
242 return [
243 'success' => true,
244 'automation_id' => isset( $result['id'] ) ? (int) $result['id'] : null,
245 ];
246 }
247
248 /**
249 * Update a legacy automation, reusing the real REST controller method.
250 *
251 * @param array $input Tool input.
252 * @return array|\WP_Error
253 */
254 public static function updateLegacyAutomation( $input = [] ) {
255 if ( ! self::mailMintAvailable() ) {
256 return self::mailMintUnavailableError();
257 }
258
259 $id = isset( $input['automation_id'] ) ? (int) $input['automation_id'] : 0;
260 if ( ! $id ) {
261 return MCPHelper::error( 'missing_automation_id', 'Provide automation_id.' );
262 }
263
264 $data = isset( $input['data'] ) && is_array( $input['data'] ) ? $input['data'] : [];
265 if ( empty( $data ) ) {
266 return MCPHelper::error( 'missing_data', 'Provide the automation fields to write in data.' );
267 }
268
269 $controller = new WpfnlAutomationController();
270 $request = new \WP_REST_Request( 'PUT', '/wpfnl/v1/automation/' . $id );
271 $request->set_param( 'id', $id );
272 $request->set_body( wp_json_encode( $data ) );
273
274 $response = $controller->update_item( $request );
275 if ( is_wp_error( $response ) ) {
276 return $response;
277 }
278
279 return [
280 'success' => true,
281 'automation_id' => $id,
282 ];
283 }
284
285 /**
286 * Permanently delete one or more legacy automations.
287 *
288 * `WpfnlAutomationController` only exposes a single-item delete route, so
289 * this calls Mail Mint's own `AutomationModel::destroy_all()` directly —
290 * the same bulk-delete method Mail Mint's own admin list table uses,
291 * rather than looping single deletes through the REST controller.
292 *
293 * @param array $input Tool input.
294 * @return array|\WP_Error
295 */
296 public static function bulkDeleteLegacyAutomations( $input = [] ) {
297 if ( ! self::mailMintAvailable() ) {
298 return self::mailMintUnavailableError();
299 }
300
301 $ids = isset( $input['automation_ids'] ) && is_array( $input['automation_ids'] )
302 ? array_values( array_filter( array_map( 'intval', $input['automation_ids'] ) ) )
303 : [];
304
305 if ( empty( $ids ) ) {
306 return MCPHelper::error( 'missing_automation_ids', 'Provide at least one automation_id.' );
307 }
308
309 $result = \MintMail\App\Internal\Automation\AutomationModel::destroy_all( $ids );
310
311 return [
312 'success' => (bool) $result,
313 'automation_ids' => $ids,
314 ];
315 }
316
317 /**
318 * Activate/deactivate a legacy automation by flipping its `status`.
319 *
320 * Mail Mint's `create_or_update()` requires `name`, `author`,
321 * `trigger_name` and `status` together on every write, so this reads the
322 * existing record first (via the real `get_item()` controller method),
323 * merges in the new status, and writes the full record back through
324 * `update_item()` — never inventing a lighter-weight "just flip a flag"
325 * path the underlying engine doesn't actually support.
326 *
327 * @param array $input Tool input.
328 * @return array|\WP_Error
329 */
330 public static function toggleLegacyAutomation( $input = [] ) {
331 if ( ! self::mailMintAvailable() ) {
332 return self::mailMintUnavailableError();
333 }
334
335 $id = isset( $input['automation_id'] ) ? (int) $input['automation_id'] : 0;
336 if ( ! $id ) {
337 return MCPHelper::error( 'missing_automation_id', 'Provide automation_id.' );
338 }
339
340 if ( ! isset( $input['active'] ) ) {
341 return MCPHelper::error( 'missing_active', 'Provide active: true or false.' );
342 }
343 $active = (bool) $input['active'];
344
345 $controller = new WpfnlAutomationController();
346
347 $get_request = new \WP_REST_Request( 'GET', '/wpfnl/v1/automation/' . $id );
348 $get_request->set_param( 'id', $id );
349 $current = $controller->get_item( $get_request );
350 if ( is_wp_error( $current ) ) {
351 return $current;
352 }
353
354 $current_data = $current->get_data();
355 $record = isset( $current_data['data'][0] ) ? $current_data['data'][0] : null;
356 if ( ! $record ) {
357 return MCPHelper::error( 'automation_not_found', sprintf( 'No automation found with ID %d.', $id ) );
358 }
359
360 $status = $active ? 'active' : 'draft';
361
362 $payload = [
363 'id' => $id,
364 'name' => isset( $record['name'] ) ? $record['name'] : '',
365 'author' => isset( $record['author'] ) ? $record['author'] : get_current_user_id(),
366 'trigger_name' => isset( $record['trigger_name'] ) ? $record['trigger_name'] : '',
367 'status' => $status,
368 ];
369
370 $update_request = new \WP_REST_Request( 'PUT', '/wpfnl/v1/automation/' . $id );
371 $update_request->set_param( 'id', $id );
372 $update_request->set_body( wp_json_encode( $payload ) );
373
374 $response = $controller->update_item( $update_request );
375 if ( is_wp_error( $response ) ) {
376 return $response;
377 }
378
379 return [
380 'success' => true,
381 'automation_id' => $id,
382 'active' => $active,
383 'status' => $status,
384 ];
385 }
386 }
387