PluginProbe
WANotifier for Forms and Actions / 3.2.0
WANotifier for Forms and Actions v3.2.0
3.2.0 3.1.1 3.1.0 3.0.4 2.7.10 2.7.11 2.7.12 2.7.13 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 2.7.8 2.7.9 3.0.0 3.0.1 3.0.2 3.0.3 trunk 0.1.0 0.1.1 1.0.0 1.0.1 All 68 releases
← All changes | includes/classes/class-notifier-notification-triggers.php +552 -93 0.1.0 → 3.2.0 View file →
@@ -1,36 +1,90 @@
1 1 <?php
2 +if ( ! defined( 'ABSPATH' ) ) {
3 + exit;
4 +}
5 +
2 6 /**
3 7 * Notification Triggers class
4 8 *
5 9 * @package Wa_Notifier
6 10 */
7 -class Notifier_Notification_Triggers extends Notifier_Notifications {
11 +class Notifier_Notification_Triggers {
8 12
9 13 /**
10 14 * Init.
11 15 */
12 16 public static function init() {
13 - add_action( 'plugins_loaded', array( __CLASS__ , 'setup_triggers_action_hooks' ), 100 );
17 + add_filter( 'init', array( __CLASS__ , 'register_cpt') );
18 + add_action( 'admin_menu', array( __CLASS__ , 'setup_admin_page') );
19 + add_action( 'init', array( __CLASS__ , 'setup_triggers_action_hooks' ));
20 + add_action( 'wp_ajax_notifier_change_trigger_status', array(__CLASS__, 'notifier_change_trigger_status'));
21 + add_action( 'wp_ajax_notifier_fetch_trigger_fields', array(__CLASS__, 'notifier_fetch_trigger_fields'));
14 22 }
15 23
16 24 /**
25 + * Register custom post type.
26 + *
27 + * Always registered so existing v2 trigger posts remain accessible for
28 + * migration queries and backward-compat firing. The admin UI is hidden.
29 + */
30 + public static function register_cpt () {
31 + notifier_register_post_type('wa_notifier_trigger', 'Trigger', 'Triggers');
32 + }
33 +
34 + /**
35 + * Add page to admin menu.
36 + *
37 + * Hidden after migration is complete — users no longer need the CPT UI.
38 + */
39 + public static function setup_admin_page () {
40 + // v3: Trigger CPT menu items are always hidden.
41 + // The CPT is still registered (register_cpt) so posts exist and fire,
42 + // but users manage everything through the React Integrations UI.
43 + return;
44 + }
45 +
46 + /**
17 47 * Setup triggers action hooks
18 48 */
19 49 public static function setup_triggers_action_hooks() {
20 - $main_triggers = self::get_notification_triggers();
21 - foreach ($main_triggers as $key => $triggers) {
22 - foreach ($triggers as $trigger) {
23 - $hook = isset($trigger['action']['hook']) ? $trigger['action']['hook'] : '';
24 - $callback = isset($trigger['action']['callback']) ? $trigger['action']['callback'] : '';
25 - $priority = isset($trigger['action']['priority']) ? $trigger['action']['priority'] : 10;
26 - $args_num = isset($trigger['action']['args_num']) ? $trigger['action']['args_num'] : 1;
27 - if ('' == $hook || '' == $callback) {
28 - continue;
50 + // Legacy path: register hooks for CPT-enabled triggers.
51 + $triggers_to_register = self::get_enabled_notification_triggers();
52 +
53 + // v3 path: also register hooks for any trigger whose integration is connected,
54 + // regardless of whether a legacy CPT trigger exists.
55 + if ( class_exists( 'Notifier_Connection' ) ) {
56 + $all_triggers = self::get_notification_triggers();
57 + foreach ( $all_triggers as $group => $group_triggers ) {
58 + foreach ( $group_triggers as $trigger ) {
59 + $trigger_id = isset( $trigger['id'] ) ? $trigger['id'] : '';
60 + $base = self::get_trigger_id_without_site_key( $trigger_id );
61 + $slug = self::get_integration_slug_for_trigger( $base );
62 + if ( $slug && Notifier_Connection::is_connected( $slug ) ) {
63 + $triggers_to_register[] = $trigger;
64 + }
29 65 }
30 - add_action($hook, $callback, $priority, $args_num);
31 66 }
32 67 }
68 +
69 + // De-duplicate by trigger ID to avoid registering the same hook twice.
70 + $registered = array();
71 + foreach ( $triggers_to_register as $trigger ) {
72 + $trigger_id = isset( $trigger['id'] ) ? $trigger['id'] : '';
73 + $hook = isset( $trigger['action']['hook'] ) ? $trigger['action']['hook'] : '';
74 + $callback = isset( $trigger['action']['callback'] ) ? $trigger['action']['callback'] : '';
75 + $priority = isset( $trigger['action']['priority'] ) ? $trigger['action']['priority'] : 10;
76 + $args_num = isset( $trigger['action']['args_num'] ) ? $trigger['action']['args_num'] : 1;
77 + if ( '' === $hook || '' === $callback ) {
78 + continue;
79 + }
80 + $key = $trigger_id ?: ( $hook . '|' . ( is_string( $callback ) ? $callback : '' ) );
81 + if ( isset( $registered[ $key ] ) ) {
82 + continue;
83 + }
84 + $registered[ $key ] = true;
85 + add_action( $hook, $callback, $priority, $args_num );
86 + }
33 87 }
34 88
35 89 /**
36 90 * Get notification triggers
@@ -36,113 +90,518 @@
36 90 * Get notification triggers
37 91 */
38 92 public static function get_notification_triggers() {
39 93 $triggers = array();
40 - $triggers['WordPress'] = array (
41 - array(
42 - 'id' => 'new_post',
43 - 'label' => 'New post is published',
44 - 'description' => 'Send notification when a new post is published.',
45 - 'action' => array (
46 - 'hook' => 'transition_post_status',
47 - 'args_num' => 3,
48 - 'callback' => function ( $new_status, $old_status, $post ) {
49 - $notif_ids = self::trigger_has_active_notification('new_post');
50 - if (empty($notif_ids)) {
51 - return;
52 - }
94 + $args = array(
95 + 'public' => true,
96 + );
53 97
54 - if ('post' !== get_post_type($post)) {
55 - return;
56 - }
98 + $post_types = get_post_types( $args, 'objects');
57 99
58 - if ( 'publish' === $new_status && 'publish' !== $old_status ) {
59 - foreach ($notif_ids as $nid) {
60 - $args = array (
61 - 'object_type' => 'post',
62 - 'object_id' => $post->ID
63 - );
64 - Notifier_Notifications::send_triggered_notification($nid, $args);
65 - }
66 - }
67 - }
68 - )
100 + $triggers = array ();
101 + unset($post_types['attachment']);
69 102
70 - ),
71 - array(
72 - 'id' => 'new_comment',
73 - 'label' => 'New comment is added',
74 - 'description' => 'Send notification when a new comment is added.',
103 + foreach($post_types as $post){
104 + $post_slug = $post->name;
105 + $triggers['WordPress'][] = array(
106 + 'id' => 'new_'.$post->name,
107 + 'label' => 'New '.$post->labels->singular_name.' is published',
108 + 'description' => 'Trigger notification when a new '.$post->name.' is published.',
109 + 'merge_tags' => Notifier_Notification_Merge_Tags::get_merge_tags( Notifier_Notification_Merge_Tags::get_post_merge_tag_types( $post->labels->singular_name ) ),
110 + 'recipient_fields' => Notifier_Notification_Merge_Tags::get_recipient_fields( Notifier_Notification_Merge_Tags::get_post_recipient_types( $post->labels->singular_name ) ),
75 111 'action' => array (
76 - 'hook' => 'comment_post',
112 + 'hook' => 'publish_'.$post->name,
77 113 'args_num' => 3,
78 - 'callback' => function ( $comment_id, $comment_approved, $commentdata ) {
79 - $notif_ids = self::trigger_has_active_notification('new_comment');
80 - if (empty($notif_ids)) {
81 - return;
114 + 'callback' => function ( $post_id, $post, $old_status ) use ($post_slug) {
115 + if ( 'publish' !== $old_status ) {
116 + $args = array (
117 + 'object_type' => $post_slug,
118 + 'object_id' => $post->ID
119 + );
120 + self::send_trigger_request('new_'.$post_slug, $args);
82 121 }
83 - if ( 'spam' != $comment_approved) {
84 - foreach ($notif_ids as $nid) {
85 - $args = array (
86 - 'object_type' => 'comment',
87 - 'object_id' => $comment_id
88 - );
89 - Notifier_Notifications::send_triggered_notification($nid, $args);
90 - }
91 - }
122 + }
123 + ),
124 + );
125 + }
92 126
127 + $triggers['WordPress'][] = array(
128 + 'id' => 'new_comment',
129 + 'label' => 'New Comment is added',
130 + 'description' => 'Trigger notification when a new comment is added.',
131 + 'merge_tags' => Notifier_Notification_Merge_Tags::get_merge_tags( Notifier_Notification_Merge_Tags::get_comment_merge_tag_types() ),
132 + 'recipient_fields' => array(),
133 + 'action' => array (
134 + 'hook' => 'comment_post',
135 + 'args_num' => 3,
136 + 'callback' => function ( $comment_id, $comment_approved, $commentdata ) {
137 + if ( 'spam' != $comment_approved) {
138 + $args = array (
139 + 'object_type' => 'comment',
140 + 'object_id' => $comment_id
141 + );
142 + self::send_trigger_request('new_comment', $args);
93 143 }
94 - )
95 - ),
96 - array(
97 - 'id' => 'new_user',
98 - 'label' => 'New user is registered',
99 - 'description' => 'Send notification when a new user is created.',
100 - 'action' => array (
101 - 'hook' => 'user_register',
102 - 'callback' => function ( $user_id ) {
103 - $notif_ids = self::trigger_has_active_notification('new_user');
104 - if (empty($notif_ids)) {
105 - return;
106 - }
144 + }
145 + )
146 + );
107 147
108 - foreach ($notif_ids as $nid) {
109 - $args = array (
110 - 'object_type' => 'user',
111 - 'object_id' => $user_id
112 - );
113 - Notifier_Notifications::send_triggered_notification($nid, $args);
114 - }
115 - }
116 - )
148 + $triggers['WordPress'][] = array(
149 + 'id' => 'new_user',
150 + 'label' => 'New User is registered',
151 + 'description' => 'Trigger notification when a new user is created.',
152 + 'merge_tags' => Notifier_Notification_Merge_Tags::get_merge_tags( Notifier_Notification_Merge_Tags::get_user_merge_tag_types() ),
153 + 'recipient_fields' => Notifier_Notification_Merge_Tags::get_recipient_fields( Notifier_Notification_Merge_Tags::get_user_recipient_types() ),
154 + 'action' => array (
155 + 'hook' => 'user_register',
156 + 'callback' => function ( $user_id ) {
157 + $args = array (
158 + 'object_type' => 'user',
159 + 'object_id' => $user_id
160 + );
161 + self::send_trigger_request('new_user', $args);
162 + },
163 + 'priority' => 999
117 164 )
118 165 );
119 - return apply_filters('notifier_notification_triggers', $triggers);
166 +
167 + $triggers['WordPress'][] = array(
168 + 'id' => 'new_attachment',
169 + 'label' => 'New Media is uploded',
170 + 'description' => 'Trigger notification when a new attachement is uploded.',
171 + 'merge_tags' => Notifier_Notification_Merge_Tags::get_merge_tags( Notifier_Notification_Merge_Tags::get_attachment_merge_tag_types() ),
172 + 'recipient_fields' => Notifier_Notification_Merge_Tags::get_recipient_fields( Notifier_Notification_Merge_Tags::get_attachment_recipient_types() ),
173 + 'action' => array (
174 + 'hook' => 'add_attachment',
175 + 'callback' => function ( $attachement_id ) {
176 + $args = array (
177 + 'object_type' => 'attachment',
178 + 'object_id' => $attachement_id
179 + );
180 + self::send_trigger_request('new_attachment', $args);
181 + }
182 + )
183 + );
184 +
185 + $triggers = apply_filters('notifier_notification_triggers', $triggers);
186 +
187 + // Add site key to trigger IDs
188 + $site_key = self::get_notification_trigger_site_key();
189 +
190 + foreach ($triggers as $trigs_key => $trigs) {
191 + foreach($trigs as $trig_key => $trig){
192 + $triggers[$trigs_key][$trig_key]['id'] = $site_key . $trig['id'];
193 + }
194 + }
195 +
196 + return $triggers;
120 197 }
121 198
122 199 /**
123 - * Get notification triggers for dropdown
200 + * Get notification trigger site key
124 201 */
125 - public static function get_notification_triggers_dropdown() {
202 + public static function get_notification_trigger_site_key(){
203 + $site_key = get_option(NOTIFIER_PREFIX . 'site_key');
204 + if(!$site_key){
205 + $site_key = notifier_generate_random_key(5);
206 + update_option(NOTIFIER_PREFIX . 'site_key', $site_key, true);
207 + }
208 + $site_key = 'wp_' . $site_key . '_';
209 + return $site_key;
210 + }
211 +
212 + /**
213 + * Get notification trigger
214 + */
215 + public static function get_notification_trigger($trigger) {
216 + $trigger = self::get_trigger_id_with_site_key($trigger);
217 + $found_trigger = array();
126 218 $main_triggers = self::get_notification_triggers();
127 - $dropdown_triggers = array('' => 'Select a trigger');
128 219 foreach ($main_triggers as $key => $triggers) {
129 - $dropdown_triggers[$key] = wp_list_pluck($triggers, 'label', 'id');
220 + foreach($triggers as $the_trigger){
221 + if($the_trigger['id'] == $trigger){
222 + $found_trigger = $the_trigger;
223 + break 2;
224 + }
225 + }
130 226 }
131 - return $dropdown_triggers;
227 + return $found_trigger;
132 228 }
133 229
134 230 /**
135 - * Check whether current trigger has active notification
231 + * Get enabled notification triggers
136 232 */
137 - public static function trigger_has_active_notification($trigger) {
138 - $active_triggers = get_option('notifier_active_triggers');
233 + public static function get_enabled_notification_triggers() {
234 + $enabled_triggers = array();
235 + $enabled_post_ids = get_posts( array (
236 + 'post_type' => 'wa_notifier_trigger',
237 + 'post_status' => 'publish',
238 + 'numberposts' => -1,
239 + 'fields' => 'ids',
240 + 'meta_query' => array(
241 + array(
242 + 'key' => NOTIFIER_PREFIX . 'trigger_enabled',
243 + 'value' => 'yes',
244 + 'compare' => '='
245 + )
246 + )
247 + ) );
139 248
140 - $has_active_notification = false;
249 + if(!empty($enabled_post_ids)){
250 + foreach($enabled_post_ids as $enabled_post_id){
251 + $trigger_name = get_post_meta($enabled_post_id, NOTIFIER_PREFIX . 'trigger', true);
252 + $enabled_triggers[] = self::get_notification_trigger($trigger_name);
253 + }
254 + }
141 255
142 - if ( !empty($active_triggers) && !empty($active_triggers[$trigger])) {
143 - $has_active_notification = $active_triggers[$trigger];
256 + return $enabled_triggers;
257 + }
258 +
259 + /**
260 + * Check whether current trigger is in use
261 + */
262 + public static function is_trigger_in_use($trigger, $excluded_ids = array()) {
263 + $in_use = false;
264 + $in_use_post_id = get_posts( array (
265 + 'post_type' => 'wa_notifier_trigger',
266 + 'post_status' => 'publish',
267 + 'numberposts' => -1,
268 + 'fields' => 'ids',
269 + 'meta_query' => array(
270 + array(
271 + 'key' => NOTIFIER_PREFIX . 'trigger',
272 + 'value' => $trigger,
273 + 'compare' => '='
274 + )
275 + ),
276 + 'post__not_in' => $excluded_ids
277 + ) );
278 +
279 + if(!empty($in_use_post_id)){
280 + $in_use = $in_use_post_id[0];
144 281 }
145 282
146 - return $has_active_notification;
283 + return $in_use;
147 284 }
285 +
286 + /**
287 + * Send triggered notifications.
288 + *
289 + * Runs both paths simultaneously during migration:
290 + * - v3 path: dispatches via Action Scheduler when the integration is connected.
291 + * - Legacy path: fires via old API key until migration is complete.
292 + *
293 + * @param string $trigger Trigger ID (with site key prefix).
294 + * @param array $context_args Context arguments passed to payload builders.
295 + */
296 + public static function send_trigger_request( $trigger, $context_args ) {
297 + if ( empty( $context_args ) ) {
298 + return false;
299 + }
300 +
301 + $slug = self::get_integration_slug_for_trigger( $trigger );
302 +
303 + error_log( sprintf( 'Notifier [send_trigger_request] trigger=%s slug=%s', $trigger, $slug ) );
304 +
305 + // If the Woo plugin is active it owns all WooCommerce triggers — skip them here
306 + // so they are not double-fired. The Woo plugin registers its own action hooks.
307 + if ( 'woocommerce' === $slug && class_exists( 'WANOWC_Notification_Triggers' ) ) {
308 + error_log( 'Notifier [send_trigger_request] skipped — handed off to Woo plugin' );
309 + return false;
310 + }
311 +
312 + // v3 path: dispatch via Action Scheduler to SaaS integration endpoint.
313 + // Payload is built inside the async job to keep the main request fast.
314 + $is_connected = $slug && class_exists( 'Notifier_Connection' ) && Notifier_Connection::is_connected( $slug );
315 + error_log( sprintf( 'Notifier [send_trigger_request] is_connected=%s', $is_connected ? 'yes' : 'no' ) );
316 + if ( $is_connected ) {
317 + Notifier_Connection::dispatch_trigger( $slug, self::get_trigger_id_without_site_key( $trigger ), $context_args );
318 + }
319 +
320 + // Legacy path: fire via old API key until migration is complete.
321 + $migration_complete = class_exists( 'Notifier_Migration' ) && Notifier_Migration::is_migration_complete();
322 + error_log( sprintf( 'Notifier [send_trigger_request] migration_complete=%s', $migration_complete ? 'yes' : 'no' ) );
323 + if ( ! $migration_complete ) {
324 + self::send_legacy_trigger_request( $trigger, $context_args );
325 + }
326 + }
327 +
328 + /**
329 + * Fire a trigger via the legacy /api/v1/fire_notification endpoint.
330 + * Used during the transition period before migration is complete.
331 + *
332 + * @param string $trigger Trigger ID (with site key prefix).
333 + * @param array $context_args Context arguments.
334 + */
335 + private static function send_legacy_trigger_request( $trigger, $context_args ) {
336 + $api_key = trim( get_option( 'notifier_api_key', '' ) );
337 + if ( empty( $api_key ) ) {
338 + error_log( 'Notifier [send_legacy_trigger_request] skipped — no API key' );
339 + return;
340 + }
341 +
342 + // Send trigger in v2 format (wp_{key}_{slug}) so Phase 1 SaaS can rewrite and match notifications.
343 + $trigger = self::get_trigger_id_with_site_key( $trigger );
344 +
345 + error_log( sprintf( 'Notifier [send_legacy_trigger_request] trigger=%s', $trigger ) );
346 +
347 + // Look up the v2 CPT post for this trigger to get the user-selected fields.
348 + // This mirrors exactly what v2 sent — only the fields the user configured.
349 + $cpt_post = get_posts( array(
350 + 'post_type' => 'wa_notifier_trigger',
351 + 'post_status' => 'publish',
352 + 'numberposts' => 1,
353 + 'fields' => 'ids',
354 + 'meta_query' => array(
355 + array(
356 + 'key' => NOTIFIER_PREFIX . 'trigger',
357 + 'value' => $trigger,
358 + ),
359 + ),
360 + ) );
361 +
362 + // If no CPT post exists for this trigger, the user never configured it in v2 — don't send.
363 + if ( empty( $cpt_post ) ) {
364 + error_log( sprintf( 'Notifier [send_legacy_trigger_request] skipped — no CPT post for trigger=%s', $trigger ) );
365 + return;
366 + }
367 +
368 + $post_id = $cpt_post[0];
369 + $enabled_merge_tags = get_post_meta( $post_id, NOTIFIER_PREFIX . 'data_fields', true );
370 + $enabled_recipient_fields = get_post_meta( $post_id, NOTIFIER_PREFIX . 'recipient_fields', true );
371 + $enabled_merge_tags = is_array( $enabled_merge_tags ) ? $enabled_merge_tags : array();
372 + $enabled_recipient_fields = is_array( $enabled_recipient_fields ) ? $enabled_recipient_fields : array();
373 +
374 + // Resolve only the selected field values.
375 + $merge_tags_data = array();
376 + $recipient_fields = array();
377 + foreach ( $enabled_merge_tags as $tag_id ) {
378 + $merge_tags_data[ $tag_id ] = Notifier_Notification_Merge_Tags::get_trigger_merge_tag_value( $tag_id, $context_args );
379 + }
380 + foreach ( $enabled_recipient_fields as $field_id ) {
381 + $recipient_fields[ $field_id ] = Notifier_Notification_Merge_Tags::get_trigger_merge_tag_value( $field_id, $context_args );
382 + }
383 +
384 + error_log( sprintf( 'Notifier [send_legacy_trigger_request] recipient_fields before=%s', wp_json_encode( $recipient_fields ) ) );
385 + foreach ( $recipient_fields as $key => $value ) {
386 + $recipient_fields[ $key ] = notifier_maybe_add_default_country_code( notifier_sanitize_phone_number( (string) $value ) );
387 + }
388 + error_log( sprintf( 'Notifier [send_legacy_trigger_request] recipient_fields after=%s', wp_json_encode( $recipient_fields ) ) );
389 +
390 + $body = wp_json_encode( array(
391 + 'source' => 'wp',
392 + 'trigger' => $trigger,
393 + 'merge_tags_data' => $merge_tags_data,
394 + 'recipient_fields' => $recipient_fields,
395 + 'site_url' => site_url(),
396 + ) );
397 +
398 + error_log( 'Notifier: ' . $body );
399 +
400 + $url = untrailingslashit( NOTIFIER_APP_BASE_URL ) . '/' . NOTIFIER_APP_API_PATH . '/fire_notification?key=' . rawurlencode( $api_key );
401 +
402 + wp_remote_post( $url, array(
403 + 'headers' => array( 'Content-Type' => 'application/json; charset=utf-8' ),
404 + 'body' => $body,
405 + 'timeout' => 30,
406 + 'sslverify' => true,
407 + ) );
408 + }
409 +
410 + /**
411 + * Determine the integration slug for a given trigger ID.
412 + *
413 + * @param string $trigger Trigger ID (with or without site key prefix).
414 + * @return string|null Integration slug or null if not determinable.
415 + */
416 + public static function get_integration_slug_for_trigger( $trigger ) {
417 + $base = self::get_trigger_id_without_site_key( $trigger );
418 +
419 + // woocommerce_cart_abandonment_recovery falls through to the woocommerce_ prefix check below.
420 + if ( strpos( $base, 'woo_' ) === 0 || strpos( $base, 'woocommerce_' ) === 0 ) {
421 + return 'woocommerce';
422 + }
423 + if ( strpos( $base, 'gravityforms_' ) === 0 ) {
424 + return 'gravityforms';
425 + }
426 + if ( strpos( $base, 'cf7_' ) === 0 ) {
427 + return 'cf7';
428 + }
429 + if ( strpos( $base, 'wpf_' ) === 0 || strpos( $base, 'wpforms_' ) === 0 ) {
430 + return 'wpforms';
431 + }
432 + if ( strpos( $base, 'ninjaforms_' ) === 0 ) {
433 + return 'ninjaforms';
434 + }
435 + if ( strpos( $base, 'formidableforms_' ) === 0 || strpos( $base, 'formidable_' ) === 0 ) {
436 + return 'formidable';
437 + }
438 + if ( strpos( $base, 'fluentforms_' ) === 0 ) {
439 + return 'fluentforms';
440 + }
441 + if ( strpos( $base, 'forminator_' ) === 0 ) {
442 + return 'forminator';
443 + }
444 + if ( strpos( $base, 'sureforms_' ) === 0 ) {
445 + return 'sureforms';
446 + }
447 + if ( strpos( $base, 'wsform_' ) === 0 ) {
448 + return 'wsform';
449 + }
450 + // WordPress core triggers (new_post, new_user, new_comment, new_attachment, etc.)
451 + if ( in_array( $base, array( 'new_comment', 'new_user', 'new_attachment' ), true )
452 + || strpos( $base, 'new_' ) === 0 ) {
453 + return 'wordpress';
454 + }
455 +
456 + return null;
457 + }
458 +
459 + /**
460 + * Enable / disable trigger
461 + */
462 + public static function notifier_change_trigger_status(){
463 + // Security check: Verify user has manage_options capability
464 + if ( ! current_user_can( 'manage_options' ) ) {
465 + wp_send_json_error( array(
466 + 'message' => 'You do not have permission to perform this action.'
467 + ) );
468 + }
469 +
470 + // Verify nonce for additional security
471 + if ( ! wp_verify_nonce( $_POST['_wpnonce'] ?? '', 'notifier_change_trigger_status' ) ) {
472 + wp_send_json_error( array(
473 + 'message' => 'Security check failed.'
474 + ) );
475 + }
476 +
477 + $post_id = isset($_POST['post_id']) ? intval($_POST['post_id']) : 0;
478 + $enabled = isset($_POST['enabled']) ? sanitize_text_field($_POST['enabled']) : 'no';
479 +
480 + if('wa_notifier_trigger' != get_post_type($post_id)){
481 + wp_send_json( array(
482 + 'error' => true,
483 + 'message' => 'Invalid post type.'
484 + ) );
485 + }
486 +
487 + update_post_meta( $post_id, NOTIFIER_PREFIX . 'trigger_enabled' , $enabled);
488 + wp_send_json( array(
489 + 'error' => false,
490 + 'message' => 'Updated'
491 + ) );
492 + }
493 +
494 + /**
495 + * Fetch trigger fields for a speicific trigger
496 + */
497 + public static function notifier_fetch_trigger_fields(){
498 + // Security check: Verify user has manage_options capability
499 + if ( ! current_user_can( 'manage_options' ) ) {
500 + wp_send_json_error( array(
501 + 'message' => 'You do not have permission to perform this action.'
502 + ) );
503 + }
504 +
505 + // Verify nonce for additional security
506 + if ( ! wp_verify_nonce( $_POST['_wpnonce'] ?? '', 'notifier_fetch_trigger_fields' ) ) {
507 + wp_send_json_error( array(
508 + 'message' => 'Security check failed.'
509 + ) );
510 + }
511 +
512 + $post_id = isset($_POST['post_id']) ? intval($_POST['post_id']) : 0;
513 + $trigger = isset($_POST['trigger']) ? sanitize_text_field($_POST['trigger']) : '';
514 +
515 + $data_fields = get_post_meta( $post_id, NOTIFIER_PREFIX . 'data_fields', true);
516 + $recipient_fields = get_post_meta( $post_id, NOTIFIER_PREFIX . 'recipient_fields', true);
517 +
518 + // Backward compatibility for Woo recipient fields not starting with woo_order_
519 + if(!empty($recipient_fields)){
520 + if ( strpos($trigger, 'woo_order') !== false){
521 + foreach($recipient_fields as $key => $recipient_field){
522 + if (in_array($recipient_field, array('billing_phone', 'shipping_phone'))){
523 + $recipient_fields[$key] = 'woo_order_' . $recipient_field;
524 + }
525 + }
526 + }
527 + }
528 +
529 + $merge_tags = Notifier_Notification_Merge_Tags::get_trigger_merge_tags($trigger);
530 + $recipient_tags = Notifier_Notification_Merge_Tags::get_trigger_recipient_fields($trigger);
531 +
532 + ob_start();
533 + echo '<div class="trigger-fields-wrap"><div class="d-flex justify-content-between"><label class="form-label w-auto">Data fields</label><div class="small"><a href="#" class="notifier-select-all-checkboxes">select all</a> / <a href="#" class="notifier-unselect-all-checkboxes">unselect all</a></div></div>';
534 +
535 + notifier_wp_select( array(
536 + 'id' => NOTIFIER_PREFIX . 'data_fields',
537 + 'name' => NOTIFIER_PREFIX . 'data_fields[]',
538 + 'value' => $data_fields,
539 + 'label' => '',
540 + 'description' => '',
541 + 'placeholder' => 'Start typing here...',
542 + 'options' => $merge_tags,
543 + 'show_wrapper' => false,
544 + 'custom_attributes' => array('multiple' => 'multiple')
545 + ) );
546 +
547 + echo '<span class="description">Select the data fields that will be sent to WANotifier.com when the trigger happens. These fields will be available to map with message template variables like <code>{{1}}</code>, <code>{{2}}</code> etc when you <a href="https://app.wanotifier.com/notifications/add/" target="_blank">create a Notification</a>.</span></div>';
548 +
549 + if(!empty($recipient_tags)){
550 + echo '<div class="trigger-fields-wrap"><div class="d-flex justify-content-between"><label class="form-label w-auto">Recipient fields</label><div class="small"><a href="#" class="notifier-select-all-checkboxes">select all</a> / <a href="#" class="notifier-unselect-all-checkboxes">unselect all</a></div></div>';
551 +
552 + notifier_wp_select( array(
553 + 'id' => NOTIFIER_PREFIX . 'recipient_fields',
554 + 'name' => NOTIFIER_PREFIX . 'recipient_fields[]',
555 + 'value' => $recipient_fields,
556 + 'label' => '',
557 + 'description' => '',
558 + 'placeholder' => 'Start typing here...',
559 + 'options' => $recipient_tags,
560 + 'show_wrapper' => false,
561 + 'custom_attributes' => array('multiple' => 'multiple')
562 + ) );
563 +
564 + echo '<span class="description">Select the recipient fields that will be sent to WANotifier.com when this trigger happens. These fields will be available under <b>Recipients</b> section when you create a Notification. Note that the selected recipient fields <b>must return a phone number</b> with a country code (e.g. +919876543210) or the message wll not be sent.</span></div>';
565 + }
566 +
567 + $html = ob_get_clean();
568 +
569 + wp_send_json( array(
570 + 'status' => 'success',
571 + 'html' => $html
572 + ) );
573 + }
574 +
575 + /**
576 + * Get post trigger ID
577 + */
578 + public static function get_post_trigger_id($post_id){
579 + $site_key = self::get_notification_trigger_site_key();
580 + $selected_trigger = get_post_meta( $post_id, NOTIFIER_PREFIX . 'trigger', true);
581 + if($selected_trigger && strpos($selected_trigger, $site_key) === false ){
582 + $selected_trigger = $site_key . $selected_trigger;
583 + }
584 + return $selected_trigger;
585 + }
586 +
587 + /**
588 + * Get trigger ID with site key
589 + */
590 + public static function get_trigger_id_with_site_key($trigger_id){
591 + $site_key = self::get_notification_trigger_site_key();
592 + if( strpos($trigger_id, $site_key) === false ){
593 + $trigger_id = $site_key . $trigger_id;
594 + }
595 + return $trigger_id;
596 + }
597 +
598 + /**
599 + * Get trigger ID without site key
600 + */
601 + public static function get_trigger_id_without_site_key($trigger_id){
602 + $site_key = self::get_notification_trigger_site_key();
603 + $trigger_id = str_replace($site_key, '', $trigger_id);
604 + return $trigger_id;
605 + }
606 +
148 607 }