Web Push Notification from Server Script

Function to send Web Push Notificatioin to single user. Copy the following code to the
Server Events → Global → All Pages → Global Code

function SendWebPushNotification($user, $title = "Notification", $body = "You have a new message") {
	if (!$user) return false;

	// Get config values from PHPMaker
	$tableName         = Config("SUBSCRIPTION_TABLE");
	$fieldUser         = Config("SUBSCRIPTION_FIELD_NAME_USER");
	$fieldEndpoint     = Config("SUBSCRIPTION_FIELD_NAME_ENDPOINT");
	$fieldPublicKey    = Config("SUBSCRIPTION_FIELD_NAME_PUBLIC_KEY");
	$fieldAuthToken    = Config("SUBSCRIPTION_FIELD_NAME_AUTH_TOKEN");
	$fieldEncoding     = Config("SUBSCRIPTION_FIELD_NAME_CONTENT_ENCODING");
	$vapidPublicKey    = Config("PUSH_SERVER_PUBLIC_KEY");
	$vapidPrivateKey   = Config("PUSH_SERVER_PRIVATE_KEY");

	// Validate VAPID keys
	if (!$vapidPublicKey || !$vapidPrivateKey) return false;

	// Fetch all subscriptions for the user
	$subscribers = ExecuteRows("SELECT * FROM `{$tableName}` WHERE `{$fieldUser}` = '" . AdjustSql($user) . "'");
	if (!$subscribers) return false;

	// VAPID auth config
	$auth = [
		'VAPID' => [
			'subject' => 'mailto:admin@yourdomain.com',
			'publicKey' => $vapidPublicKey,
			'privateKey' => $vapidPrivateKey
		]
	];
	$webPush = new \Minishlink\WebPush\WebPush($auth);

	$payload = json_encode(["title" => $title, "body" => $body]);

	$success = false;
	foreach ($subscribers as $row) {
		$subscription = \Minishlink\WebPush\Subscription::create([
			'endpoint' => $row[$fieldEndpoint],
			'publicKey' => $row[$fieldPublicKey],
			'authToken' => $row[$fieldAuthToken],
			'contentEncoding' => $row[$fieldEncoding]
		]);

		try {
			$report = $webPush->sendOneNotification($subscription, $payload);
			$success = true;
		} catch (\Exception $e) {
			// optionally log error: $e->getMessage()
		}
	}

	return $success;
}

How to use - just call the function

$title = "Notification";
$body = "You have a new message"
SendWebPushNotification($user, $title, $body) ;

Note : This does not work for Anonymous Users

Thanks for sharing the useful tips.

I modified your function, by adding some feedback messages, so that we are able to know the cause of issue when system failed to send notification to destination user.

function SendWebPushNotification($user, $title = "Notification", $body = "You have a new message") {
	
	$feedback = ""; //initial feedback;
	
	if (!$user) {
		$feedback = "User not defined on function call";
		return $feedback;
	}

	// Get config values from PHPMaker
	$tableName         = Config("SUBSCRIPTION_TABLE");
	$fieldUser         = Config("SUBSCRIPTION_FIELD_NAME_USER");
	$fieldEndpoint     = Config("SUBSCRIPTION_FIELD_NAME_ENDPOINT");
	$fieldPublicKey    = Config("SUBSCRIPTION_FIELD_NAME_PUBLIC_KEY");
	$fieldAuthToken    = Config("SUBSCRIPTION_FIELD_NAME_AUTH_TOKEN");
	$fieldEncoding     = Config("SUBSCRIPTION_FIELD_NAME_CONTENT_ENCODING");
	$vapidPublicKey    = Config("PUSH_SERVER_PUBLIC_KEY");
	$vapidPrivateKey   = Config("PUSH_SERVER_PRIVATE_KEY");

	// Validate VAPID keys
	if (!$vapidPublicKey || !$vapidPrivateKey) return false;

	// Fetch all subscriptions for the user
	$sql = "SELECT * FROM `{$tableName}` WHERE `{$fieldUser}` = '" . AdjustSql($user) . "'";
	$subscribers = ExecuteRows($sql);
	// echo "SQL: "  . $sql; // if you want to check the output of SQL
	if (!$subscribers) {
		$feedback = "Not found in subscriptions table";
		return $feedback;
	}
	
	// VAPID auth config
	$auth = [
		'VAPID' => [
			'subject' => 'mailto:admin@yourdomain.com',
			'publicKey' => $vapidPublicKey,
			'privateKey' => $vapidPrivateKey
		]
	];
	$webPush = new \Minishlink\WebPush\WebPush($auth);
	$payload = json_encode(["title" => $title, "body" => $body]);
	
	foreach ($subscribers as $row) {
		$subscription = \Minishlink\WebPush\Subscription::create([
			'endpoint' => $row[$fieldEndpoint],
			'publicKey' => $row[$fieldPublicKey],
			'authToken' => $row[$fieldAuthToken],
			'contentEncoding' => $row[$fieldEncoding]
		]);
		try {
			$report = $webPush->sendOneNotification($subscription, $payload);
			$feedback = "success";
		} catch (\Exception $e) {
			// optionally log error: 
			$feedback = $e->getMessage();
			
		}
	}
	return $feedback;
}

By modifying the function, then we can call and check the feedback message as follows:

        if (CurrentUserName() == "andrew") { // tested on demo2025 project by user andrew
            $title = "Notification";
    		$body = "You have a new message from andrew!";
    		$user = ""; // destination user
    		$feedback = SendWebPushNotification($user, $title, $body);
			if ($feedback == "success")
				$this->setSuccessMessage("Succeed to send Notification to user " . $user);
			else	
				$this->setFailureMessage("Failed to send Notification to user " . $user . ". Feedback: " . $feedback);
        }

Let’s say in the function call above, we have not defined the user, yet, then we will get the feedback message:
Failed to send Notification to user . Feedback: User not defined on function call.

Another failed case, if the destination user “999” is not found in subscriptions table, then we will get the feedback message:
Failed to send Notification to user 999. Feedback: Not found in subscriptions table

Or, another failed case, we have already defined the user = “1”, but when system failed to create the local key, then we will get the feedback message:
Failed to send Notification to user 1. Feedback: Unable to create the local key..