Changeset 3335490
- Timestamp:
- 07/28/2025 04:51:38 PM (7 months ago)
- Location:
- logtivity
- Files:
-
- 4 added
- 34 edited
- 1 copied
-
tags/3.2.0 (copied) (copied from logtivity/trunk)
-
tags/3.2.0/Admin/Logtivity_Log_Index_Controller.php (modified) (3 diffs)
-
tags/3.2.0/Admin/Logtivity_Options.php (modified) (5 diffs)
-
tags/3.2.0/Errors/Logtivity_Error_Logger.php (modified) (2 diffs)
-
tags/3.2.0/Helpers/Helpers.php (modified) (1 diff)
-
tags/3.2.0/Helpers/Logtivity_Log_Global_Function.php (modified) (1 diff)
-
tags/3.2.0/Logs/Core/Logtivity_Core.php (modified) (1 diff)
-
tags/3.2.0/Logs/Core/Logtivity_User.php (modified) (4 diffs)
-
tags/3.2.0/Logs/Memberpress/Logtivity_Memberpress.php (modified) (4 diffs)
-
tags/3.2.0/Services/Logtivity_Api.php (modified) (13 diffs)
-
tags/3.2.0/Services/Logtivity_Check_For_Disabled_Individual_Logs.php (modified) (1 diff)
-
tags/3.2.0/Services/Logtivity_Check_For_New_Settings.php (modified) (5 diffs)
-
tags/3.2.0/Services/Logtivity_JsonWebToken.php (added)
-
tags/3.2.0/Services/Logtivity_Logger.php (modified) (2 diffs)
-
tags/3.2.0/Services/Logtivity_Rest_Endpoints.php (added)
-
tags/3.2.0/assets/app.js (modified) (7 diffs)
-
tags/3.2.0/composer.json (modified) (1 diff)
-
tags/3.2.0/logtivity.php (modified) (11 diffs)
-
tags/3.2.0/readme.txt (modified) (2 diffs)
-
tags/3.2.0/views/_logs-loop.php (modified) (1 diff)
-
trunk/Admin/Logtivity_Log_Index_Controller.php (modified) (3 diffs)
-
trunk/Admin/Logtivity_Options.php (modified) (5 diffs)
-
trunk/Errors/Logtivity_Error_Logger.php (modified) (2 diffs)
-
trunk/Helpers/Helpers.php (modified) (1 diff)
-
trunk/Helpers/Logtivity_Log_Global_Function.php (modified) (1 diff)
-
trunk/Logs/Core/Logtivity_Core.php (modified) (1 diff)
-
trunk/Logs/Core/Logtivity_User.php (modified) (4 diffs)
-
trunk/Logs/Memberpress/Logtivity_Memberpress.php (modified) (4 diffs)
-
trunk/Services/Logtivity_Api.php (modified) (13 diffs)
-
trunk/Services/Logtivity_Check_For_Disabled_Individual_Logs.php (modified) (1 diff)
-
trunk/Services/Logtivity_Check_For_New_Settings.php (modified) (5 diffs)
-
trunk/Services/Logtivity_JsonWebToken.php (added)
-
trunk/Services/Logtivity_Logger.php (modified) (2 diffs)
-
trunk/Services/Logtivity_Rest_Endpoints.php (added)
-
trunk/assets/app.js (modified) (7 diffs)
-
trunk/composer.json (modified) (1 diff)
-
trunk/logtivity.php (modified) (11 diffs)
-
trunk/readme.txt (modified) (2 diffs)
-
trunk/views/_logs-loop.php (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
logtivity/tags/3.2.0/Admin/Logtivity_Log_Index_Controller.php
r3294349 r3335490 41 41 { 42 42 if (current_user_can(Logtivity::ACCESS_LOGS)) { 43 $response = (new Logtivity_Api()) 44 ->get( 45 '/logs', 46 [ 47 'page' => $this->getInput('page'), 48 'action' => $this->getInput('search_action'), 49 'context' => $this->getInput('search_context'), 50 'action_user' => $this->getInput('action_user'), 51 ] 52 ); 43 $api = Logtivity::log(); 53 44 54 if ($response) { 55 $this->successResponse(json_decode(json_encode($response))); 45 if ($api->getOption()->getApiKey()) { 46 $response = $api 47 ->get( 48 '/logs', 49 [ 50 'page' => $this->getInput('page'), 51 'action' => $this->getInput('search_action'), 52 'context' => $this->getInput('search_context'), 53 'action_user' => $this->getInput('action_user'), 54 ] 55 ); 56 56 57 } elseif ((new Logtivity_Options())->getApiKey() == false) { 58 $this->welcomeResponse(); 57 if ($response) { 58 $response = json_decode(json_encode($response)); 59 60 $this->renderView([ 61 'message' => $response->error, 62 'logs' => $response->body->data ?? [], 63 'meta' => $response->body->meta ?? null, 64 'hasNextPage' => $response->body->links->next ?? null, 65 ]); 66 } else { 67 $this->renderView($api->getConnectionMessage()); 68 } 59 69 60 70 } else { 61 $this-> errorResponse((new Logtivity_Api())->getConnectionMessage());71 $this->welcomeResponse(); 62 72 } 63 73 } else { 64 $this-> errorResponse(__('You do not have sufficient permissions to access this page.'));74 $this->renderView(__('You do not have sufficient permissions to access this page.')); 65 75 } 66 76 } 67 77 68 78 /** 69 * @param object $response 79 * @param string $field 80 * 81 * @return ?string 82 */ 83 protected function getInput(string $field): ?string 84 { 85 return sanitize_text_field($_GET[$field] ?? null); 86 } 87 88 /** 89 * @param string|array $response 70 90 * 71 91 * @return void 72 92 */ 73 pr ivate function successResponse(object $response): void93 protected function renderView($viewData): void 74 94 { 95 if (is_string($viewData)) { 96 $viewData = ['message' => $viewData]; 97 } 98 99 $viewData = array_merge( 100 [ 101 'message' => null, 102 'logs' => [], 103 'meta' => null, 104 'hasNextPage' => null, 105 ], 106 $viewData 107 ); 108 75 109 wp_send_json([ 76 'view' => logtivity_view('_logs-loop', [ 77 'logs' => $response->data, 78 'meta' => $response->meta, 79 'hasNextPage' => $response->links->next, 80 ]), 81 ]); 82 } 83 84 /** 85 * @param string $message 86 * 87 * @return void 88 */ 89 private function errorResponse(string $message): void 90 { 91 wp_send_json([ 92 'view' => logtivity_view('_logs-loop', [ 93 'message' => $message, 94 'logs' => [], 95 ]), 110 'view' => logtivity_view('_logs-loop', $viewData), 96 111 ]); 97 112 } … … 100 115 * @return void 101 116 */ 102 pr ivatefunction welcomeResponse()117 protected function welcomeResponse() 103 118 { 104 119 wp_send_json([ … … 109 124 ]); 110 125 } 111 112 /**113 * @param string $field114 *115 * @return ?string116 */117 private function getInput(string $field): ?string118 {119 return sanitize_text_field($_GET[$field] ?? null);120 }121 126 } 122 127 -
logtivity/tags/3.2.0/Admin/Logtivity_Options.php
r3306623 r3335490 28 28 class Logtivity_Options 29 29 { 30 /** 31 * Checkin for settings updates in designated minutes 32 * 33 * @var int 34 */ 35 protected int $checkinDelay = 10; 36 30 37 /** 31 38 * The option keys that we can save to the options table … … 175 182 176 183 if ($lastCheckin) { 177 return time() - strtotime($lastCheckin) > 10 * MINUTE_IN_SECONDS;184 return time() - strtotime($lastCheckin) > ($this->checkinDelay * MINUTE_IN_SECONDS); 178 185 } 179 186 } … … 232 239 public function update(array $data = [], bool $checkApiKey = true): void 233 240 { 234 if (count($data)) { 235 foreach ($this->settings as $setting => $default) { 236 if (array_key_exists($setting, $data) && $this->validateSetting($setting, $data[$setting])) { 237 update_option($setting, $data[$setting]); 238 } 239 } 240 } else { 241 foreach ($this->settings as $setting => $default) { 242 if (array_key_exists($setting, $_POST) && $this->validateSetting($setting, $_POST[$setting])) { 243 update_option($setting, $_POST[$setting]); 244 } 241 $settings = array_intersect_key($data ?: $_POST, $this->settings); 242 foreach ($settings as $key => $value) { 243 if ($this->validateSetting($key, $value)) { 244 update_option($key, $value); 245 245 } 246 246 } … … 249 249 $this->checkApiKey($data['logtivity_site_api_key'] ?? $_POST['logtivity_site_api_key'] ?? null); 250 250 } 251 } 252 253 /** 254 * Validate that the passed parameters are in the correct format 255 * 256 * @param string $key 257 * @param mixed $value 258 * 259 * @return bool 260 */ 261 protected function validateSetting(string $key, $value): bool 262 { 263 $setting = $this->settings[$key] ?? null; 264 265 if ($setting) { 266 $method = $setting['rule'] ?? null; 267 268 if ($method == 'is_bool') { 269 return $method((bool)$value); 270 } 271 272 return $method($value); 273 } 274 275 return true; 251 276 } 252 277 … … 262 287 ->setAction('Settings Updated') 263 288 ->setContext('Logtivity') 264 ->ignoreStatus()265 289 ->waitForResponse() 266 290 ->send(); 267 291 } 268 292 } 269 270 /**271 * Validate that the passed parameters are in the correct format272 *273 * @param string $key274 * @param mixed $value275 *276 * @return bool277 */278 protected function validateSetting(string $key, $value): bool279 {280 $setting = $this->settings[$key] ?? null;281 282 if ($setting) {283 $method = $setting['rule'] ?? null;284 285 if ($method == 'is_bool') {286 return $method((bool)$value);287 }288 289 return $method($value);290 }291 292 return true;293 }294 293 } -
logtivity/tags/3.2.0/Errors/Logtivity_Error_Logger.php
r3272661 r3335490 70 70 * @return ?array 71 71 */ 72 public function send(): ?array72 public function send(): void 73 73 { 74 74 $message = $this->error['message'] ?? ''; … … 79 79 80 80 if ($this->active) { 81 $ response = $this->makeRequest('/errors/store', $this->getData());81 $this->makeRequest('/errors/store', $this->getData()); 82 82 } 83 83 } 84 85 return $response ?? null;86 84 } 87 85 -
logtivity/tags/3.2.0/Helpers/Helpers.php
r3272661 r3335490 51 51 { 52 52 extract($vars); 53 unset($vars); 53 54 54 55 ob_start(); -
logtivity/tags/3.2.0/Helpers/Logtivity_Log_Global_Function.php
r3290027 r3335490 33 33 * @deprecated v3.1.8 - use Logtivity::log() instead 34 34 */ 35 function logtivity_log(?string $action = null, ?string $meta = null, ?string $user_id = null) 35 function logtivity_log(?string $action = null, ?string $meta = null, ?string $user_id = null): void 36 36 { 37 returnLogtivity::log($action, $meta, $user_id)->send();37 Logtivity::log($action, $meta, $user_id)->send(); 38 38 } -
logtivity/tags/3.2.0/Logs/Core/Logtivity_Core.php
r3290027 r3335490 197 197 ->setAction('Settings Updated') 198 198 ->setContext('Core:' . $optionPage) 199 ->ignoreStatus()200 199 ->send(); 201 200 } -
logtivity/tags/3.2.0/Logs/Core/Logtivity_User.php
r3272661 r3335490 25 25 class Logtivity_User extends Logtivity_Abstract_Logger 26 26 { 27 protected static $loggedUserlogin = false;27 protected static bool $loggedUserlogin = false; 28 28 29 29 /** 30 * @inheritDoc 30 * @param string $username 31 * @param WP_User $user 32 * 33 * @return void 31 34 */ 32 p rotected function registerHooks(): void35 public function userLoggedIn(string $username, WP_User $user) 33 36 { 34 add_action('wp_login', [$this, 'wpLogin'], 10, 2); 35 add_action('wp_logout', [$this, 'userLoggedOut'], 10, 1); 36 add_action('user_register', [$this, 'userCreated'], 10, 1); 37 add_action('delete_user', [$this, 'userDeleted']); 38 add_action('profile_update', [$this, 'profileUpdated'], 10, 2); 37 if (static::$loggedUserlogin == false) { 38 static::$loggedUserlogin = true; 39 40 $logger = Logtivity::log()->setUser($user->ID); 41 42 $logger->setAction('User Logged In') 43 ->setContext($logger->user->getRole()) 44 ->send(); 45 } 39 46 } 40 47 41 public function wpLogin($user_login, $user) 48 /** 49 * @param int $userId 50 * 51 * @return void 52 */ 53 public function userLoggedOut(int $userId): void 42 54 { 43 if (self::$loggedUserlogin) { 44 return; 55 if ($userId) { 56 $logger = Logtivity::log()->setUser($userId); 57 58 $logger 59 ->setAction('User Logged Out') 60 ->setContext($logger->user->getRole()) 61 ->send(); 45 62 } 46 47 return $this->userLoggedIn($user->ID);48 63 } 49 64 50 public function userLoggedIn($user_id) 51 { 52 self::$loggedUserlogin = true; 53 54 $logtivityUser = new Logtivity_WP_User($user_id); 55 56 return (new Logtivity_Logger($user_id)) 57 ->setAction('User Logged In') 58 ->setContext($logtivityUser->getRole()) 59 ->send(); 60 } 61 62 public function userLoggedOut($user_id) 63 { 64 if ($user_id == 0) { 65 return; 66 } 67 68 $user = new Logtivity_WP_User($user_id); 69 70 return (new Logtivity_Logger($user_id)) 71 ->setAction('User Logged Out') 72 ->setContext($user->getRole()) 73 ->send(); 74 } 75 76 public function userCreated($user_id) 65 /** 66 * @param int $userId 67 * 68 * @return void 69 */ 70 public function userCreated(int $userId): void 77 71 { 78 72 $log = Logtivity::log(); 79 73 80 if (!is_user_logged_in()) { 81 $log->setUser($user_id); 74 if (is_user_logged_in() == false) { 75 $log->setUser($userId); 76 $user = $log->user; 77 } else { 78 $user = new Logtivity_WP_User($userId); 82 79 } 83 84 $user = new Logtivity_WP_User($user_id);85 80 86 81 $log->setAction('User Created') … … 90 85 } 91 86 92 public function userDeleted($user_id) 87 /** 88 * @param int $userId 89 * 90 * @return void 91 */ 92 public function userDeleted(int $userId): void 93 93 { 94 $user = new Logtivity_WP_User($user _id);94 $user = new Logtivity_WP_User($userId); 95 95 96 96 Logtivity::log() … … 101 101 } 102 102 103 public function profileUpdated($user _id, $old_user_data)103 public function profileUpdated($userId) 104 104 { 105 $user = new Logtivity_WP_User($user _id);105 $user = new Logtivity_WP_User($userId); 106 106 107 107 Logtivity::log() … … 111 111 ->send(); 112 112 } 113 114 /** 115 * @inheritDoc 116 */ 117 protected function registerHooks(): void 118 { 119 add_action('wp_login', [$this, 'userLoggedIn'], 10, 2); 120 add_action('wp_logout', [$this, 'userLoggedOut'], 10, 1); 121 add_action('user_register', [$this, 'userCreated'], 10, 1); 122 add_action('delete_user', [$this, 'userDeleted']); 123 add_action('profile_update', [$this, 'profileUpdated'], 10, 1); 124 } 113 125 } 114 126 -
logtivity/tags/3.2.0/Logs/Memberpress/Logtivity_Memberpress.php
r3272661 r3335490 25 25 class Logtivity_Memberpress extends Logtivity_Abstract_Logger 26 26 { 27 /** 28 * @inheritDoc 29 */ 30 protected function registerHooks(): void 31 { 32 add_action('mepr-event-member-signup-completed', [$this, 'freeSubscriptionCreated']); 33 add_action('mepr-event-subscription-created', [$this, 'subscriptionCreated']); 34 add_action('mepr-event-subscription-paused', [$this, 'subscriptionPaused']); 35 add_action('mepr-event-subscription-resumed', [$this, 'subscriptionResumed']); 36 add_action('mepr-event-subscription-stopped', [$this, 'subscriptionStopped']); 37 add_action('init', [$this, 'profileUpdated']); 38 add_filter('mepr_create_transaction', [$this, 'transactionCreated'], 10, 3); 39 add_filter('mepr_update_transaction', [$this, 'transactionUpdated'], 10, 3); 40 add_action('mepr_email_sent', [$this, 'emailSent'], 10, 3); 41 add_action('mepr-process-options', [$this, 'settingsUpdated'], 10, 1); 42 } 43 44 public function freeSubscriptionCreated($event) 27 public function freeSubscriptionCreated($event): void 45 28 { 46 29 $user = $event->get_data(); 47 30 $subscription = $this->getSubscription($user); 48 31 49 if (!$subscription) { 50 return; 32 if ($subscription && $subscription->gateway == 'free') { 33 $product = $subscription->product(); 34 35 Logtivity::log( 36 'Free Subscription Created', 37 [ 38 'Subscription ID' => $subscription->id, 39 ] 40 ) 41 ->setContext($product->post_title) 42 ->send(); 51 43 } 52 53 if ($subscription->gateway != 'free') {54 return;55 }56 57 $product = $subscription->product();58 59 return (new Logtivity_Logger($user->ID))60 ->setAction('Free Subscription Created')61 ->setContext($product->post_title)62 ->addMeta('Subscription ID', $subscription->id)63 ->send();64 44 } 65 45 … … 73 53 } 74 54 75 public function subscriptionCreated($event) 55 /** 56 * @param $event 57 * 58 * @return void 59 */ 60 public function subscriptionCreated($event): void 76 61 { 77 62 $subscription = $event->get_data(); … … 80 65 $paymentMethod = $subscription->payment_method(); 81 66 82 return (new Logtivity_Logger($user->ID)) 83 ->setAction('Subscription Created') 67 Logtivity::log( 68 'Subscription Created', 69 [ 70 'Transaction Total' => $subscription->total, 71 'Payment Method' => $paymentMethod->name, 72 'Subscription ID' => $subscription->id, 73 ], 74 $user->ID 75 ) 84 76 ->setContext($product->post_title) 85 ->addMeta('Transaction Total', $subscription->total)86 ->addMeta('Payment Method', $paymentMethod->name)87 ->addMeta('Subscription ID', $subscription->id)88 77 ->send(); 89 78 } … … 188 177 ->send(); 189 178 } 179 180 /** 181 * @inheritDoc 182 */ 183 protected function registerHooks(): void 184 { 185 add_action('mepr-event-member-signup-completed', [$this, 'freeSubscriptionCreated']); 186 add_action('mepr-event-subscription-created', [$this, 'subscriptionCreated']); 187 add_action('mepr-event-subscription-paused', [$this, 'subscriptionPaused']); 188 add_action('mepr-event-subscription-resumed', [$this, 'subscriptionResumed']); 189 add_action('mepr-event-subscription-stopped', [$this, 'subscriptionStopped']); 190 add_action('init', [$this, 'profileUpdated']); 191 add_filter('mepr_create_transaction', [$this, 'transactionCreated'], 10, 3); 192 add_filter('mepr_update_transaction', [$this, 'transactionUpdated'], 10, 3); 193 add_action('mepr_email_sent', [$this, 'emailSent'], 10, 3); 194 add_action('mepr-process-options', [$this, 'settingsUpdated'], 10, 1); 195 } 190 196 } 191 197 -
logtivity/tags/3.2.0/Services/Logtivity_Api.php
r3306623 r3335490 25 25 class Logtivity_Api 26 26 { 27 public const CURL_TIMEOUT = 28; 28 29 /** 30 * @var array 31 */ 32 protected static $responseData = [ 33 'code' => null, 34 'message' => null, 35 'error' => null, 36 'body' => null, 37 ]; 38 27 39 /** 28 40 * Option class to access the plugin settings … … 62 74 * @return $this 63 75 */ 64 public function waitForResponse(): self65 { 66 $this-> waitForResponse= true;76 public function ignoreStatus(): self 77 { 78 $this->ignoreStatus = true; 67 79 68 80 return $this; 69 }70 71 /**72 * @return $this73 */74 public function ignoreStatus(): self75 {76 $this->ignoreStatus = true;77 78 return $this;79 }80 81 /**82 * @param string $endpoint83 *84 * @return string85 */86 public function getEndpoint(string $endpoint): string87 {88 return logtivity_get_api_url() . $endpoint;89 81 } 90 82 … … 98 90 { 99 91 return $this->makeRequest($url, $body); 100 }101 102 /**103 * @param string $url104 * @param ?array $body105 *106 * @return ?array107 */108 public function get(string $url, ?array $body = null): ?array109 {110 return $this->waitForResponse()->makeRequest($url, $body, 'GET');111 }112 113 /**114 * @return ?string115 */116 public function getApiKey(): ?string117 {118 if ($this->api_key == false) {119 $this->api_key = $this->options->getApiKey();120 }121 122 return $this->api_key;123 }124 125 /**126 * @param string $apikey127 *128 * @return $this129 */130 public function setApiKey(string $apikey): self131 {132 $this->api_key = $apikey;133 134 return $this;135 92 } 136 93 … … 151 108 152 109 if ($this->ready()) { 153 if ($this-> options->getOption('logtivity_app_verify_url')) {110 if ($this->getOption('logtivity_app_verify_url')) { 154 111 $body = array_merge( 155 112 $body ?: [], … … 177 134 // @TODO: Switch to Logtivity_Response class to get standardized responses 178 135 $response = wp_remote_request($this->getEndpoint($url), $request); 179 if ($ this->notUpdatingWidgetInCustomizer()) {136 if ($waitForResponse && $this->notUpdatingWidgetInCustomizer()) { 180 137 // We waited and received a response 181 138 if ($response instanceof WP_Error) { 182 $responseData = [139 $responseData = array_merge(static::$responseData, [ 183 140 'code' => 500, 184 141 'message' => $response->get_error_code(), 185 142 'error' => $response->get_error_message() ?: $response->get_error_code(), 186 143 'body' => get_object_vars($response), 187 ] ;144 ]); 188 145 189 146 } else { … … 197 154 $responseError = $responseMessage; 198 155 $responseMessage = (($responseBody['message'] ?? $responseMessage) ?: 'Unknown error'); 199 200 156 } 201 157 $responseData = [ … … 207 163 } 208 164 165 $newStatus = 'success'; 209 166 if ($responseData['code']) { 210 167 if ($responseData['code'] < 400) { 211 168 // Successful request, check if api is telling us to pause 212 $newStatus = $responseData['error'] ? 'paused' : 'success'; 213 $this->updateSettings($response['body']); 169 if ($responseData['error']) { 170 $newStatus = 'paused'; 171 } 172 173 $body = json_decode($response['body'] ?? 'null', true); 174 $this->updateSettings($body['settings'] ?? []); 214 175 215 176 } else { 216 // Something went wrong submitting the api request 217 $newStatus = 'fail'; 218 update_option('logtivity_last_settings_check_in_at', ['date' => date('Y-m-d H:i:s')]); 177 if ($this->getCurlError($responseData['error']) != static::CURL_TIMEOUT) { 178 // Something other than a timeout went wrong with the request 179 $newStatus = 'fail'; 180 } 181 182 $this->updateLastCheckin(); 219 183 } 220 184 … … 229 193 ); 230 194 231 return $responseData ['body'];195 return $responseData; 232 196 } 233 197 } … … 238 202 239 203 /** 204 * @return bool 205 */ 206 protected function ready(): bool 207 { 208 return ($this->getApiKey()) 209 && logtivity_has_site_url_changed() == false 210 && ( 211 $this->ignoreStatus 212 || $this->getOption('logtivity_api_key_check') == 'success' 213 || $this->options->shouldCheckInWithApi() 214 ); 215 } 216 217 /** 218 * @return ?string 219 */ 220 public function getApiKey(): ?string 221 { 222 if ($this->api_key == false) { 223 $this->api_key = $this->options->getApiKey(); 224 } 225 226 return $this->api_key; 227 } 228 229 /** 230 * @param string $apikey 231 * 232 * @return $this 233 */ 234 public function setApiKey(string $apikey): self 235 { 236 $this->api_key = $apikey; 237 238 return $this; 239 } 240 241 /** 242 * @param ?string $key 243 * 244 * @return Logtivity_Options|mixed 245 */ 246 public function getOption(?string $key = null) 247 { 248 if ($key) { 249 return $this->options->getOption($key); 250 } 251 252 return $this->options; 253 } 254 255 /** 256 * @param string $endpoint 257 * 258 * @return string 259 */ 260 public function getEndpoint(string $endpoint): string 261 { 262 return logtivity_get_api_url() . $endpoint; 263 } 264 265 /** 266 * You cannot call an extra update_option during a widget update so we make 267 * sure not to log the most recent log response in this case. 268 * 269 * @return bool 270 */ 271 protected function notUpdatingWidgetInCustomizer(): bool 272 { 273 $customize = sanitize_text_field($_POST['wp_customize'] ?? null); 274 $action = sanitize_text_field($_POST['action'] ?? null); 275 276 return ($action == 'update-widget' && $customize == 'on') == false; 277 } 278 279 /** 240 280 * @param array|object $body 241 281 * 242 282 * @return void 243 283 */ 244 public function updateSettings($body): void 245 { 246 $settings = (object)($body->settings ?? $body['settings'] ?? null); 247 284 public function updateSettings(array $settings): void 285 { 248 286 if ($settings) { 249 $this->options->update( 250 [ 251 'logtivity_global_disabled_logs' => $settings->disabled_logs ?? null, 252 'logtivity_enable_white_label_mode' => $settings->enable_white_label_mode ?? null, 253 'logtivity_disabled_error_levels' => $settings->disabled_error_levels ?? null, 254 'logtivity_disable_error_logging' => $settings->disable_error_logging ?? null, 255 'logtivity_hide_plugin_from_ui' => $settings->hide_plugin_from_ui ?? null, 256 'logtivity_disable_default_logging' => $settings->disable_default_logging ?? null, 257 'logtivity_enable_options_table_logging' => $settings->enable_options_table_logging ?? null, 258 'logtivity_enable_post_meta_logging' => $settings->enable_post_meta_logging ?? null, 259 'logtivity_custom_plugin_name' => $settings->custom_plugin_name ?? null, 260 ], 261 false 262 ); 263 264 update_option('logtivity_last_settings_check_in_at', ['date' => date('Y-m-d H:i:s')]); 265 } 287 $verifiedSettings = []; 288 foreach ($settings as $key => $value) { 289 if ($key == 'disabled_logs') { 290 $key = 'global_' . $key; 291 } 292 $verifiedSettings['logtivity_' . $key] = is_null($value) ? '' : $value; 293 } 294 295 $this->options->update($verifiedSettings, false); 296 } 297 298 $this->updateLastCheckin(); 299 } 300 301 /** 302 * @return void 303 */ 304 protected function updateLastCheckin(): void 305 { 306 update_option('logtivity_last_settings_check_in_at', ['date' => date('Y-m-d H:i:s')]); 307 } 308 309 /** 310 * @param ?string $message 311 * 312 * @return int 313 */ 314 protected function getCurlError(?string $message): ?int 315 { 316 preg_match('/curl\s+error\s+(\d+)/i', $message, $matches); 317 318 return $matches[1] ?? null; 266 319 } 267 320 … … 271 324 public function getLatestResponse(): ?array 272 325 { 273 $response = $this-> options->getOption('logtivity_latest_response');326 $response = $this->getOption('logtivity_latest_response'); 274 327 275 328 return $response ?: null; … … 277 330 278 331 /** 279 * @return ?string 280 */ 281 public function getConnectionStatus(): ?string 282 { 283 $status = null; 284 $apiKey = $this->getApiKey(); 285 286 if ($apiKey) { 287 $status = $this->options->getOption('logtivity_api_key_check'); 288 } 289 290 return $status; 332 * @param string $url 333 * @param ?array $body 334 * 335 * @return ?array 336 */ 337 public function get(string $url, ?array $body = null): ?array 338 { 339 return $this->waitForResponse()->makeRequest($url, $body, 'GET'); 340 } 341 342 /** 343 * @return $this 344 */ 345 public function waitForResponse(): self 346 { 347 $this->waitForResponse = true; 348 349 return $this; 291 350 } 292 351 … … 310 369 $error = $this->getLatestResponse(); 311 370 $code = $error['code'] ?? null; 312 $message = $error[' message'] ?? null;371 $message = $error['error'] ?? $error['message'] ?? null; 313 372 314 373 if ($code && $message) { … … 329 388 330 389 /** 331 * You cannot call an extra update_option during a widget update so we make 332 * sure not to log the most recent log response in this case. 333 * 334 * @return bool 335 */ 336 private function notUpdatingWidgetInCustomizer(): bool 337 { 338 $customize = sanitize_text_field($_POST['wp_customize'] ?? null); 339 $action = sanitize_text_field($_POST['action'] ?? null); 340 341 return ($action == 'update-widget' && $customize == 'on') == false; 342 } 343 344 /** 345 * @return bool 346 */ 347 private function ready(): bool 348 { 349 //var_dump($this->ignoreStatus); 350 return ($this->getApiKey()) 351 && logtivity_has_site_url_changed() == false 352 && ( 353 $this->ignoreStatus 354 || $this->options->getOption('logtivity_api_key_check') == 'success' 355 || $this->options->shouldCheckInWithApi() 356 ); 390 * @return ?string 391 */ 392 public function getConnectionStatus(): ?string 393 { 394 $status = null; 395 $apiKey = $this->getApiKey(); 396 397 if ($apiKey) { 398 $status = $this->getOption('logtivity_api_key_check'); 399 } 400 401 return $status; 357 402 } 358 403 } -
logtivity/tags/3.2.0/Services/Logtivity_Check_For_Disabled_Individual_Logs.php
r3246625 r3335490 25 25 class Logtivity_Check_For_Disabled_Individual_Logs 26 26 { 27 public function __construct() 28 { 29 add_action('wp_logtivity_instance', [$this, 'handle'], 10, 999); 30 } 27 /** 28 * @var Logtivity_Options 29 */ 30 protected Logtivity_Options $options; 31 31 32 public function handle($Logtivity_Logger) 33 { 34 foreach ($this->getLogsToExclude() as $log) { 35 if ($this->check($Logtivity_Logger, $log)) { 36 $Logtivity_Logger->stop(); 37 } 38 } 32 public function __construct() 33 { 34 add_action('wp_logtivity_instance', [$this, 'handle'], 10, 2); 35 } 39 36 40 foreach ($this->globalLogsToExclude() as $log) { 41 if ($this->check($Logtivity_Logger, $log)) { 42 $Logtivity_Logger->stop(); 43 } 44 } 45 } 37 /** 38 * @param Logtivity_Logger $logger 39 * 40 * @return void 41 */ 42 public function handle(Logtivity_Logger $logger): void 43 { 44 // Refresh options whenever invoked 45 $this->options = new Logtivity_Options(); 46 46 47 public function check($Logtivity_Logger, $log) 48 { 49 $array = explode('&&', $log); 47 $exclusions = array_unique( 48 array_merge( 49 $this->parseExcludeEntries('logtivity_disable_individual_logs'), 50 $this->parseExcludeEntries('logtivity_global_disabled_logs') 51 ) 52 ); 50 53 51 if (isset($array[0]) && isset($array[1])) { 52 if (trim($array[0]) === '*' && trim($array[1]) === '*') { 53 return; 54 } 55 if ($this->matches($Logtivity_Logger->action, $array[0]) && $this->matches($Logtivity_Logger->context, $array[1])) { 56 return true; 57 } 58 } elseif(isset($array[0])) { 59 if (trim($array[0]) === '*') { 60 return; 61 } 62 if ($this->matches($Logtivity_Logger->action, $array[0])) { 63 return true; 64 } 65 } 66 return false; 67 } 54 foreach ($exclusions as $exclusion) { 55 if ($this->isDisabled($logger, $exclusion)) { 56 $logger->stop(); 68 57 69 private function matches($keyword, $disabledKeyword) 70 { 71 // @TODO: this may not be the best way to check the arguments 72 if (is_string($keyword) && is_string($disabledKeyword)) { 73 $keyword = trim(strtolower($keyword)); 74 $disabledKeyword = trim(strtolower($disabledKeyword)); 58 return; 59 } 60 } 61 } 75 62 76 if ($disabledKeyword === '*') { 77 return true; 78 } 63 /** 64 * @param string $option 65 * 66 * @return array 67 */ 68 protected function parseExcludeEntries(string $option): array 69 { 70 $value = (string)$this->options->getOption($option); 79 71 80 if (strpos($disabledKeyword, '*') !== false) { 81 return strpos($keyword, str_replace('*', '', $disabledKeyword)) !== false; 82 } 72 $entries = preg_split("/\\r\\n|\\r|\\n/", $value); 83 73 84 return $keyword == $disabledKeyword;85 }74 return array_unique(array_filter($entries)); 75 } 86 76 87 return false; 88 } 77 /** 78 * @param Logtivity_Logger $logger 79 * @param string $exclusion 80 * 81 * @return bool 82 */ 83 protected function isDisabled(Logtivity_Logger $logger, string $exclusion): bool 84 { 85 $array = explode('&&', $exclusion); 86 $action = strtolower(trim((string)array_shift($array))); 87 $context = strtolower(trim((string)array_shift($array))); 89 88 90 private function getLogsToExclude() 91 { 92 $value = (new Logtivity_Options)->getOption('logtivity_disable_individual_logs'); 89 if ($action == '*' && $context == '*') { 90 return false; 91 } elseif ($this->matches($logger->action, $action) && $this->matches($logger->context, $context)) { 92 return true; 93 } elseif ($action == '*') { 94 return false; 95 } elseif ($this->matches($logger->action, $action)) { 96 return true; 97 } 93 98 94 if ($value == '') { 95 return []; 96 } 99 return false; 100 } 97 101 98 return preg_split("/\\r\\n|\\r|\\n/", $value); 99 } 102 /** 103 * @param ?string $keywordTarget 104 * @param ?string $keywordCheck 105 * 106 * @return bool 107 */ 108 protected function matches(?string $keywordTarget, ?string $keywordCheck): bool 109 { 110 $keywordTarget = strtolower(trim((string)$keywordTarget)); 111 $keywordCheck = strtolower(trim((string)$keywordCheck)); 100 112 101 public function globalLogsToExclude() 102 { 103 $value = (new Logtivity_Options)->getOption('logtivity_global_disabled_logs'); 113 if ($keywordTarget && $keywordCheck) { 114 if ($keywordCheck == '*') { 115 return true; 116 } 104 117 105 if ($value == '') { 106 return []; 107 } 118 if (strpos($keywordCheck, '*') !== false) { 119 $regex = str_replace(['*', '/'], ['.*?', '\/'], $keywordCheck); 120 return preg_match('/' . $regex . '/', $keywordTarget); 121 } 108 122 109 return preg_split("/\\r\\n|\\r|\\n/", $value); 110 } 123 return $keywordCheck == $keywordTarget; 124 } 125 126 return false; 127 } 111 128 } 112 129 113 $CheckForDisabledIndividualLogs = new Logtivity_Check_For_Disabled_Individual_Logs;130 new Logtivity_Check_For_Disabled_Individual_Logs(); -
logtivity/tags/3.2.0/Services/Logtivity_Check_For_New_Settings.php
r3290027 r3335490 41 41 42 42 /** 43 * @return bool 44 */ 45 public function shouldCheckInWithApi(): bool 46 { 47 return (new Logtivity_Options())->shouldCheckInWithApi(); 48 } 49 50 /** 43 51 * @return void 44 52 */ … … 53 61 54 62 try { 55 $api = new Logtivity_Api();56 57 63 $theme = wp_get_theme(); 58 64 … … 63 69 $latestMinMySqlVersion = $coreUpdates[0]->mysql_version ?? null; 64 70 65 $response = $api->ignoreStatus()->post('/settings-check', [ 66 'php_version' => phpversion(), 67 'plugins' => $this->getPluginsWithStatuses(), 68 'theme_name' => $theme ? $theme->name : null, 69 'theme_version' => $theme ? $theme->version : null, 70 'themes' => $this->getThemesListWithStatuses(), 71 'wordpress_version' => $wp_version, 72 'latest_wp_version' => $latestWPVersion, 73 'latest_wp_min_php_version' => $latestMinPhpVersion, 74 'latest_wp_min_mysql_version' => $latestMinMySqlVersion, 75 ]); 71 $api = new Logtivity_Api(); 76 72 77 if ($response) { 78 $api->updateSettings($response); 73 $response = $api 74 ->ignoreStatus() 75 ->waitForResponse() 76 ->makeRequest( 77 '/settings-check', 78 [ 79 'php_version' => phpversion(), 80 'plugins' => $this->getPluginsWithStatuses(), 81 'theme_name' => $theme ? $theme->name : null, 82 'theme_version' => $theme ? $theme->version : null, 83 'themes' => $this->getThemesListWithStatuses(), 84 'wordpress_version' => $wp_version, 85 'latest_wp_version' => $latestWPVersion, 86 'latest_wp_min_php_version' => $latestMinPhpVersion, 87 'latest_wp_min_mysql_version' => $latestMinMySqlVersion, 88 ]); 89 90 if ($settings = $response['body']['settings'] ?? null) { 91 $api->updateSettings($settings); 79 92 } 80 93 … … 82 95 // Ignore 83 96 } 84 }85 86 /**87 * @return array[]88 */89 private function getThemesListWithStatuses(): array90 {91 $themes = wp_get_themes();92 93 $themesDetails = [];94 95 foreach ($themes as $theme) {96 $themesDetails[] = [97 'name' => $theme->name,98 'version' => $theme->version,99 ];100 }101 102 return $themesDetails;103 97 } 104 98 … … 174 168 175 169 /** 176 * @return bool170 * @return array[] 177 171 */ 178 p ublic function shouldCheckInWithApi(): bool172 private function getThemesListWithStatuses(): array 179 173 { 180 return (new Logtivity_Options())->shouldCheckInWithApi(); 174 $themes = wp_get_themes(); 175 176 $themesDetails = []; 177 178 foreach ($themes as $theme) { 179 $themesDetails[] = [ 180 'name' => $theme->name, 181 'version' => $theme->version, 182 ]; 183 } 184 185 return $themesDetails; 181 186 } 182 187 } -
logtivity/tags/3.2.0/Services/Logtivity_Logger.php
r3290027 r3335490 225 225 * Send the logged data to Logtivity 226 226 * 227 * @return ?array228 */ 229 public function send(): ?array227 * @return void 228 */ 229 public function send(): void 230 230 { 231 231 $this->maybeAddProfileLink(); … … 234 234 235 235 if ($this->active) { 236 return $this->makeRequest('/logs/store', $this->getData()); 237 } 238 239 return null; 236 $this->makeRequest('/logs/store', $this->getData()); 237 } 240 238 } 241 239 -
logtivity/tags/3.2.0/assets/app.js
r3306623 r3335490 4 4 this.container = $('#logtivity-log-index'); 5 5 6 if (!this.container.length) { 7 return; 6 if (this.container.length) { 7 this.form = $('#logtivity-log-index-search-form'); 8 this.listenForPagination(); 9 this.listenForChange(); 10 this.filter(); 11 this.listenForViewLog() 12 this.listenForCloseModal(); 8 13 } 9 10 this.form = $('#logtivity-log-index-search-form');11 this.listenForPagination();12 this.listenForChange();13 this.filter();14 this.listenForViewLog()15 this.listenForCloseModal();16 14 }, 17 15 … … 19 17 let listenForCloseModal = this; 20 18 21 $( "body").on("click", ".js-logtivity-notice-dismiss", function(e) {19 $('body').on('click', '.js-logtivity-notice-dismiss', function(e) { 22 20 e.preventDefault(); 23 21 … … 26 24 27 25 $(document).on('keyup', function(e) { 28 if (e.key === "Escape") {26 if (e.key === 'Escape') { 29 27 listenForCloseModal.hideModal(); 30 28 } … … 49 47 let listenForViewLog = this; 50 48 51 $( "body").on("click", ".js-logtivity-view-log", function(e) {49 $('body').on('click', '.js-logtivity-view-log', function(e) { 52 50 e.preventDefault(); 53 51 … … 74 72 timeout = null; 75 73 76 $( "body").on("input", "#logtivity-log-index-search-form input", function(e) {74 $('body').on('input', '#logtivity-log-index-search-form input', function(e) { 77 75 e.preventDefault(); 78 76 … … 93 91 loading: function() { 94 92 this.container.html( 95 '<div style="text-align: center; padding-bottom: 20px"><div class="spinner is-active" style="float:none;width:auto;height:auto;padding:10px 0 10px 50px;background-position:20px 0;"></div></div>' 93 '<div style="text-align: center; padding-bottom: 20px">' 94 + '<div class="spinner is-active" style="float:none;width:auto;height:auto;padding:10px 0 10px 50px;background-position:20px 0;"></div>' 95 + '</div>' 96 96 ); 97 97 }, … … 100 100 let listenForPagination = this; 101 101 102 $( "body").on("click", ".js-logtivity-pagination", function(e) {102 $('body').on('click', '.js-logtivity-pagination', function(e) { 103 103 e.preventDefault(); 104 104 -
logtivity/tags/3.2.0/composer.json
r3290027 r3335490 25 25 }, 26 26 "require": { 27 "php" : ">=7.4",27 "php" : ">=7.4", 28 28 "ext-json": "*" 29 29 }, -
logtivity/tags/3.2.0/logtivity.php
r3306623 r3335490 6 6 * Description: Record activity logs and errors logs across all your WordPress sites. 7 7 * Author: Logtivity 8 * Version: 3. 1.128 * Version: 3.2.0 9 9 * Text Domain: logtivity 10 10 * Requires at least: 4.7 … … 45 45 * @var string 46 46 */ 47 protected string $version = '3. 1.12';47 protected string $version = '3.2.0'; 48 48 49 49 /** 50 50 * List all classes here with their file paths. Keep class names the same as filenames. 51 51 * Ordering of this list matters! 52 * @TODO: Implement ps t-0 autoloading52 * @TODO: Implement psr-0 autoloading 53 53 * 54 54 * @var string[] … … 71 71 'Services/Logtivity_Check_For_Disabled_Individual_Logs', 72 72 'Services/Logtivity_Check_For_New_Settings', 73 'Services/Logtivity_Rest_Endpoints', 73 74 /** 74 75 * Error logging … … 79 80 'Errors/Logtivity_Error_Log', 80 81 ]; 81 82 82 /** 83 83 * @var string[] … … 96 96 'Logs/Core/Logtivity_Meta', 97 97 ]; 98 99 98 /** 100 99 * List all integration dependencies … … 177 176 { 178 177 require_once plugin_dir_path(__FILE__) . $filePath . '.php'; 178 } 179 180 /** 181 * Review updates based on version 182 * 183 * @return void 184 */ 185 public function updateCheck(): void 186 { 187 $currentVersion = get_option('logtivity_version'); 188 189 if (version_compare($currentVersion, '3.1.6', '<=')) { 190 static::checkCapabilities(); 191 } 192 193 if ($currentVersion && version_compare($currentVersion, '3.1.7', '<=')) { 194 // Default for updating sites should be no behavior change 195 update_option('logtivity_app_verify_url', 0); 196 } 197 198 update_option('logtivity_version', $this->version); 199 } 200 201 /** 202 * Custom capabilities added prior to v3.1.7 203 * 204 * @return void 205 */ 206 public static function checkCapabilities(): void 207 { 208 $capabilities = array_filter( 209 array_keys(logtivity_get_capabilities()), 210 function (string $capability): bool { 211 return in_array($capability, [Logtivity::ACCESS_LOGS, Logtivity::ACCESS_SETTINGS]); 212 } 213 ); 214 215 if ($capabilities == false) { 216 // Make sure at least admins can access us 217 if ($role = get_role('administrator')) { 218 if ($role->has_cap(Logtivity::ACCESS_LOGS) == false) { 219 $role->add_cap(Logtivity::ACCESS_LOGS); 220 } 221 if ($role->has_cap(Logtivity::ACCESS_SETTINGS) == false) { 222 $role->add_cap(Logtivity::ACCESS_SETTINGS); 223 } 224 } 225 } 179 226 } 180 227 … … 270 317 if ($created) { 271 318 $createdTimestamp = strtotime($created); 272 $creationText = sprintf(319 $creationText = sprintf( 273 320 'It was created on %s at %s ', 274 321 wp_date(get_option('date_format'), $createdTimestamp), … … 290 337 } 291 338 292 return $response ?? null;339 return $response; 293 340 } 294 341 … … 313 360 { 314 361 return new Logtivity_Error_Logger($error); 315 }316 317 /**318 * Review updates based on version319 *320 * @return void321 */322 public function updateCheck(): void323 {324 $currentVersion = get_option('logtivity_version');325 326 if (version_compare($currentVersion, '3.1.6', '<=')) {327 static::checkCapabilities();328 }329 330 if ($currentVersion && version_compare($currentVersion, '3.1.7', '<=')) {331 // Default for updating sites should be no behavior change332 update_option('logtivity_app_verify_url', 0);333 }334 335 update_option('logtivity_version', $this->version);336 362 } 337 363 … … 423 449 424 450 /** 425 * Custom capabilities added prior to v3.1.7426 *427 * @return void428 */429 public static function checkCapabilities(): void430 {431 $capabilities = array_filter(432 array_keys(logtivity_get_capabilities()),433 function (string $capability): bool {434 return in_array($capability, [Logtivity::ACCESS_LOGS, Logtivity::ACCESS_SETTINGS]);435 }436 );437 438 if ($capabilities == false) {439 // Make sure at least admins can access us440 if ($role = get_role('administrator')) {441 if ($role->has_cap(Logtivity::ACCESS_LOGS) == false) {442 $role->add_cap(Logtivity::ACCESS_LOGS);443 }444 if ($role->has_cap(Logtivity::ACCESS_SETTINGS) == false) {445 $role->add_cap(Logtivity::ACCESS_SETTINGS);446 }447 }448 }449 }450 451 /**452 451 * @return void 453 452 */ … … 469 468 current_user_can(static::ACCESS_SETTINGS) 470 469 && logtivity_has_site_url_changed() 470 && (new Logtivity_Options())->isWhiteLabelMode() == false 471 471 && !get_transient('dismissed-logtivity-site-url-has-changed-notice') 472 472 ) { -
logtivity/tags/3.2.0/readme.txt
r3306623 r3335490 5 5 Requires at least: 6.6 6 6 Tested up to: 6.8 7 Stable tag: 3. 1.127 Stable tag: 3.2.0 8 8 Requires PHP: 7.4 9 9 License: GPLv2 or later … … 262 262 263 263 == Changelog == 264 265 = 3.2.0 = 266 267 * Add JSON Web Token halper class 268 * Add REST api listener 269 * Retrieve more detailed error information on connection fails 270 * Normalize response data 271 * Fix automatic settings checkin 272 * Prevent disconnect on timeout errors 273 274 _Release Date - Monday, July 28, 2025_ 264 275 265 276 = 3.1.12 = -
logtivity/tags/3.2.0/views/_logs-loop.php
r3272661 r3335490 24 24 25 25 /** 26 * @var string $fileName 27 * @var ?string $message 26 28 * @var object[] $logs 27 * @var ?string $hasNextPage 29 * @var object $meta 30 * @var string $hasNextPage 28 31 */ 29 32 -
logtivity/trunk/Admin/Logtivity_Log_Index_Controller.php
r3294349 r3335490 41 41 { 42 42 if (current_user_can(Logtivity::ACCESS_LOGS)) { 43 $response = (new Logtivity_Api()) 44 ->get( 45 '/logs', 46 [ 47 'page' => $this->getInput('page'), 48 'action' => $this->getInput('search_action'), 49 'context' => $this->getInput('search_context'), 50 'action_user' => $this->getInput('action_user'), 51 ] 52 ); 43 $api = Logtivity::log(); 53 44 54 if ($response) { 55 $this->successResponse(json_decode(json_encode($response))); 45 if ($api->getOption()->getApiKey()) { 46 $response = $api 47 ->get( 48 '/logs', 49 [ 50 'page' => $this->getInput('page'), 51 'action' => $this->getInput('search_action'), 52 'context' => $this->getInput('search_context'), 53 'action_user' => $this->getInput('action_user'), 54 ] 55 ); 56 56 57 } elseif ((new Logtivity_Options())->getApiKey() == false) { 58 $this->welcomeResponse(); 57 if ($response) { 58 $response = json_decode(json_encode($response)); 59 60 $this->renderView([ 61 'message' => $response->error, 62 'logs' => $response->body->data ?? [], 63 'meta' => $response->body->meta ?? null, 64 'hasNextPage' => $response->body->links->next ?? null, 65 ]); 66 } else { 67 $this->renderView($api->getConnectionMessage()); 68 } 59 69 60 70 } else { 61 $this-> errorResponse((new Logtivity_Api())->getConnectionMessage());71 $this->welcomeResponse(); 62 72 } 63 73 } else { 64 $this-> errorResponse(__('You do not have sufficient permissions to access this page.'));74 $this->renderView(__('You do not have sufficient permissions to access this page.')); 65 75 } 66 76 } 67 77 68 78 /** 69 * @param object $response 79 * @param string $field 80 * 81 * @return ?string 82 */ 83 protected function getInput(string $field): ?string 84 { 85 return sanitize_text_field($_GET[$field] ?? null); 86 } 87 88 /** 89 * @param string|array $response 70 90 * 71 91 * @return void 72 92 */ 73 pr ivate function successResponse(object $response): void93 protected function renderView($viewData): void 74 94 { 95 if (is_string($viewData)) { 96 $viewData = ['message' => $viewData]; 97 } 98 99 $viewData = array_merge( 100 [ 101 'message' => null, 102 'logs' => [], 103 'meta' => null, 104 'hasNextPage' => null, 105 ], 106 $viewData 107 ); 108 75 109 wp_send_json([ 76 'view' => logtivity_view('_logs-loop', [ 77 'logs' => $response->data, 78 'meta' => $response->meta, 79 'hasNextPage' => $response->links->next, 80 ]), 81 ]); 82 } 83 84 /** 85 * @param string $message 86 * 87 * @return void 88 */ 89 private function errorResponse(string $message): void 90 { 91 wp_send_json([ 92 'view' => logtivity_view('_logs-loop', [ 93 'message' => $message, 94 'logs' => [], 95 ]), 110 'view' => logtivity_view('_logs-loop', $viewData), 96 111 ]); 97 112 } … … 100 115 * @return void 101 116 */ 102 pr ivatefunction welcomeResponse()117 protected function welcomeResponse() 103 118 { 104 119 wp_send_json([ … … 109 124 ]); 110 125 } 111 112 /**113 * @param string $field114 *115 * @return ?string116 */117 private function getInput(string $field): ?string118 {119 return sanitize_text_field($_GET[$field] ?? null);120 }121 126 } 122 127 -
logtivity/trunk/Admin/Logtivity_Options.php
r3306623 r3335490 28 28 class Logtivity_Options 29 29 { 30 /** 31 * Checkin for settings updates in designated minutes 32 * 33 * @var int 34 */ 35 protected int $checkinDelay = 10; 36 30 37 /** 31 38 * The option keys that we can save to the options table … … 175 182 176 183 if ($lastCheckin) { 177 return time() - strtotime($lastCheckin) > 10 * MINUTE_IN_SECONDS;184 return time() - strtotime($lastCheckin) > ($this->checkinDelay * MINUTE_IN_SECONDS); 178 185 } 179 186 } … … 232 239 public function update(array $data = [], bool $checkApiKey = true): void 233 240 { 234 if (count($data)) { 235 foreach ($this->settings as $setting => $default) { 236 if (array_key_exists($setting, $data) && $this->validateSetting($setting, $data[$setting])) { 237 update_option($setting, $data[$setting]); 238 } 239 } 240 } else { 241 foreach ($this->settings as $setting => $default) { 242 if (array_key_exists($setting, $_POST) && $this->validateSetting($setting, $_POST[$setting])) { 243 update_option($setting, $_POST[$setting]); 244 } 241 $settings = array_intersect_key($data ?: $_POST, $this->settings); 242 foreach ($settings as $key => $value) { 243 if ($this->validateSetting($key, $value)) { 244 update_option($key, $value); 245 245 } 246 246 } … … 249 249 $this->checkApiKey($data['logtivity_site_api_key'] ?? $_POST['logtivity_site_api_key'] ?? null); 250 250 } 251 } 252 253 /** 254 * Validate that the passed parameters are in the correct format 255 * 256 * @param string $key 257 * @param mixed $value 258 * 259 * @return bool 260 */ 261 protected function validateSetting(string $key, $value): bool 262 { 263 $setting = $this->settings[$key] ?? null; 264 265 if ($setting) { 266 $method = $setting['rule'] ?? null; 267 268 if ($method == 'is_bool') { 269 return $method((bool)$value); 270 } 271 272 return $method($value); 273 } 274 275 return true; 251 276 } 252 277 … … 262 287 ->setAction('Settings Updated') 263 288 ->setContext('Logtivity') 264 ->ignoreStatus()265 289 ->waitForResponse() 266 290 ->send(); 267 291 } 268 292 } 269 270 /**271 * Validate that the passed parameters are in the correct format272 *273 * @param string $key274 * @param mixed $value275 *276 * @return bool277 */278 protected function validateSetting(string $key, $value): bool279 {280 $setting = $this->settings[$key] ?? null;281 282 if ($setting) {283 $method = $setting['rule'] ?? null;284 285 if ($method == 'is_bool') {286 return $method((bool)$value);287 }288 289 return $method($value);290 }291 292 return true;293 }294 293 } -
logtivity/trunk/Errors/Logtivity_Error_Logger.php
r3272661 r3335490 70 70 * @return ?array 71 71 */ 72 public function send(): ?array72 public function send(): void 73 73 { 74 74 $message = $this->error['message'] ?? ''; … … 79 79 80 80 if ($this->active) { 81 $ response = $this->makeRequest('/errors/store', $this->getData());81 $this->makeRequest('/errors/store', $this->getData()); 82 82 } 83 83 } 84 85 return $response ?? null;86 84 } 87 85 -
logtivity/trunk/Helpers/Helpers.php
r3272661 r3335490 51 51 { 52 52 extract($vars); 53 unset($vars); 53 54 54 55 ob_start(); -
logtivity/trunk/Helpers/Logtivity_Log_Global_Function.php
r3290027 r3335490 33 33 * @deprecated v3.1.8 - use Logtivity::log() instead 34 34 */ 35 function logtivity_log(?string $action = null, ?string $meta = null, ?string $user_id = null) 35 function logtivity_log(?string $action = null, ?string $meta = null, ?string $user_id = null): void 36 36 { 37 returnLogtivity::log($action, $meta, $user_id)->send();37 Logtivity::log($action, $meta, $user_id)->send(); 38 38 } -
logtivity/trunk/Logs/Core/Logtivity_Core.php
r3290027 r3335490 197 197 ->setAction('Settings Updated') 198 198 ->setContext('Core:' . $optionPage) 199 ->ignoreStatus()200 199 ->send(); 201 200 } -
logtivity/trunk/Logs/Core/Logtivity_User.php
r3272661 r3335490 25 25 class Logtivity_User extends Logtivity_Abstract_Logger 26 26 { 27 protected static $loggedUserlogin = false;27 protected static bool $loggedUserlogin = false; 28 28 29 29 /** 30 * @inheritDoc 30 * @param string $username 31 * @param WP_User $user 32 * 33 * @return void 31 34 */ 32 p rotected function registerHooks(): void35 public function userLoggedIn(string $username, WP_User $user) 33 36 { 34 add_action('wp_login', [$this, 'wpLogin'], 10, 2); 35 add_action('wp_logout', [$this, 'userLoggedOut'], 10, 1); 36 add_action('user_register', [$this, 'userCreated'], 10, 1); 37 add_action('delete_user', [$this, 'userDeleted']); 38 add_action('profile_update', [$this, 'profileUpdated'], 10, 2); 37 if (static::$loggedUserlogin == false) { 38 static::$loggedUserlogin = true; 39 40 $logger = Logtivity::log()->setUser($user->ID); 41 42 $logger->setAction('User Logged In') 43 ->setContext($logger->user->getRole()) 44 ->send(); 45 } 39 46 } 40 47 41 public function wpLogin($user_login, $user) 48 /** 49 * @param int $userId 50 * 51 * @return void 52 */ 53 public function userLoggedOut(int $userId): void 42 54 { 43 if (self::$loggedUserlogin) { 44 return; 55 if ($userId) { 56 $logger = Logtivity::log()->setUser($userId); 57 58 $logger 59 ->setAction('User Logged Out') 60 ->setContext($logger->user->getRole()) 61 ->send(); 45 62 } 46 47 return $this->userLoggedIn($user->ID);48 63 } 49 64 50 public function userLoggedIn($user_id) 51 { 52 self::$loggedUserlogin = true; 53 54 $logtivityUser = new Logtivity_WP_User($user_id); 55 56 return (new Logtivity_Logger($user_id)) 57 ->setAction('User Logged In') 58 ->setContext($logtivityUser->getRole()) 59 ->send(); 60 } 61 62 public function userLoggedOut($user_id) 63 { 64 if ($user_id == 0) { 65 return; 66 } 67 68 $user = new Logtivity_WP_User($user_id); 69 70 return (new Logtivity_Logger($user_id)) 71 ->setAction('User Logged Out') 72 ->setContext($user->getRole()) 73 ->send(); 74 } 75 76 public function userCreated($user_id) 65 /** 66 * @param int $userId 67 * 68 * @return void 69 */ 70 public function userCreated(int $userId): void 77 71 { 78 72 $log = Logtivity::log(); 79 73 80 if (!is_user_logged_in()) { 81 $log->setUser($user_id); 74 if (is_user_logged_in() == false) { 75 $log->setUser($userId); 76 $user = $log->user; 77 } else { 78 $user = new Logtivity_WP_User($userId); 82 79 } 83 84 $user = new Logtivity_WP_User($user_id);85 80 86 81 $log->setAction('User Created') … … 90 85 } 91 86 92 public function userDeleted($user_id) 87 /** 88 * @param int $userId 89 * 90 * @return void 91 */ 92 public function userDeleted(int $userId): void 93 93 { 94 $user = new Logtivity_WP_User($user _id);94 $user = new Logtivity_WP_User($userId); 95 95 96 96 Logtivity::log() … … 101 101 } 102 102 103 public function profileUpdated($user _id, $old_user_data)103 public function profileUpdated($userId) 104 104 { 105 $user = new Logtivity_WP_User($user _id);105 $user = new Logtivity_WP_User($userId); 106 106 107 107 Logtivity::log() … … 111 111 ->send(); 112 112 } 113 114 /** 115 * @inheritDoc 116 */ 117 protected function registerHooks(): void 118 { 119 add_action('wp_login', [$this, 'userLoggedIn'], 10, 2); 120 add_action('wp_logout', [$this, 'userLoggedOut'], 10, 1); 121 add_action('user_register', [$this, 'userCreated'], 10, 1); 122 add_action('delete_user', [$this, 'userDeleted']); 123 add_action('profile_update', [$this, 'profileUpdated'], 10, 1); 124 } 113 125 } 114 126 -
logtivity/trunk/Logs/Memberpress/Logtivity_Memberpress.php
r3272661 r3335490 25 25 class Logtivity_Memberpress extends Logtivity_Abstract_Logger 26 26 { 27 /** 28 * @inheritDoc 29 */ 30 protected function registerHooks(): void 31 { 32 add_action('mepr-event-member-signup-completed', [$this, 'freeSubscriptionCreated']); 33 add_action('mepr-event-subscription-created', [$this, 'subscriptionCreated']); 34 add_action('mepr-event-subscription-paused', [$this, 'subscriptionPaused']); 35 add_action('mepr-event-subscription-resumed', [$this, 'subscriptionResumed']); 36 add_action('mepr-event-subscription-stopped', [$this, 'subscriptionStopped']); 37 add_action('init', [$this, 'profileUpdated']); 38 add_filter('mepr_create_transaction', [$this, 'transactionCreated'], 10, 3); 39 add_filter('mepr_update_transaction', [$this, 'transactionUpdated'], 10, 3); 40 add_action('mepr_email_sent', [$this, 'emailSent'], 10, 3); 41 add_action('mepr-process-options', [$this, 'settingsUpdated'], 10, 1); 42 } 43 44 public function freeSubscriptionCreated($event) 27 public function freeSubscriptionCreated($event): void 45 28 { 46 29 $user = $event->get_data(); 47 30 $subscription = $this->getSubscription($user); 48 31 49 if (!$subscription) { 50 return; 32 if ($subscription && $subscription->gateway == 'free') { 33 $product = $subscription->product(); 34 35 Logtivity::log( 36 'Free Subscription Created', 37 [ 38 'Subscription ID' => $subscription->id, 39 ] 40 ) 41 ->setContext($product->post_title) 42 ->send(); 51 43 } 52 53 if ($subscription->gateway != 'free') {54 return;55 }56 57 $product = $subscription->product();58 59 return (new Logtivity_Logger($user->ID))60 ->setAction('Free Subscription Created')61 ->setContext($product->post_title)62 ->addMeta('Subscription ID', $subscription->id)63 ->send();64 44 } 65 45 … … 73 53 } 74 54 75 public function subscriptionCreated($event) 55 /** 56 * @param $event 57 * 58 * @return void 59 */ 60 public function subscriptionCreated($event): void 76 61 { 77 62 $subscription = $event->get_data(); … … 80 65 $paymentMethod = $subscription->payment_method(); 81 66 82 return (new Logtivity_Logger($user->ID)) 83 ->setAction('Subscription Created') 67 Logtivity::log( 68 'Subscription Created', 69 [ 70 'Transaction Total' => $subscription->total, 71 'Payment Method' => $paymentMethod->name, 72 'Subscription ID' => $subscription->id, 73 ], 74 $user->ID 75 ) 84 76 ->setContext($product->post_title) 85 ->addMeta('Transaction Total', $subscription->total)86 ->addMeta('Payment Method', $paymentMethod->name)87 ->addMeta('Subscription ID', $subscription->id)88 77 ->send(); 89 78 } … … 188 177 ->send(); 189 178 } 179 180 /** 181 * @inheritDoc 182 */ 183 protected function registerHooks(): void 184 { 185 add_action('mepr-event-member-signup-completed', [$this, 'freeSubscriptionCreated']); 186 add_action('mepr-event-subscription-created', [$this, 'subscriptionCreated']); 187 add_action('mepr-event-subscription-paused', [$this, 'subscriptionPaused']); 188 add_action('mepr-event-subscription-resumed', [$this, 'subscriptionResumed']); 189 add_action('mepr-event-subscription-stopped', [$this, 'subscriptionStopped']); 190 add_action('init', [$this, 'profileUpdated']); 191 add_filter('mepr_create_transaction', [$this, 'transactionCreated'], 10, 3); 192 add_filter('mepr_update_transaction', [$this, 'transactionUpdated'], 10, 3); 193 add_action('mepr_email_sent', [$this, 'emailSent'], 10, 3); 194 add_action('mepr-process-options', [$this, 'settingsUpdated'], 10, 1); 195 } 190 196 } 191 197 -
logtivity/trunk/Services/Logtivity_Api.php
r3306623 r3335490 25 25 class Logtivity_Api 26 26 { 27 public const CURL_TIMEOUT = 28; 28 29 /** 30 * @var array 31 */ 32 protected static $responseData = [ 33 'code' => null, 34 'message' => null, 35 'error' => null, 36 'body' => null, 37 ]; 38 27 39 /** 28 40 * Option class to access the plugin settings … … 62 74 * @return $this 63 75 */ 64 public function waitForResponse(): self65 { 66 $this-> waitForResponse= true;76 public function ignoreStatus(): self 77 { 78 $this->ignoreStatus = true; 67 79 68 80 return $this; 69 }70 71 /**72 * @return $this73 */74 public function ignoreStatus(): self75 {76 $this->ignoreStatus = true;77 78 return $this;79 }80 81 /**82 * @param string $endpoint83 *84 * @return string85 */86 public function getEndpoint(string $endpoint): string87 {88 return logtivity_get_api_url() . $endpoint;89 81 } 90 82 … … 98 90 { 99 91 return $this->makeRequest($url, $body); 100 }101 102 /**103 * @param string $url104 * @param ?array $body105 *106 * @return ?array107 */108 public function get(string $url, ?array $body = null): ?array109 {110 return $this->waitForResponse()->makeRequest($url, $body, 'GET');111 }112 113 /**114 * @return ?string115 */116 public function getApiKey(): ?string117 {118 if ($this->api_key == false) {119 $this->api_key = $this->options->getApiKey();120 }121 122 return $this->api_key;123 }124 125 /**126 * @param string $apikey127 *128 * @return $this129 */130 public function setApiKey(string $apikey): self131 {132 $this->api_key = $apikey;133 134 return $this;135 92 } 136 93 … … 151 108 152 109 if ($this->ready()) { 153 if ($this-> options->getOption('logtivity_app_verify_url')) {110 if ($this->getOption('logtivity_app_verify_url')) { 154 111 $body = array_merge( 155 112 $body ?: [], … … 177 134 // @TODO: Switch to Logtivity_Response class to get standardized responses 178 135 $response = wp_remote_request($this->getEndpoint($url), $request); 179 if ($ this->notUpdatingWidgetInCustomizer()) {136 if ($waitForResponse && $this->notUpdatingWidgetInCustomizer()) { 180 137 // We waited and received a response 181 138 if ($response instanceof WP_Error) { 182 $responseData = [139 $responseData = array_merge(static::$responseData, [ 183 140 'code' => 500, 184 141 'message' => $response->get_error_code(), 185 142 'error' => $response->get_error_message() ?: $response->get_error_code(), 186 143 'body' => get_object_vars($response), 187 ] ;144 ]); 188 145 189 146 } else { … … 197 154 $responseError = $responseMessage; 198 155 $responseMessage = (($responseBody['message'] ?? $responseMessage) ?: 'Unknown error'); 199 200 156 } 201 157 $responseData = [ … … 207 163 } 208 164 165 $newStatus = 'success'; 209 166 if ($responseData['code']) { 210 167 if ($responseData['code'] < 400) { 211 168 // Successful request, check if api is telling us to pause 212 $newStatus = $responseData['error'] ? 'paused' : 'success'; 213 $this->updateSettings($response['body']); 169 if ($responseData['error']) { 170 $newStatus = 'paused'; 171 } 172 173 $body = json_decode($response['body'] ?? 'null', true); 174 $this->updateSettings($body['settings'] ?? []); 214 175 215 176 } else { 216 // Something went wrong submitting the api request 217 $newStatus = 'fail'; 218 update_option('logtivity_last_settings_check_in_at', ['date' => date('Y-m-d H:i:s')]); 177 if ($this->getCurlError($responseData['error']) != static::CURL_TIMEOUT) { 178 // Something other than a timeout went wrong with the request 179 $newStatus = 'fail'; 180 } 181 182 $this->updateLastCheckin(); 219 183 } 220 184 … … 229 193 ); 230 194 231 return $responseData ['body'];195 return $responseData; 232 196 } 233 197 } … … 238 202 239 203 /** 204 * @return bool 205 */ 206 protected function ready(): bool 207 { 208 return ($this->getApiKey()) 209 && logtivity_has_site_url_changed() == false 210 && ( 211 $this->ignoreStatus 212 || $this->getOption('logtivity_api_key_check') == 'success' 213 || $this->options->shouldCheckInWithApi() 214 ); 215 } 216 217 /** 218 * @return ?string 219 */ 220 public function getApiKey(): ?string 221 { 222 if ($this->api_key == false) { 223 $this->api_key = $this->options->getApiKey(); 224 } 225 226 return $this->api_key; 227 } 228 229 /** 230 * @param string $apikey 231 * 232 * @return $this 233 */ 234 public function setApiKey(string $apikey): self 235 { 236 $this->api_key = $apikey; 237 238 return $this; 239 } 240 241 /** 242 * @param ?string $key 243 * 244 * @return Logtivity_Options|mixed 245 */ 246 public function getOption(?string $key = null) 247 { 248 if ($key) { 249 return $this->options->getOption($key); 250 } 251 252 return $this->options; 253 } 254 255 /** 256 * @param string $endpoint 257 * 258 * @return string 259 */ 260 public function getEndpoint(string $endpoint): string 261 { 262 return logtivity_get_api_url() . $endpoint; 263 } 264 265 /** 266 * You cannot call an extra update_option during a widget update so we make 267 * sure not to log the most recent log response in this case. 268 * 269 * @return bool 270 */ 271 protected function notUpdatingWidgetInCustomizer(): bool 272 { 273 $customize = sanitize_text_field($_POST['wp_customize'] ?? null); 274 $action = sanitize_text_field($_POST['action'] ?? null); 275 276 return ($action == 'update-widget' && $customize == 'on') == false; 277 } 278 279 /** 240 280 * @param array|object $body 241 281 * 242 282 * @return void 243 283 */ 244 public function updateSettings($body): void 245 { 246 $settings = (object)($body->settings ?? $body['settings'] ?? null); 247 284 public function updateSettings(array $settings): void 285 { 248 286 if ($settings) { 249 $this->options->update( 250 [ 251 'logtivity_global_disabled_logs' => $settings->disabled_logs ?? null, 252 'logtivity_enable_white_label_mode' => $settings->enable_white_label_mode ?? null, 253 'logtivity_disabled_error_levels' => $settings->disabled_error_levels ?? null, 254 'logtivity_disable_error_logging' => $settings->disable_error_logging ?? null, 255 'logtivity_hide_plugin_from_ui' => $settings->hide_plugin_from_ui ?? null, 256 'logtivity_disable_default_logging' => $settings->disable_default_logging ?? null, 257 'logtivity_enable_options_table_logging' => $settings->enable_options_table_logging ?? null, 258 'logtivity_enable_post_meta_logging' => $settings->enable_post_meta_logging ?? null, 259 'logtivity_custom_plugin_name' => $settings->custom_plugin_name ?? null, 260 ], 261 false 262 ); 263 264 update_option('logtivity_last_settings_check_in_at', ['date' => date('Y-m-d H:i:s')]); 265 } 287 $verifiedSettings = []; 288 foreach ($settings as $key => $value) { 289 if ($key == 'disabled_logs') { 290 $key = 'global_' . $key; 291 } 292 $verifiedSettings['logtivity_' . $key] = is_null($value) ? '' : $value; 293 } 294 295 $this->options->update($verifiedSettings, false); 296 } 297 298 $this->updateLastCheckin(); 299 } 300 301 /** 302 * @return void 303 */ 304 protected function updateLastCheckin(): void 305 { 306 update_option('logtivity_last_settings_check_in_at', ['date' => date('Y-m-d H:i:s')]); 307 } 308 309 /** 310 * @param ?string $message 311 * 312 * @return int 313 */ 314 protected function getCurlError(?string $message): ?int 315 { 316 preg_match('/curl\s+error\s+(\d+)/i', $message, $matches); 317 318 return $matches[1] ?? null; 266 319 } 267 320 … … 271 324 public function getLatestResponse(): ?array 272 325 { 273 $response = $this-> options->getOption('logtivity_latest_response');326 $response = $this->getOption('logtivity_latest_response'); 274 327 275 328 return $response ?: null; … … 277 330 278 331 /** 279 * @return ?string 280 */ 281 public function getConnectionStatus(): ?string 282 { 283 $status = null; 284 $apiKey = $this->getApiKey(); 285 286 if ($apiKey) { 287 $status = $this->options->getOption('logtivity_api_key_check'); 288 } 289 290 return $status; 332 * @param string $url 333 * @param ?array $body 334 * 335 * @return ?array 336 */ 337 public function get(string $url, ?array $body = null): ?array 338 { 339 return $this->waitForResponse()->makeRequest($url, $body, 'GET'); 340 } 341 342 /** 343 * @return $this 344 */ 345 public function waitForResponse(): self 346 { 347 $this->waitForResponse = true; 348 349 return $this; 291 350 } 292 351 … … 310 369 $error = $this->getLatestResponse(); 311 370 $code = $error['code'] ?? null; 312 $message = $error[' message'] ?? null;371 $message = $error['error'] ?? $error['message'] ?? null; 313 372 314 373 if ($code && $message) { … … 329 388 330 389 /** 331 * You cannot call an extra update_option during a widget update so we make 332 * sure not to log the most recent log response in this case. 333 * 334 * @return bool 335 */ 336 private function notUpdatingWidgetInCustomizer(): bool 337 { 338 $customize = sanitize_text_field($_POST['wp_customize'] ?? null); 339 $action = sanitize_text_field($_POST['action'] ?? null); 340 341 return ($action == 'update-widget' && $customize == 'on') == false; 342 } 343 344 /** 345 * @return bool 346 */ 347 private function ready(): bool 348 { 349 //var_dump($this->ignoreStatus); 350 return ($this->getApiKey()) 351 && logtivity_has_site_url_changed() == false 352 && ( 353 $this->ignoreStatus 354 || $this->options->getOption('logtivity_api_key_check') == 'success' 355 || $this->options->shouldCheckInWithApi() 356 ); 390 * @return ?string 391 */ 392 public function getConnectionStatus(): ?string 393 { 394 $status = null; 395 $apiKey = $this->getApiKey(); 396 397 if ($apiKey) { 398 $status = $this->getOption('logtivity_api_key_check'); 399 } 400 401 return $status; 357 402 } 358 403 } -
logtivity/trunk/Services/Logtivity_Check_For_Disabled_Individual_Logs.php
r3246625 r3335490 25 25 class Logtivity_Check_For_Disabled_Individual_Logs 26 26 { 27 public function __construct() 28 { 29 add_action('wp_logtivity_instance', [$this, 'handle'], 10, 999); 30 } 27 /** 28 * @var Logtivity_Options 29 */ 30 protected Logtivity_Options $options; 31 31 32 public function handle($Logtivity_Logger) 33 { 34 foreach ($this->getLogsToExclude() as $log) { 35 if ($this->check($Logtivity_Logger, $log)) { 36 $Logtivity_Logger->stop(); 37 } 38 } 32 public function __construct() 33 { 34 add_action('wp_logtivity_instance', [$this, 'handle'], 10, 2); 35 } 39 36 40 foreach ($this->globalLogsToExclude() as $log) { 41 if ($this->check($Logtivity_Logger, $log)) { 42 $Logtivity_Logger->stop(); 43 } 44 } 45 } 37 /** 38 * @param Logtivity_Logger $logger 39 * 40 * @return void 41 */ 42 public function handle(Logtivity_Logger $logger): void 43 { 44 // Refresh options whenever invoked 45 $this->options = new Logtivity_Options(); 46 46 47 public function check($Logtivity_Logger, $log) 48 { 49 $array = explode('&&', $log); 47 $exclusions = array_unique( 48 array_merge( 49 $this->parseExcludeEntries('logtivity_disable_individual_logs'), 50 $this->parseExcludeEntries('logtivity_global_disabled_logs') 51 ) 52 ); 50 53 51 if (isset($array[0]) && isset($array[1])) { 52 if (trim($array[0]) === '*' && trim($array[1]) === '*') { 53 return; 54 } 55 if ($this->matches($Logtivity_Logger->action, $array[0]) && $this->matches($Logtivity_Logger->context, $array[1])) { 56 return true; 57 } 58 } elseif(isset($array[0])) { 59 if (trim($array[0]) === '*') { 60 return; 61 } 62 if ($this->matches($Logtivity_Logger->action, $array[0])) { 63 return true; 64 } 65 } 66 return false; 67 } 54 foreach ($exclusions as $exclusion) { 55 if ($this->isDisabled($logger, $exclusion)) { 56 $logger->stop(); 68 57 69 private function matches($keyword, $disabledKeyword) 70 { 71 // @TODO: this may not be the best way to check the arguments 72 if (is_string($keyword) && is_string($disabledKeyword)) { 73 $keyword = trim(strtolower($keyword)); 74 $disabledKeyword = trim(strtolower($disabledKeyword)); 58 return; 59 } 60 } 61 } 75 62 76 if ($disabledKeyword === '*') { 77 return true; 78 } 63 /** 64 * @param string $option 65 * 66 * @return array 67 */ 68 protected function parseExcludeEntries(string $option): array 69 { 70 $value = (string)$this->options->getOption($option); 79 71 80 if (strpos($disabledKeyword, '*') !== false) { 81 return strpos($keyword, str_replace('*', '', $disabledKeyword)) !== false; 82 } 72 $entries = preg_split("/\\r\\n|\\r|\\n/", $value); 83 73 84 return $keyword == $disabledKeyword;85 }74 return array_unique(array_filter($entries)); 75 } 86 76 87 return false; 88 } 77 /** 78 * @param Logtivity_Logger $logger 79 * @param string $exclusion 80 * 81 * @return bool 82 */ 83 protected function isDisabled(Logtivity_Logger $logger, string $exclusion): bool 84 { 85 $array = explode('&&', $exclusion); 86 $action = strtolower(trim((string)array_shift($array))); 87 $context = strtolower(trim((string)array_shift($array))); 89 88 90 private function getLogsToExclude() 91 { 92 $value = (new Logtivity_Options)->getOption('logtivity_disable_individual_logs'); 89 if ($action == '*' && $context == '*') { 90 return false; 91 } elseif ($this->matches($logger->action, $action) && $this->matches($logger->context, $context)) { 92 return true; 93 } elseif ($action == '*') { 94 return false; 95 } elseif ($this->matches($logger->action, $action)) { 96 return true; 97 } 93 98 94 if ($value == '') { 95 return []; 96 } 99 return false; 100 } 97 101 98 return preg_split("/\\r\\n|\\r|\\n/", $value); 99 } 102 /** 103 * @param ?string $keywordTarget 104 * @param ?string $keywordCheck 105 * 106 * @return bool 107 */ 108 protected function matches(?string $keywordTarget, ?string $keywordCheck): bool 109 { 110 $keywordTarget = strtolower(trim((string)$keywordTarget)); 111 $keywordCheck = strtolower(trim((string)$keywordCheck)); 100 112 101 public function globalLogsToExclude() 102 { 103 $value = (new Logtivity_Options)->getOption('logtivity_global_disabled_logs'); 113 if ($keywordTarget && $keywordCheck) { 114 if ($keywordCheck == '*') { 115 return true; 116 } 104 117 105 if ($value == '') { 106 return []; 107 } 118 if (strpos($keywordCheck, '*') !== false) { 119 $regex = str_replace(['*', '/'], ['.*?', '\/'], $keywordCheck); 120 return preg_match('/' . $regex . '/', $keywordTarget); 121 } 108 122 109 return preg_split("/\\r\\n|\\r|\\n/", $value); 110 } 123 return $keywordCheck == $keywordTarget; 124 } 125 126 return false; 127 } 111 128 } 112 129 113 $CheckForDisabledIndividualLogs = new Logtivity_Check_For_Disabled_Individual_Logs;130 new Logtivity_Check_For_Disabled_Individual_Logs(); -
logtivity/trunk/Services/Logtivity_Check_For_New_Settings.php
r3290027 r3335490 41 41 42 42 /** 43 * @return bool 44 */ 45 public function shouldCheckInWithApi(): bool 46 { 47 return (new Logtivity_Options())->shouldCheckInWithApi(); 48 } 49 50 /** 43 51 * @return void 44 52 */ … … 53 61 54 62 try { 55 $api = new Logtivity_Api();56 57 63 $theme = wp_get_theme(); 58 64 … … 63 69 $latestMinMySqlVersion = $coreUpdates[0]->mysql_version ?? null; 64 70 65 $response = $api->ignoreStatus()->post('/settings-check', [ 66 'php_version' => phpversion(), 67 'plugins' => $this->getPluginsWithStatuses(), 68 'theme_name' => $theme ? $theme->name : null, 69 'theme_version' => $theme ? $theme->version : null, 70 'themes' => $this->getThemesListWithStatuses(), 71 'wordpress_version' => $wp_version, 72 'latest_wp_version' => $latestWPVersion, 73 'latest_wp_min_php_version' => $latestMinPhpVersion, 74 'latest_wp_min_mysql_version' => $latestMinMySqlVersion, 75 ]); 71 $api = new Logtivity_Api(); 76 72 77 if ($response) { 78 $api->updateSettings($response); 73 $response = $api 74 ->ignoreStatus() 75 ->waitForResponse() 76 ->makeRequest( 77 '/settings-check', 78 [ 79 'php_version' => phpversion(), 80 'plugins' => $this->getPluginsWithStatuses(), 81 'theme_name' => $theme ? $theme->name : null, 82 'theme_version' => $theme ? $theme->version : null, 83 'themes' => $this->getThemesListWithStatuses(), 84 'wordpress_version' => $wp_version, 85 'latest_wp_version' => $latestWPVersion, 86 'latest_wp_min_php_version' => $latestMinPhpVersion, 87 'latest_wp_min_mysql_version' => $latestMinMySqlVersion, 88 ]); 89 90 if ($settings = $response['body']['settings'] ?? null) { 91 $api->updateSettings($settings); 79 92 } 80 93 … … 82 95 // Ignore 83 96 } 84 }85 86 /**87 * @return array[]88 */89 private function getThemesListWithStatuses(): array90 {91 $themes = wp_get_themes();92 93 $themesDetails = [];94 95 foreach ($themes as $theme) {96 $themesDetails[] = [97 'name' => $theme->name,98 'version' => $theme->version,99 ];100 }101 102 return $themesDetails;103 97 } 104 98 … … 174 168 175 169 /** 176 * @return bool170 * @return array[] 177 171 */ 178 p ublic function shouldCheckInWithApi(): bool172 private function getThemesListWithStatuses(): array 179 173 { 180 return (new Logtivity_Options())->shouldCheckInWithApi(); 174 $themes = wp_get_themes(); 175 176 $themesDetails = []; 177 178 foreach ($themes as $theme) { 179 $themesDetails[] = [ 180 'name' => $theme->name, 181 'version' => $theme->version, 182 ]; 183 } 184 185 return $themesDetails; 181 186 } 182 187 } -
logtivity/trunk/Services/Logtivity_Logger.php
r3290027 r3335490 225 225 * Send the logged data to Logtivity 226 226 * 227 * @return ?array228 */ 229 public function send(): ?array227 * @return void 228 */ 229 public function send(): void 230 230 { 231 231 $this->maybeAddProfileLink(); … … 234 234 235 235 if ($this->active) { 236 return $this->makeRequest('/logs/store', $this->getData()); 237 } 238 239 return null; 236 $this->makeRequest('/logs/store', $this->getData()); 237 } 240 238 } 241 239 -
logtivity/trunk/assets/app.js
r3306623 r3335490 4 4 this.container = $('#logtivity-log-index'); 5 5 6 if (!this.container.length) { 7 return; 6 if (this.container.length) { 7 this.form = $('#logtivity-log-index-search-form'); 8 this.listenForPagination(); 9 this.listenForChange(); 10 this.filter(); 11 this.listenForViewLog() 12 this.listenForCloseModal(); 8 13 } 9 10 this.form = $('#logtivity-log-index-search-form');11 this.listenForPagination();12 this.listenForChange();13 this.filter();14 this.listenForViewLog()15 this.listenForCloseModal();16 14 }, 17 15 … … 19 17 let listenForCloseModal = this; 20 18 21 $( "body").on("click", ".js-logtivity-notice-dismiss", function(e) {19 $('body').on('click', '.js-logtivity-notice-dismiss', function(e) { 22 20 e.preventDefault(); 23 21 … … 26 24 27 25 $(document).on('keyup', function(e) { 28 if (e.key === "Escape") {26 if (e.key === 'Escape') { 29 27 listenForCloseModal.hideModal(); 30 28 } … … 49 47 let listenForViewLog = this; 50 48 51 $( "body").on("click", ".js-logtivity-view-log", function(e) {49 $('body').on('click', '.js-logtivity-view-log', function(e) { 52 50 e.preventDefault(); 53 51 … … 74 72 timeout = null; 75 73 76 $( "body").on("input", "#logtivity-log-index-search-form input", function(e) {74 $('body').on('input', '#logtivity-log-index-search-form input', function(e) { 77 75 e.preventDefault(); 78 76 … … 93 91 loading: function() { 94 92 this.container.html( 95 '<div style="text-align: center; padding-bottom: 20px"><div class="spinner is-active" style="float:none;width:auto;height:auto;padding:10px 0 10px 50px;background-position:20px 0;"></div></div>' 93 '<div style="text-align: center; padding-bottom: 20px">' 94 + '<div class="spinner is-active" style="float:none;width:auto;height:auto;padding:10px 0 10px 50px;background-position:20px 0;"></div>' 95 + '</div>' 96 96 ); 97 97 }, … … 100 100 let listenForPagination = this; 101 101 102 $( "body").on("click", ".js-logtivity-pagination", function(e) {102 $('body').on('click', '.js-logtivity-pagination', function(e) { 103 103 e.preventDefault(); 104 104 -
logtivity/trunk/composer.json
r3290027 r3335490 25 25 }, 26 26 "require": { 27 "php" : ">=7.4",27 "php" : ">=7.4", 28 28 "ext-json": "*" 29 29 }, -
logtivity/trunk/logtivity.php
r3306623 r3335490 6 6 * Description: Record activity logs and errors logs across all your WordPress sites. 7 7 * Author: Logtivity 8 * Version: 3. 1.128 * Version: 3.2.0 9 9 * Text Domain: logtivity 10 10 * Requires at least: 4.7 … … 45 45 * @var string 46 46 */ 47 protected string $version = '3. 1.12';47 protected string $version = '3.2.0'; 48 48 49 49 /** 50 50 * List all classes here with their file paths. Keep class names the same as filenames. 51 51 * Ordering of this list matters! 52 * @TODO: Implement ps t-0 autoloading52 * @TODO: Implement psr-0 autoloading 53 53 * 54 54 * @var string[] … … 71 71 'Services/Logtivity_Check_For_Disabled_Individual_Logs', 72 72 'Services/Logtivity_Check_For_New_Settings', 73 'Services/Logtivity_Rest_Endpoints', 73 74 /** 74 75 * Error logging … … 79 80 'Errors/Logtivity_Error_Log', 80 81 ]; 81 82 82 /** 83 83 * @var string[] … … 96 96 'Logs/Core/Logtivity_Meta', 97 97 ]; 98 99 98 /** 100 99 * List all integration dependencies … … 177 176 { 178 177 require_once plugin_dir_path(__FILE__) . $filePath . '.php'; 178 } 179 180 /** 181 * Review updates based on version 182 * 183 * @return void 184 */ 185 public function updateCheck(): void 186 { 187 $currentVersion = get_option('logtivity_version'); 188 189 if (version_compare($currentVersion, '3.1.6', '<=')) { 190 static::checkCapabilities(); 191 } 192 193 if ($currentVersion && version_compare($currentVersion, '3.1.7', '<=')) { 194 // Default for updating sites should be no behavior change 195 update_option('logtivity_app_verify_url', 0); 196 } 197 198 update_option('logtivity_version', $this->version); 199 } 200 201 /** 202 * Custom capabilities added prior to v3.1.7 203 * 204 * @return void 205 */ 206 public static function checkCapabilities(): void 207 { 208 $capabilities = array_filter( 209 array_keys(logtivity_get_capabilities()), 210 function (string $capability): bool { 211 return in_array($capability, [Logtivity::ACCESS_LOGS, Logtivity::ACCESS_SETTINGS]); 212 } 213 ); 214 215 if ($capabilities == false) { 216 // Make sure at least admins can access us 217 if ($role = get_role('administrator')) { 218 if ($role->has_cap(Logtivity::ACCESS_LOGS) == false) { 219 $role->add_cap(Logtivity::ACCESS_LOGS); 220 } 221 if ($role->has_cap(Logtivity::ACCESS_SETTINGS) == false) { 222 $role->add_cap(Logtivity::ACCESS_SETTINGS); 223 } 224 } 225 } 179 226 } 180 227 … … 270 317 if ($created) { 271 318 $createdTimestamp = strtotime($created); 272 $creationText = sprintf(319 $creationText = sprintf( 273 320 'It was created on %s at %s ', 274 321 wp_date(get_option('date_format'), $createdTimestamp), … … 290 337 } 291 338 292 return $response ?? null;339 return $response; 293 340 } 294 341 … … 313 360 { 314 361 return new Logtivity_Error_Logger($error); 315 }316 317 /**318 * Review updates based on version319 *320 * @return void321 */322 public function updateCheck(): void323 {324 $currentVersion = get_option('logtivity_version');325 326 if (version_compare($currentVersion, '3.1.6', '<=')) {327 static::checkCapabilities();328 }329 330 if ($currentVersion && version_compare($currentVersion, '3.1.7', '<=')) {331 // Default for updating sites should be no behavior change332 update_option('logtivity_app_verify_url', 0);333 }334 335 update_option('logtivity_version', $this->version);336 362 } 337 363 … … 423 449 424 450 /** 425 * Custom capabilities added prior to v3.1.7426 *427 * @return void428 */429 public static function checkCapabilities(): void430 {431 $capabilities = array_filter(432 array_keys(logtivity_get_capabilities()),433 function (string $capability): bool {434 return in_array($capability, [Logtivity::ACCESS_LOGS, Logtivity::ACCESS_SETTINGS]);435 }436 );437 438 if ($capabilities == false) {439 // Make sure at least admins can access us440 if ($role = get_role('administrator')) {441 if ($role->has_cap(Logtivity::ACCESS_LOGS) == false) {442 $role->add_cap(Logtivity::ACCESS_LOGS);443 }444 if ($role->has_cap(Logtivity::ACCESS_SETTINGS) == false) {445 $role->add_cap(Logtivity::ACCESS_SETTINGS);446 }447 }448 }449 }450 451 /**452 451 * @return void 453 452 */ … … 469 468 current_user_can(static::ACCESS_SETTINGS) 470 469 && logtivity_has_site_url_changed() 470 && (new Logtivity_Options())->isWhiteLabelMode() == false 471 471 && !get_transient('dismissed-logtivity-site-url-has-changed-notice') 472 472 ) { -
logtivity/trunk/readme.txt
r3306623 r3335490 5 5 Requires at least: 6.6 6 6 Tested up to: 6.8 7 Stable tag: 3. 1.127 Stable tag: 3.2.0 8 8 Requires PHP: 7.4 9 9 License: GPLv2 or later … … 262 262 263 263 == Changelog == 264 265 = 3.2.0 = 266 267 * Add JSON Web Token halper class 268 * Add REST api listener 269 * Retrieve more detailed error information on connection fails 270 * Normalize response data 271 * Fix automatic settings checkin 272 * Prevent disconnect on timeout errors 273 274 _Release Date - Monday, July 28, 2025_ 264 275 265 276 = 3.1.12 = -
logtivity/trunk/views/_logs-loop.php
r3272661 r3335490 24 24 25 25 /** 26 * @var string $fileName 27 * @var ?string $message 26 28 * @var object[] $logs 27 * @var ?string $hasNextPage 29 * @var object $meta 30 * @var string $hasNextPage 28 31 */ 29 32
Note: See TracChangeset
for help on using the changeset viewer.