Below is a differential between the unpatched vulnerable code and the patched update, for reference.
--- 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
}