| @@ -35,26 +35,33 @@ | ||
| 35 | 35 | $xprofile->save(); |
| 36 | 36 | } |
| 37 | 37 | }); |
| 38 | 38 | |
| 39 | - add_action('wp_ajax_fluent_community_renew_nonce', function () { | |
| 39 | + add_action('wp_ajax_fluent_community_renew_nonce', [$this, 'renewNonce']); | |
| 40 | 40 | |
| 41 | - $ajax_nonce = Arr::get($_REQUEST, 'ajax_nonce'); // phpcs:ignore WordPress.Security.NonceVerification.Recommended | |
| 41 | + // Logged-out: without this, WP returns "0"/200 and the SPA loops on a stale nonce. | |
| 42 | + add_action('wp_ajax_nopriv_fluent_community_renew_nonce', function () { | |
| 43 | + wp_send_json(['message' => __('Your session has expired. Please log in again.', 'fluent-community')], 401); | |
| 44 | + }); | |
| 45 | + } | |
| 42 | 46 | |
| 43 | - if (!wp_verify_nonce($ajax_nonce, 'fluent_community_ajax_nonce')) { | |
| 44 | - wp_send_json(['message' => 'Invalid nonce'], 400); | |
| 45 | - } | |
| 47 | + public function renewNonce() | |
| 48 | + { | |
| 49 | + $ajax_nonce = Arr::get($_REQUEST, 'ajax_nonce'); // phpcs:ignore WordPress.Security.NonceVerification.Recommended | |
| 46 | 50 | |
| 47 | - $currentProfile = Helper::getCurrentProfile(); | |
| 48 | - if (!$currentProfile) { | |
| 49 | - wp_send_json(['message' => 'Invalid user'], 400); | |
| 50 | - } | |
| 51 | + if (!wp_verify_nonce($ajax_nonce, 'fluent_community_ajax_nonce')) { | |
| 52 | + wp_send_json(['message' => __('Invalid nonce', 'fluent-community')], 400); | |
| 53 | + } | |
| 51 | 54 | |
| 52 | - wp_send_json([ | |
| 53 | - 'rest_nonce' => wp_create_nonce('wp_rest'), | |
| 54 | - 'ajax_nonce' => wp_create_nonce('fluent_community_ajax_nonce'), | |
| 55 | - ], 200); | |
| 56 | - }); | |
| 55 | + $currentProfile = Helper::getCurrentProfile(); | |
| 56 | + if (!$currentProfile) { | |
| 57 | + wp_send_json(['message' => __('Invalid user', 'fluent-community')], 401); | |
| 58 | + } | |
| 59 | + | |
| 60 | + wp_send_json([ | |
| 61 | + 'rest_nonce' => wp_create_nonce('wp_rest'), | |
| 62 | + 'ajax_nonce' => wp_create_nonce('fluent_community_ajax_nonce'), | |
| 63 | + ], 200); | |
| 57 | 64 | } |
| 58 | 65 | |
| 59 | 66 | |
| 60 | 67 | public function handleNewCommentEvent($comment, $feed) |
| @@ -106,8 +113,16 @@ | ||
| 106 | 113 | { |
| 107 | 114 | $currentProfile = Helper::getCurrentProfile(); |
| 108 | 115 | |
| 109 | 116 | if (!$currentProfile) { |
| 117 | + return false; | |
| 118 | + } | |
| 119 | + | |
| 120 | + // Debounce: skip the write if last_activity was updated within the last 5 minutes. | |
| 121 | + // The ticker polls every ~45-75s per session; without this each poll issues an | |
| 122 | + // xprofile UPDATE, saturating the DB at scale. | |
| 123 | + $throttleSeconds = apply_filters('fluent_community/track_activity_throttle_seconds', 300); | |
| 124 | + if ($currentProfile->last_activity && (current_time('timestamp') - strtotime($currentProfile->last_activity)) < $throttleSeconds) { | |
| 110 | 125 | return false; |
| 111 | 126 | } |
| 112 | 127 | |
| 113 | 128 | $currentProfile->last_activity = current_time('mysql'); |