PluginProbe ʕ •ᴥ•ʔ
Atarim – AI Agency for WordPress: Edit Pages, Fix Code, Update Plugins, SEO & Client Feedback / trunk
Atarim – AI Agency for WordPress: Edit Pages, Fix Code, Update Plugins, SEO & Client Feedback vtrunk
5.1.3 5.1.2 5.1.1 5.1 5.0 trunk 3.10 3.11 3.12 3.13 3.14 3.15 3.16 3.17 3.18 3.19 3.2.0 3.2.1 3.22 3.22.1 3.22.2 3.22.3 3.22.4 3.22.5 3.22.6 3.3.0 3.3.1 3.3.2 3.3.2.1 3.3.2.2 3.3.3 3.30 3.31 3.32 3.4 3.4.1 3.4.3 3.4.4 3.5 3.5.1 3.6 3.6.1 3.7 3.8 3.9 3.9.1 3.9.2 3.9.3 3.9.4 3.9.6 3.9.6.1 4.0 4.0.1 4.0.2 4.0.3 4.0.4 4.0.5 4.0.6 4.0.7 4.0.8 4.0.9 4.1.0 4.1.1 4.1.2 4.1.3 4.2 4.2.1 4.2.2 4.3 4.3.1 4.3.2 4.3.3 4.3.4 4.3.5 4.4
atarim-visual-collaboration / third-party / forms / wpforms / class-avcf-abilities-wpforms-pro.php
atarim-visual-collaboration / third-party / forms / wpforms Last commit date
class-avcf-abilities-wpforms-pro.php 3 weeks ago class-avcf-abilities-wpforms.php 3 weeks ago class-avcf-wpforms-detector.php 1 month ago class-avcf-wpforms-helpers.php 3 weeks ago
class-avcf-abilities-wpforms-pro.php
421 lines
1 <?php
2 /**
3 * WPForms — power MCP abilities (standalone cluster, -pro file).
4 *
5 * WPForms-specific depth beyond the common surface: form CRUD, entry
6 * delete/star/read + notes, full notification & confirmation management, and a
7 * read of connected marketing/CRM providers. Entry writers require WPForms Pro.
8 * Writers use WPForms' own capabilities with a manage_options fallback; deletes
9 * are confirm-gated. Built on WPForms; not runtime-tested here.
10 *
11 * @package atarim-visual-collaboration
12 */
13
14 if ( ! defined('ABSPATH') ) {
15 exit;
16 }
17
18 class AVCF_Abilities_WPForms_Pro extends AVCF_Abilities_Base {
19
20 /** @var AVCF_WPForms_Detector */
21 private $detector;
22
23 public function __construct() {
24 $this->detector = new AVCF_WPForms_Detector();
25 }
26
27 public function register() {
28 if ( ! $this->detector->avcf_wpforms_is_available() ) {
29 return;
30 }
31 $this->register_create_form();
32 $this->register_update_form();
33 $this->register_delete_form();
34 $this->register_delete_entry();
35 $this->register_star_entry();
36 $this->register_mark_entry_read();
37 $this->register_list_entry_notes();
38 $this->register_add_entry_note();
39 $this->register_list_notifications();
40 $this->register_save_notification();
41 $this->register_list_confirmations();
42 $this->register_save_confirmation();
43 $this->register_list_providers();
44 }
45
46 /* ------------------------------ shared ----------------------------- */
47
48 private function write_meta( $d = false ) { return [ 'mcp' => [ 'public' => true, 'type' => 'tool' ], 'annotations' => [ 'readonly' => false, 'destructive' => (bool) $d, 'idempotent' => false ] ]; }
49 private function ro_meta() { return [ 'mcp' => [ 'public' => true, 'type' => 'tool' ], 'annotations' => [ 'readonly' => true, 'destructive' => false, 'idempotent' => true ] ]; }
50 private function std() { return [ 'type' => 'object', 'properties' => [ 'success' => [ 'type' => 'boolean' ], 'message' => [ 'type' => 'string' ] ], 'required' => [ 'success', 'message' ] ]; }
51
52 public function is_pro() { return $this->detector->avcf_wpforms_is_pro(); }
53 public function can_create_forms() { return current_user_can( 'wpforms_create_forms' ) || current_user_can( 'wpforms_edit_forms' ) || current_user_can( 'manage_options' ); }
54 public function can_edit_forms() { return current_user_can( 'wpforms_edit_forms' ) || current_user_can( 'manage_options' ); }
55 public function can_delete_forms() { return current_user_can( 'wpforms_delete_forms' ) || current_user_can( 'manage_options' ); }
56 public function can_view_entries() { return current_user_can( 'wpforms_view_entries' ) || current_user_can( 'manage_options' ); }
57 public function can_edit_entries() { return current_user_can( 'wpforms_edit_entries' ) || current_user_can( 'manage_options' ); }
58 public function can_delete_entries() { return current_user_can( 'wpforms_delete_entries' ) || current_user_can( 'manage_options' ); }
59 public function lite_block() { return [ 'success' => false, 'message' => AVCF_WPForms_Helpers::LITE_NOTE ]; }
60
61 /** Load decoded form_data + the post, or null. */
62 public function load_form( $form_id ) {
63 $form = wpforms()->form->get( (int) $form_id, [ 'content_only' => false ] );
64 if ( ! $form ) { return null; }
65 $data = wpforms_decode( $form->post_content );
66 if ( ! is_array( $data ) ) { $data = []; }
67 return [ 'post' => $form, 'data' => $data ];
68 }
69 public function save_form_data( $form_id, $data ) {
70 return wp_update_post( [ 'ID' => (int) $form_id, 'post_content' => wpforms_encode( $data ) ], true );
71 }
72
73 /* ----------------------------- create-form ------------------------- */
74
75 private function register_create_form() {
76 $self = $this;
77 wp_register_ability( 'atarim/wpforms-create-form', [
78 'label' => 'Create WPForm', 'category' => 'atarim',
79 'description' => 'Create a new WPForms form. Provide a title and an optional simple fields array (each: { type, label, required?, choices?[] }) — field ids are auto-assigned. Returns the new form_id.',
80 'input_schema' => [ 'type' => 'object', 'properties' => [ 'title' => [ 'type' => 'string', 'minLength' => 1 ], 'fields' => [ 'type' => 'array', 'items' => [ 'type' => 'object' ] ] ], 'required' => [ 'title' ], 'additionalProperties' => false ],
81 'output_schema'=> [ 'type' => 'object', 'properties' => [ 'success' => [ 'type' => 'boolean' ], 'form_id' => [ 'type' => 'integer' ], 'message' => [ 'type' => 'string' ] ], 'required' => [ 'success', 'message' ] ],
82 'execute_callback' => function( $input = [] ) use ( $self ) {
83 $title = sanitize_text_field( $input['title'] );
84 if ( $title === '' ) { return [ 'success' => false, 'message' => 'A title is required.' ]; }
85 if ( ! method_exists( wpforms()->form, 'add' ) ) { return [ 'success' => false, 'message' => 'WPForms form->add() unavailable.' ]; }
86 $form_id = wpforms()->form->add( $title );
87 if ( is_wp_error( $form_id ) || ! $form_id ) { return [ 'success' => false, 'message' => 'Create failed.' ]; }
88 if ( isset( $input['fields'] ) && is_array( $input['fields'] ) && $input['fields'] ) {
89 $loaded = $self->load_form( $form_id );
90 if ( $loaded ) {
91 $data = $loaded['data'];
92 if ( ! isset( $data['fields'] ) || ! is_array( $data['fields'] ) ) { $data['fields'] = []; }
93 $i = 1;
94 foreach ( $input['fields'] as $f ) {
95 if ( ! is_array( $f ) ) { continue; }
96 $fid = isset( $f['id'] ) ? (int) $f['id'] : $i;
97 $field = [ 'id' => $fid, 'type' => isset( $f['type'] ) ? (string) $f['type'] : 'text', 'label' => isset( $f['label'] ) ? (string) $f['label'] : ( 'Field ' . $fid ), 'required' => ! empty( $f['required'] ) ? '1' : '' ];
98 if ( isset( $f['choices'] ) && is_array( $f['choices'] ) ) {
99 $field['choices'] = []; $ci = 1;
100 foreach ( $f['choices'] as $c ) { $txt = is_array( $c ) ? ( isset( $c['label'] ) ? $c['label'] : '' ) : (string) $c; $field['choices'][ $ci ] = [ 'label' => (string) $txt ]; $ci++; }
101 }
102 $data['fields'][ $fid ] = $field; $i++;
103 }
104 $self->save_form_data( $form_id, $data );
105 }
106 }
107 return [ 'success' => true, 'form_id' => (int) $form_id, 'message' => sprintf( 'Form %d created.', (int) $form_id ) ];
108 },
109 'permission_callback' => function() use ( $self ) { return $self->can_create_forms(); },
110 'meta' => $this->write_meta( false ),
111 ] );
112 }
113
114 /* ----------------------------- update-form ------------------------- */
115
116 private function register_update_form() {
117 $self = $this;
118 wp_register_ability( 'atarim/wpforms-update-form', [
119 'label' => 'Update WPForm', 'category' => 'atarim',
120 'description' => 'Update a form: title, and/or a settings patch (merged into form_data["settings"]), and/or a full replacement fields map (keyed by field id). Only provided keys change.',
121 'input_schema' => [ 'type' => 'object', 'properties' => [ 'form_id' => [ 'type' => 'integer', 'minimum' => 1 ], 'title' => [ 'type' => 'string' ], 'settings' => [ 'type' => 'object' ], 'fields' => [ 'type' => 'object' ] ], 'required' => [ 'form_id' ], 'additionalProperties' => false ],
122 'output_schema'=> $this->std(),
123 'execute_callback' => function( $input = [] ) use ( $self ) {
124 $loaded = $self->load_form( (int) $input['form_id'] );
125 if ( $loaded === null ) { return [ 'success' => false, 'message' => 'Form not found.' ]; }
126 $data = $loaded['data'];
127 $post_update = [ 'ID' => (int) $input['form_id'] ];
128 if ( isset( $input['title'] ) ) {
129 $t = sanitize_text_field( $input['title'] );
130 $data['settings']['form_title'] = $t;
131 $post_update['post_title'] = $t;
132 }
133 if ( isset( $input['settings'] ) && is_array( $input['settings'] ) ) {
134 if ( ! isset( $data['settings'] ) || ! is_array( $data['settings'] ) ) { $data['settings'] = []; }
135 $data['settings'] = array_merge( $data['settings'], $input['settings'] );
136 }
137 if ( isset( $input['fields'] ) && is_array( $input['fields'] ) ) { $data['fields'] = $input['fields']; }
138 $post_update['post_content'] = wpforms_encode( $data );
139 $r = wp_update_post( $post_update, true );
140 if ( is_wp_error( $r ) ) { return [ 'success' => false, 'message' => $r->get_error_message() ]; }
141 return [ 'success' => true, 'message' => 'Form updated.' ];
142 },
143 'permission_callback' => function() use ( $self ) { return $self->can_edit_forms(); },
144 'meta' => $this->write_meta( false ),
145 ] );
146 }
147
148 /* ----------------------------- delete-form ------------------------- */
149
150 private function register_delete_form() {
151 $self = $this;
152 wp_register_ability( 'atarim/wpforms-delete-form', [
153 'label' => 'Delete WPForm', 'category' => 'atarim',
154 'description' => 'Permanently delete a form (and its entries). DESTRUCTIVE — dry run unless confirm:true.',
155 'input_schema' => [ 'type' => 'object', 'properties' => [ 'form_id' => [ 'type' => 'integer', 'minimum' => 1 ], 'confirm' => [ 'type' => 'boolean', 'default' => false ] ], 'required' => [ 'form_id' ], 'additionalProperties' => false ],
156 'output_schema'=> $this->std(),
157 'execute_callback' => function( $input = [] ) use ( $self ) {
158 $form_id = (int) $input['form_id'];
159 if ( ! wpforms()->form->get( $form_id, [ 'content_only' => false ] ) ) { return [ 'success' => false, 'message' => 'Form not found.' ]; }
160 if ( empty( $input['confirm'] ) ) { return [ 'success' => true, 'message' => 'Dry run: re-call with confirm:true to permanently delete this form and its entries.' ]; }
161 $ok = false;
162 if ( method_exists( wpforms()->form, 'delete' ) ) { $ok = (bool) wpforms()->form->delete( [ $form_id ] ); }
163 else { $ok = (bool) wp_delete_post( $form_id, true ); }
164 return $ok ? [ 'success' => true, 'message' => sprintf( 'Form %d deleted.', $form_id ) ] : [ 'success' => false, 'message' => 'Delete failed.' ];
165 },
166 'permission_callback' => function() use ( $self ) { return $self->can_delete_forms(); },
167 'meta' => $this->write_meta( true ),
168 ] );
169 }
170
171 /* ----------------------------- delete-entry ------------------------ */
172
173 private function register_delete_entry() {
174 $self = $this;
175 wp_register_ability( 'atarim/wpforms-delete-entry', [
176 'label' => 'Delete WPForms Entry', 'category' => 'atarim',
177 'description' => 'Permanently delete an entry. WPForms Pro only. DESTRUCTIVE — dry run unless confirm:true.',
178 'input_schema' => [ 'type' => 'object', 'properties' => [ 'entry_id' => [ 'type' => 'integer', 'minimum' => 1 ], 'confirm' => [ 'type' => 'boolean', 'default' => false ] ], 'required' => [ 'entry_id' ], 'additionalProperties' => false ],
179 'output_schema'=> $this->std(),
180 'execute_callback' => function( $input = [] ) use ( $self ) {
181 if ( ! $self->is_pro() ) { return $self->lite_block(); }
182 $entry_id = (int) $input['entry_id'];
183 if ( ! wpforms()->entry->get( $entry_id ) ) { return [ 'success' => false, 'message' => 'Entry not found.' ]; }
184 if ( empty( $input['confirm'] ) ) { return [ 'success' => true, 'message' => 'Dry run: re-call with confirm:true to permanently delete this entry.' ]; }
185 $ok = (bool) wpforms()->entry->delete( $entry_id );
186 return $ok ? [ 'success' => true, 'message' => sprintf( 'Entry %d deleted.', $entry_id ) ] : [ 'success' => false, 'message' => 'Delete failed.' ];
187 },
188 'permission_callback' => function() use ( $self ) { return $self->can_delete_entries(); },
189 'meta' => $this->write_meta( true ),
190 ] );
191 }
192
193 /* ------------------------------ star-entry ------------------------- */
194
195 private function register_star_entry() {
196 $self = $this;
197 wp_register_ability( 'atarim/wpforms-star-entry', [
198 'label' => 'Star WPForms Entry', 'category' => 'atarim',
199 'description' => 'Star or unstar an entry (starred:true/false). WPForms Pro only.',
200 'input_schema' => [ 'type' => 'object', 'properties' => [ 'entry_id' => [ 'type' => 'integer', 'minimum' => 1 ], 'starred' => [ 'type' => 'boolean', 'default' => true ] ], 'required' => [ 'entry_id' ], 'additionalProperties' => false ],
201 'output_schema'=> $this->std(),
202 'execute_callback' => function( $input = [] ) use ( $self ) {
203 if ( ! $self->is_pro() ) { return $self->lite_block(); }
204 $entry_id = (int) $input['entry_id'];
205 if ( ! wpforms()->entry->get( $entry_id ) ) { return [ 'success' => false, 'message' => 'Entry not found.' ]; }
206 $val = ! isset( $input['starred'] ) || ! empty( $input['starred'] ) ? 1 : 0;
207 $r = wpforms()->entry->update( $entry_id, [ 'starred' => $val ], '', 'edit', [ 'cap' => 'edit_entries_form_single' ] );
208 return $r ? [ 'success' => true, 'message' => $val ? 'Entry starred.' : 'Entry unstarred.' ] : [ 'success' => false, 'message' => 'Update failed.' ];
209 },
210 'permission_callback' => function() use ( $self ) { return $self->can_edit_entries(); },
211 'meta' => $this->write_meta( false ),
212 ] );
213 }
214
215 /* -------------------------- mark-entry-read ------------------------ */
216
217 private function register_mark_entry_read() {
218 $self = $this;
219 wp_register_ability( 'atarim/wpforms-mark-entry-read', [
220 'label' => 'Mark WPForms Entry Read', 'category' => 'atarim',
221 'description' => 'Mark an entry read or unread (read:true/false). WPForms Pro only.',
222 'input_schema' => [ 'type' => 'object', 'properties' => [ 'entry_id' => [ 'type' => 'integer', 'minimum' => 1 ], 'read' => [ 'type' => 'boolean', 'default' => true ] ], 'required' => [ 'entry_id' ], 'additionalProperties' => false ],
223 'output_schema'=> $this->std(),
224 'execute_callback' => function( $input = [] ) use ( $self ) {
225 if ( ! $self->is_pro() ) { return $self->lite_block(); }
226 $entry_id = (int) $input['entry_id'];
227 if ( ! wpforms()->entry->get( $entry_id ) ) { return [ 'success' => false, 'message' => 'Entry not found.' ]; }
228 $val = ! isset( $input['read'] ) || ! empty( $input['read'] ) ? 1 : 0;
229 $r = wpforms()->entry->update( $entry_id, [ 'viewed' => $val ], '', 'edit', [ 'cap' => 'edit_entries_form_single' ] );
230 return $r ? [ 'success' => true, 'message' => $val ? 'Entry marked read.' : 'Entry marked unread.' ] : [ 'success' => false, 'message' => 'Update failed.' ];
231 },
232 'permission_callback' => function() use ( $self ) { return $self->can_edit_entries(); },
233 'meta' => $this->write_meta( false ),
234 ] );
235 }
236
237 /* -------------------------- list-entry-notes ----------------------- */
238
239 private function register_list_entry_notes() {
240 $self = $this;
241 wp_register_ability( 'atarim/wpforms-list-entry-notes', [
242 'label' => 'List WPForms Entry Notes', 'category' => 'atarim',
243 'description' => 'List admin notes on an entry: { id, data, date, user_id }. WPForms Pro only.',
244 'input_schema' => [ 'type' => 'object', 'properties' => [ 'entry_id' => [ 'type' => 'integer', 'minimum' => 1 ] ], 'required' => [ 'entry_id' ], 'additionalProperties' => false ],
245 'output_schema'=> [ 'type' => 'object', 'properties' => [ 'success' => [ 'type' => 'boolean' ], 'notes' => [ 'type' => 'array' ], 'message' => [ 'type' => 'string' ] ], 'required' => [ 'success', 'message' ] ],
246 'execute_callback' => function( $input = [] ) use ( $self ) {
247 if ( ! $self->is_pro() ) { return $self->lite_block(); }
248 if ( ! isset( wpforms()->entry_meta ) || ! method_exists( wpforms()->entry_meta, 'get_meta' ) ) { return [ 'success' => false, 'message' => 'WPForms entry-meta API unavailable.' ]; }
249 $raw = wpforms()->entry_meta->get_meta( [ 'entry_id' => (int) $input['entry_id'], 'type' => 'note', 'number' => 200 ] );
250 $out = [];
251 foreach ( (array) $raw as $n ) { $out[] = [ 'id' => isset( $n->id ) ? (int) $n->id : 0, 'data' => isset( $n->data ) ? (string) $n->data : '', 'date' => isset( $n->date ) ? (string) $n->date : '', 'user_id' => isset( $n->user_id ) ? (int) $n->user_id : 0 ]; }
252 return [ 'success' => true, 'notes' => $out, 'message' => sprintf( '%d note(s).', count( $out ) ) ];
253 },
254 'permission_callback' => function() use ( $self ) { return $self->can_view_entries(); },
255 'meta' => $this->ro_meta(),
256 ] );
257 }
258
259 /* --------------------------- add-entry-note ------------------------ */
260
261 private function register_add_entry_note() {
262 $self = $this;
263 wp_register_ability( 'atarim/wpforms-add-entry-note', [
264 'label' => 'Add WPForms Entry Note', 'category' => 'atarim',
265 'description' => 'Attach an admin note to an entry (attributed to the current user). WPForms Pro only.',
266 'input_schema' => [ 'type' => 'object', 'properties' => [ 'entry_id' => [ 'type' => 'integer', 'minimum' => 1 ], 'note' => [ 'type' => 'string', 'minLength' => 1 ] ], 'required' => [ 'entry_id', 'note' ], 'additionalProperties' => false ],
267 'output_schema'=> $this->std(),
268 'execute_callback' => function( $input = [] ) use ( $self ) {
269 if ( ! $self->is_pro() ) { return $self->lite_block(); }
270 if ( ! isset( wpforms()->entry_meta ) || ! method_exists( wpforms()->entry_meta, 'add' ) ) { return [ 'success' => false, 'message' => 'WPForms entry-meta API unavailable.' ]; }
271 $entry = wpforms()->entry->get( (int) $input['entry_id'] );
272 if ( ! $entry ) { return [ 'success' => false, 'message' => 'Entry not found.' ]; }
273 $r = wpforms()->entry_meta->add( [ 'entry_id' => (int) $input['entry_id'], 'form_id' => isset( $entry->form_id ) ? (int) $entry->form_id : 0, 'user_id' => get_current_user_id(), 'type' => 'note', 'data' => wp_kses_post( $input['note'] ) ], 'entry_meta' );
274 return $r ? [ 'success' => true, 'message' => 'Note added.' ] : [ 'success' => false, 'message' => 'Add note failed.' ];
275 },
276 'permission_callback' => function() use ( $self ) { return $self->can_edit_entries(); },
277 'meta' => $this->write_meta( false ),
278 ] );
279 }
280
281 /* ------------------------- list-notifications ---------------------- */
282
283 private function register_list_notifications() {
284 $self = $this;
285 wp_register_ability( 'atarim/wpforms-list-notifications', [
286 'label' => 'List WPForms Notifications', 'category' => 'atarim',
287 'description' => 'List a form\'s notifications in full: { id, name, email, subject, message, enabled }.',
288 'input_schema' => [ 'type' => 'object', 'properties' => [ 'form_id' => [ 'type' => 'integer', 'minimum' => 1 ] ], 'required' => [ 'form_id' ], 'additionalProperties' => false ],
289 'output_schema'=> [ 'type' => 'object', 'properties' => [ 'success' => [ 'type' => 'boolean' ], 'notifications' => [ 'type' => 'array' ], 'message' => [ 'type' => 'string' ] ], 'required' => [ 'success', 'message' ] ],
290 'execute_callback' => function( $input = [] ) use ( $self ) {
291 $loaded = $self->load_form( (int) $input['form_id'] );
292 if ( $loaded === null ) { return [ 'success' => false, 'message' => 'Form not found.' ]; }
293 $set = isset( $loaded['data']['settings']['notifications'] ) && is_array( $loaded['data']['settings']['notifications'] ) ? $loaded['data']['settings']['notifications'] : [];
294 $out = [];
295 foreach ( $set as $nid => $n ) {
296 if ( ! is_array( $n ) ) { continue; }
297 $out[] = [ 'id' => (string) $nid, 'name' => isset( $n['notification_name'] ) ? (string) $n['notification_name'] : '', 'email' => isset( $n['email'] ) ? (string) $n['email'] : '', 'subject' => isset( $n['subject'] ) ? (string) $n['subject'] : '', 'message' => isset( $n['message'] ) ? (string) $n['message'] : '', 'enabled' => ! isset( $n['enable'] ) || ! empty( $n['enable'] ) ];
298 }
299 return [ 'success' => true, 'notifications' => $out, 'message' => sprintf( '%d notification(s).', count( $out ) ) ];
300 },
301 'permission_callback' => function() use ( $self ) { return $self->can_edit_forms(); },
302 'meta' => $this->ro_meta(),
303 ] );
304 }
305
306 /* -------------------------- save-notification ---------------------- */
307
308 private function register_save_notification() {
309 $self = $this;
310 wp_register_ability( 'atarim/wpforms-save-notification', [
311 'label' => 'Create/Update WPForms Notification', 'category' => 'atarim',
312 'description' => 'Create or update a notification on a form. Omit notification_id to create (a numeric id is generated). Settable: name, email, subject, message, enabled. Returns the notification_id.',
313 'input_schema' => [ 'type' => 'object', 'properties' => [ 'form_id' => [ 'type' => 'integer', 'minimum' => 1 ], 'notification_id' => [ 'type' => 'string' ], 'name' => [ 'type' => 'string' ], 'email' => [ 'type' => 'string' ], 'subject' => [ 'type' => 'string' ], 'message' => [ 'type' => 'string' ], 'enabled' => [ 'type' => 'boolean' ] ], 'required' => [ 'form_id' ], 'additionalProperties' => false ],
314 'output_schema'=> [ 'type' => 'object', 'properties' => [ 'success' => [ 'type' => 'boolean' ], 'notification_id' => [ 'type' => 'string' ], 'message' => [ 'type' => 'string' ] ], 'required' => [ 'success', 'message' ] ],
315 'execute_callback' => function( $input = [] ) use ( $self ) {
316 $loaded = $self->load_form( (int) $input['form_id'] );
317 if ( $loaded === null ) { return [ 'success' => false, 'message' => 'Form not found.' ]; }
318 $data = $loaded['data'];
319 if ( ! isset( $data['settings']['notifications'] ) || ! is_array( $data['settings']['notifications'] ) ) { $data['settings']['notifications'] = []; }
320 $nid = isset( $input['notification_id'] ) && $input['notification_id'] !== '' ? (string) $input['notification_id'] : (string) ( count( $data['settings']['notifications'] ) + 1 );
321 $n = isset( $data['settings']['notifications'][ $nid ] ) && is_array( $data['settings']['notifications'][ $nid ] ) ? $data['settings']['notifications'][ $nid ] : [];
322 if ( isset( $input['name'] ) ) { $n['notification_name'] = sanitize_text_field( $input['name'] ); }
323 if ( isset( $input['email'] ) ) { $n['email'] = (string) $input['email']; }
324 if ( isset( $input['subject'] ) ) { $n['subject'] = (string) $input['subject']; }
325 if ( isset( $input['message'] ) ) { $n['message'] = (string) $input['message']; }
326 if ( isset( $input['enabled'] ) ) { $n['enable'] = ! empty( $input['enabled'] ) ? '1' : '0'; }
327 $data['settings']['notifications'][ $nid ] = $n;
328 $r = $self->save_form_data( (int) $input['form_id'], $data );
329 if ( is_wp_error( $r ) ) { return [ 'success' => false, 'message' => $r->get_error_message() ]; }
330 return [ 'success' => true, 'notification_id' => $nid, 'message' => 'Notification saved.' ];
331 },
332 'permission_callback' => function() use ( $self ) { return $self->can_edit_forms(); },
333 'meta' => $this->write_meta( false ),
334 ] );
335 }
336
337 /* ------------------------- list-confirmations ---------------------- */
338
339 private function register_list_confirmations() {
340 $self = $this;
341 wp_register_ability( 'atarim/wpforms-list-confirmations', [
342 'label' => 'List WPForms Confirmations', 'category' => 'atarim',
343 'description' => 'List a form\'s confirmations: { id, name, type (message|page|redirect), message, page, redirect }.',
344 'input_schema' => [ 'type' => 'object', 'properties' => [ 'form_id' => [ 'type' => 'integer', 'minimum' => 1 ] ], 'required' => [ 'form_id' ], 'additionalProperties' => false ],
345 'output_schema'=> [ 'type' => 'object', 'properties' => [ 'success' => [ 'type' => 'boolean' ], 'confirmations' => [ 'type' => 'array' ], 'message' => [ 'type' => 'string' ] ], 'required' => [ 'success', 'message' ] ],
346 'execute_callback' => function( $input = [] ) use ( $self ) {
347 $loaded = $self->load_form( (int) $input['form_id'] );
348 if ( $loaded === null ) { return [ 'success' => false, 'message' => 'Form not found.' ]; }
349 $set = isset( $loaded['data']['settings']['confirmations'] ) && is_array( $loaded['data']['settings']['confirmations'] ) ? $loaded['data']['settings']['confirmations'] : [];
350 $out = [];
351 foreach ( $set as $cid => $c ) {
352 if ( ! is_array( $c ) ) { continue; }
353 $out[] = [ 'id' => (string) $cid, 'name' => isset( $c['name'] ) ? (string) $c['name'] : '', 'type' => isset( $c['type'] ) ? (string) $c['type'] : 'message', 'message' => isset( $c['message'] ) ? (string) $c['message'] : '', 'page' => isset( $c['page'] ) ? $c['page'] : null, 'redirect' => isset( $c['redirect'] ) ? (string) $c['redirect'] : '' ];
354 }
355 return [ 'success' => true, 'confirmations' => $out, 'message' => sprintf( '%d confirmation(s).', count( $out ) ) ];
356 },
357 'permission_callback' => function() use ( $self ) { return $self->can_edit_forms(); },
358 'meta' => $this->ro_meta(),
359 ] );
360 }
361
362 /* -------------------------- save-confirmation ---------------------- */
363
364 private function register_save_confirmation() {
365 $self = $this;
366 wp_register_ability( 'atarim/wpforms-save-confirmation', [
367 'label' => 'Create/Update WPForms Confirmation', 'category' => 'atarim',
368 'description' => 'Create or update a confirmation. Omit confirmation_id to create. Settable: name, type (message|page|redirect), message, page (page id), redirect (url). Returns the confirmation_id.',
369 'input_schema' => [ 'type' => 'object', 'properties' => [ 'form_id' => [ 'type' => 'integer', 'minimum' => 1 ], 'confirmation_id' => [ 'type' => 'string' ], 'name' => [ 'type' => 'string' ], 'type' => [ 'type' => 'string', 'enum' => [ 'message', 'page', 'redirect' ] ], 'message' => [ 'type' => 'string' ], 'page' => [ 'type' => 'integer' ], 'redirect' => [ 'type' => 'string' ] ], 'required' => [ 'form_id' ], 'additionalProperties' => false ],
370 'output_schema'=> [ 'type' => 'object', 'properties' => [ 'success' => [ 'type' => 'boolean' ], 'confirmation_id' => [ 'type' => 'string' ], 'message' => [ 'type' => 'string' ] ], 'required' => [ 'success', 'message' ] ],
371 'execute_callback' => function( $input = [] ) use ( $self ) {
372 $loaded = $self->load_form( (int) $input['form_id'] );
373 if ( $loaded === null ) { return [ 'success' => false, 'message' => 'Form not found.' ]; }
374 $data = $loaded['data'];
375 if ( ! isset( $data['settings']['confirmations'] ) || ! is_array( $data['settings']['confirmations'] ) ) { $data['settings']['confirmations'] = []; }
376 $cid = isset( $input['confirmation_id'] ) && $input['confirmation_id'] !== '' ? (string) $input['confirmation_id'] : (string) ( count( $data['settings']['confirmations'] ) + 1 );
377 $c = isset( $data['settings']['confirmations'][ $cid ] ) && is_array( $data['settings']['confirmations'][ $cid ] ) ? $data['settings']['confirmations'][ $cid ] : [];
378 if ( isset( $input['name'] ) ) { $c['name'] = sanitize_text_field( $input['name'] ); }
379 if ( isset( $input['type'] ) ) { $c['type'] = (string) $input['type']; }
380 if ( isset( $input['message'] ) ) { $c['message'] = (string) $input['message']; }
381 if ( isset( $input['page'] ) ) { $c['page'] = (int) $input['page']; }
382 if ( isset( $input['redirect'] ) ) { $c['redirect'] = esc_url_raw( $input['redirect'] ); }
383 $data['settings']['confirmations'][ $cid ] = $c;
384 $r = $self->save_form_data( (int) $input['form_id'], $data );
385 if ( is_wp_error( $r ) ) { return [ 'success' => false, 'message' => $r->get_error_message() ]; }
386 return [ 'success' => true, 'confirmation_id' => $cid, 'message' => 'Confirmation saved.' ];
387 },
388 'permission_callback' => function() use ( $self ) { return $self->can_edit_forms(); },
389 'meta' => $this->write_meta( false ),
390 ] );
391 }
392
393 /* ----------------------------- providers --------------------------- */
394
395 private function register_list_providers() {
396 $self = $this;
397 wp_register_ability( 'atarim/wpforms-list-providers', [
398 'label' => 'List WPForms Form Providers', 'category' => 'atarim',
399 'description' => 'List connected marketing/CRM provider integrations on a form (e.g. mailchimp, sendinblue, zapier): { provider, connections: [{ id, name }] }, read from the form\'s providers config.',
400 'input_schema' => [ 'type' => 'object', 'properties' => [ 'form_id' => [ 'type' => 'integer', 'minimum' => 1 ] ], 'required' => [ 'form_id' ], 'additionalProperties' => false ],
401 'output_schema'=> [ 'type' => 'object', 'properties' => [ 'success' => [ 'type' => 'boolean' ], 'providers' => [ 'type' => 'array' ], 'message' => [ 'type' => 'string' ] ], 'required' => [ 'success', 'message' ] ],
402 'execute_callback' => function( $input = [] ) use ( $self ) {
403 $loaded = $self->load_form( (int) $input['form_id'] );
404 if ( $loaded === null ) { return [ 'success' => false, 'message' => 'Form not found.' ]; }
405 $providers = isset( $loaded['data']['providers'] ) && is_array( $loaded['data']['providers'] ) ? $loaded['data']['providers'] : [];
406 $out = [];
407 foreach ( $providers as $slug => $conns ) {
408 $connections = [];
409 if ( is_array( $conns ) ) {
410 foreach ( $conns as $conn_id => $conn ) { $connections[] = [ 'id' => (string) $conn_id, 'name' => is_array( $conn ) && isset( $conn['connection_name'] ) ? (string) $conn['connection_name'] : '' ]; }
411 }
412 $out[] = [ 'provider' => (string) $slug, 'connections' => $connections ];
413 }
414 return [ 'success' => true, 'providers' => $out, 'message' => sprintf( '%d provider(s) connected.', count( $out ) ) ];
415 },
416 'permission_callback' => function() use ( $self ) { return $self->can_edit_forms(); },
417 'meta' => $this->ro_meta(),
418 ] );
419 }
420 }
421