| @@ -216,8 +216,9 @@ | ||
| 216 | 216 | $saas_base = NOTIFIER_APP_BASE_URL; |
| 217 | 217 | |
| 218 | 218 | $payload = base64_encode( wp_json_encode( array( |
| 219 | 219 | 'store_url' => site_url(), |
| 220 | + 'rest_url' => rest_url(), | |
| 220 | 221 | 'connect_token' => $token, |
| 221 | 222 | 'return_url' => admin_url( 'admin.php?page=notifier' ), |
| 222 | 223 | ) ) ); |
| 223 | 224 | |
| @@ -224,19 +225,21 @@ | ||
| 224 | 225 | return $saas_base . '/integrations/' . $slug . '/connect?payload=' . rawurlencode( $payload ); |
| 225 | 226 | } |
| 226 | 227 | |
| 227 | 228 | // ======================================== |
| 228 | - // 3. TRIGGER DISPATCH (v3 — always via Action Scheduler) | |
| 229 | + // 3. TRIGGER DISPATCH (v3) | |
| 229 | 230 | // ======================================== |
| 230 | 231 | |
| 231 | 232 | /** |
| 232 | - * Dispatch a trigger event via Action Scheduler. | |
| 233 | + * Dispatch a trigger event. | |
| 233 | 234 | * |
| 234 | - * Always async — AS provides built-in retry (3 attempts with backoff). | |
| 235 | + * Default: async via Action Scheduler — AS provides built-in retry (3 attempts with backoff). | |
| 236 | + * When the `notifier_disable_background_processing` option is `yes`, fires synchronously in the | |
| 237 | + * current request instead (no AS queueing, no retry, no dedupe). | |
| 235 | 238 | * |
| 236 | 239 | * @param string $slug Integration slug. |
| 237 | 240 | * @param string $trigger_slug Trigger slug (e.g. 'woo_order_new'). |
| 238 | - * @param array $payload Trigger payload with merge_tags_data and recipient_fields. | |
| 241 | + * @param array $context_args Context args (object_type, object_id, or form entry data). | |
| 239 | 242 | */ |
| 240 | 243 | public static function dispatch_trigger( $slug, $trigger_slug, $context_args ) { |
| 241 | 244 | if ( ! self::is_connected( $slug ) ) { |
| 242 | 245 | return; |
| @@ -241,8 +244,14 @@ | ||
| 241 | 244 | if ( ! self::is_connected( $slug ) ) { |
| 242 | 245 | return; |
| 243 | 246 | } |
| 244 | 247 | |
| 248 | + // Real-time mode: skip Action Scheduler and fire synchronously in the same request. | |
| 249 | + if ( 'yes' === get_option( 'notifier_disable_background_processing', 'no' ) ) { | |
| 250 | + self::handle_fire_trigger_action( $slug, $trigger_slug, $context_args ); | |
| 251 | + return; | |
| 252 | + } | |
| 253 | + | |
| 245 | 254 | $object_id = isset( $context_args['object_id'] ) ? (int) $context_args['object_id'] : 0; |
| 246 | 255 | Notifier_Backend::insert_activity_log( |
| 247 | 256 | 'debug', |
| 248 | 257 | sprintf( '[%s] Trigger scheduled: %s (object_id: %d)', $slug, $trigger_slug, $object_id ) |
| @@ -247,15 +256,33 @@ | ||
| 247 | 256 | 'debug', |
| 248 | 257 | sprintf( '[%s] Trigger scheduled: %s (object_id: %d)', $slug, $trigger_slug, $object_id ) |
| 249 | 258 | ); |
| 250 | 259 | |
| 260 | + $action_args = array( | |
| 261 | + 'slug' => $slug, | |
| 262 | + 'trigger_slug' => $trigger_slug, | |
| 263 | + 'context_args' => $context_args, | |
| 264 | + ); | |
| 265 | + | |
| 266 | + // Prevent duplicate actions for the same trigger + context. | |
| 267 | + $existing = as_get_scheduled_actions( array( | |
| 268 | + 'hook' => 'notifier_fire_trigger', | |
| 269 | + 'args' => $action_args, | |
| 270 | + 'group' => 'notifier', | |
| 271 | + 'status' => ActionScheduler_Store::STATUS_PENDING, | |
| 272 | + ), 'ids' ); | |
| 273 | + | |
| 274 | + if ( ! empty( $existing ) ) { | |
| 275 | + Notifier_Backend::insert_activity_log( | |
| 276 | + 'debug', | |
| 277 | + sprintf( '[%s] Duplicate trigger skipped: %s (object_id: %d)', $slug, $trigger_slug, $object_id ) | |
| 278 | + ); | |
| 279 | + return; | |
| 280 | + } | |
| 281 | + | |
| 251 | 282 | as_enqueue_async_action( |
| 252 | 283 | 'notifier_fire_trigger', |
| 253 | - array( | |
| 254 | - 'slug' => $slug, | |
| 255 | - 'trigger_slug' => $trigger_slug, | |
| 256 | - 'context_args' => $context_args, | |
| 257 | - ), | |
| 284 | + $action_args, | |
| 258 | 285 | 'notifier' |
| 259 | 286 | ); |
| 260 | 287 | } |
| 261 | 288 | |