base64_encode(random_bytes(65)), 'private_key' => base64_encode(random_bytes(32)), 'generated_at' => current_time('mysql'), ]; } /** * Get VAPID public key * * @return string */ public static function get_public_key() { $keys = self::ensure_vapid_keys(); return $keys['public_key']; } /** * Subscribe to push notifications * * @param array $subscription Subscription data * @param int $user_id User ID * @return bool */ public static function subscribe($subscription, $user_id = 0) { $subscriptions = get_option(self::SUBSCRIPTIONS_KEY, []); $subscription_id = md5(json_encode($subscription)); $subscriptions[$subscription_id] = [ 'subscription' => $subscription, 'user_id' => $user_id, 'subscribed_at' => current_time('mysql'), ]; return update_option(self::SUBSCRIPTIONS_KEY, $subscriptions); } /** * Unsubscribe from push notifications * * @param string $subscription_id Subscription ID * @return bool */ public static function unsubscribe($subscription_id) { $subscriptions = get_option(self::SUBSCRIPTIONS_KEY, []); if (isset($subscriptions[$subscription_id])) { unset($subscriptions[$subscription_id]); return update_option(self::SUBSCRIPTIONS_KEY, $subscriptions); } return false; } /** * Get all subscriptions * * @param int $user_id Optional user ID filter * @return array */ public static function get_subscriptions($user_id = null) { $subscriptions = get_option(self::SUBSCRIPTIONS_KEY, []); if ($user_id !== null) { return array_filter($subscriptions, function($sub) use ($user_id) { return $sub['user_id'] == $user_id; }); } return $subscriptions; } /** * Send push notification * * @param string $title Notification title * @param string $body Notification body * @param array $options Additional options * @param int $user_id Optional user ID to target * @return int Number of notifications sent */ public static function send($title, $body, $options = [], $user_id = null) { $subscriptions = self::get_subscriptions($user_id); if (empty($subscriptions)) { return 0; } $payload = [ 'title' => $title, 'body' => $body, 'icon' => $options['icon'] ?? get_site_icon_url(), 'badge' => $options['badge'] ?? get_site_icon_url(), 'data' => $options['data'] ?? [], 'actions' => $options['actions'] ?? [], ]; $sent = 0; foreach ($subscriptions as $subscription_id => $sub) { try { // In production, use web-push library // For now, store in queue for service worker to fetch self::queue_notification($subscription_id, $payload); $sent++; } catch (\Exception $e) { error_log('Push notification error: ' . $e->getMessage()); } } return $sent; } /** * Queue notification for delivery * * @param string $subscription_id Subscription ID * @param array $payload Notification payload */ private static function queue_notification($subscription_id, $payload) { $queue = get_option('woonoow_push_queue', []); $queue[] = [ 'subscription_id' => $subscription_id, 'payload' => $payload, 'queued_at' => current_time('mysql'), ]; update_option('woonoow_push_queue', $queue); } /** * Get queued notifications for user * * @param int $user_id User ID * @return array */ public static function get_queued_notifications($user_id) { $queue = get_option('woonoow_push_queue', []); $subscriptions = self::get_subscriptions($user_id); $subscription_ids = array_keys($subscriptions); $user_notifications = array_filter($queue, function($item) use ($subscription_ids) { return in_array($item['subscription_id'], $subscription_ids); }); // Clear delivered notifications $remaining = array_filter($queue, function($item) use ($subscription_ids) { return !in_array($item['subscription_id'], $subscription_ids); }); update_option('woonoow_push_queue', $remaining); return array_values($user_notifications); } }