data['credentials']['subject'] ?? null; $pending = array_filter($store->data['jobs'], static fn($j)=>$j['subject'] === $subject && in_array($j['status'], ['GENERATING','PERSISTING'], true)); if (($pending || picsart_runtime_notifications($store)) && !wp_next_scheduled('picsart_runtime_poll',[get_current_user_id()])) wp_schedule_single_event(time() + 15,'picsart_runtime_poll',[get_current_user_id()]); } function picsart_runtime_notifications($store) { $subject = $store->data['credentials']['subject'] ?? null; if (!$subject) return []; $delivery = picsart_notification_preferences(['subject'=>$subject]); if (empty($delivery['enabledAt'])) return []; $prefs = picsart_runtime_preferences($store,$subject); $categories = ['GENERATING'=>'started','REVIEW'=>'ready','ACCEPTED'=>'ready','SAVED'=>'exports','ATTACHED'=>'exports','UNKNOWN_SUBMISSION'=>'attention','IMPORT_UNKNOWN'=>'attention','RECONCILIATION_REQUIRED'=>'attention']; $pending = []; foreach ($store->data['jobs'] as $job) { $category = $categories[$job['status']] ?? null; if ($job['subject'] !== $subject || $job['approvedAt'] < $delivery['enabledAt'] || !$category || empty($prefs[$category])) continue; $event = hash('sha256',$subject . ':' . $job['id'] . ':' . $category . ':' . ($category === 'exports' ? $job['status'] : '')); if (isset($store->data['notifications'][$event])) continue; $pending[$event] = ['eventId'=>$event,'subject'=>$subject,'jobId'=>$job['id'],'category'=>$category]; } return $pending; } function picsart_runtime_notify($store) { foreach (picsart_runtime_notifications($store) as $event=>$notification) { // Persist before delivery; a lost response never sends a duplicate email. $store->data['notifications'][$event] = 'unknown'; $store->save(); $result = picsart_send_notification($notification); $store->data['notifications'][$event] = is_wp_error($result) ? 'unknown' : ($result['status'] ?? 'unknown'); $store->save(); break; } } add_action('picsart_runtime_poll',static function($user_id) { $previous = get_current_user_id(); $store = null; wp_set_current_user(absint($user_id)); try { $prefs = get_user_meta(get_current_user_id(),'_picsart_preferences',true); if (!current_user_can('upload_files') || empty($prefs['consent'])) return; $store = new Picsart_Runtime_Store(); if (empty($store->data['credentials'])) return; // Only poll existing receipts. This worker never approves or submits a generation. picsart_runtime_tick($store); picsart_runtime_notify($store); } catch (Throwable $error) { // WP-Cron consumes the event before this callback. Contention must not lose it. if ($error instanceof Picsart_Runtime_Error && $error->reason === 'BUSY' && !wp_next_scheduled('picsart_runtime_poll',[absint($user_id)])) wp_schedule_single_event(time() + 30,'picsart_runtime_poll',[absint($user_id)]); } finally { if ($store) { picsart_runtime_schedule($store); $store->release(); } wp_set_current_user($previous); } });