PluginProbe
MainWP Dashboard: Self-hosted WordPress Management for Agencies / 6.2.1
MainWP Dashboard: Self-hosted WordPress Management for Agencies v6.2.1
6.2.2 6.2.1 6.2 6.1.8 6.1.7 6.1.6 6.1.5 6.1.4 6.1.3 6.1.2 6.1.1 6.1 6.0.12 6.0.11 4.6.0.1 5.0 5.0.1 5.0.2 5.0.3 5.0.3.1 5.0.3.2 5.1 5.1.1 5.2 5.2.1 All 155 releases
← All changes | modules/logs/classes/class-log-manager.php +593 -177 5.0.1 → 6.2.1 View file →
@@ -8,10 +8,17 @@
8 8 */
9 9
10 10 namespace MainWP\Dashboard\Module\Log;
11 11
12 -use MainWP\Dashboard\MainWP_Execution_Helper;
12 +use MainWP\Dashboard\MainWP_DB;
13 +use MainWP\Dashboard\MainWP_Utility;
14 +use MainWP\Dashboard\MainWP_Logger;
13 15
16 +// Exit if accessed directly.
17 +if ( ! defined( 'ABSPATH' ) ) {
18 + exit;
19 +}
20 +
14 21 /**
15 22 * Class Log_Manager
16 23 *
17 24 * @package MainWP\Dashboard
@@ -17,212 +24,621 @@
17 24 * @package MainWP\Dashboard
18 25 */
19 26 class Log_Manager {
20 27
21 - /**
22 - * Version
23 - *
24 - * @const string Plugin version number.
25 - * */
26 - const VERSION = '5.0.0';
28 + /**
29 + * Version
30 + *
31 + * @const string Plugin version number.
32 + * */
33 + const VERSION = '5.0.0';
27 34
28 - /**
29 - * Log_Admin
30 - *
31 - * @var \MainWP\Dashboard\Module\Log\Log_Admin Admin class.
32 - * */
33 - public $admin;
35 + /**
36 + * Log_Admin
37 + *
38 + * @var \MainWP\Dashboard\Module\Log\Log_Admin Admin class.
39 + * */
40 + public $admin;
34 41
35 - /**
36 - * MainWP_Execution_Helper
37 - *
38 - * @var \MainWP\Dashboard\MainWP_Execution_Helper class.
39 - * */
40 - public $executor;
42 + /**
43 + * Holds Instance of settings object
44 + *
45 + * @var Log_Settings
46 + */
47 + public $settings;
41 48
42 - /**
43 - * Holds Instance of settings object
44 - *
45 - * @var Log_Settings
46 - */
47 - public $settings;
49 + /**
50 + * Log_Connectors
51 + *
52 + * @var \MainWP\Dashboard\Module\Log\Log_Connectors Connectors class.
53 + * */
54 + public $connectors;
48 55
49 - /**
50 - * Log_Connectors
51 - *
52 - * @var \MainWP\Dashboard\Module\Log\Log_Connectors Connectors class.
53 - * */
54 - public $connectors;
56 + /**
57 + * Log_DB
58 + *
59 + * @var \MainWP\Dashboard\Module\Log\Log_DB DB Class.
60 + * */
61 + public $db;
55 62
56 - /**
57 - * Log_DB
58 - *
59 - * @var \MainWP\Dashboard\Module\Log\Log_DB DB Class.
60 - * */
61 - public $db;
63 + /**
64 + * Log
65 + *
66 + * @var \MainWP\Dashboard\Module\Log\Log Log Class.
67 + * */
68 + public $log;
62 69
63 - /**
64 - * Log
65 - *
66 - * @var \MainWP\Dashboard\Module\Log\Log Log Class.
67 - * */
68 - public $log;
70 + /**
71 + * Log_Install class.
72 + *
73 + * @var \MainWP\Dashboard\Module\Log\Log_Install Install class.
74 + * */
75 + public $install;
69 76
70 - /**
71 - * Log_Install class.
72 - *
73 - * @var \MainWP\Dashboard\Module\Log\Log_Install Install class.
74 - * */
75 - public $install;
77 + /**
78 + * Holds the last log created time.
79 + *
80 + * @var array
81 + */
82 + private static $last_log_created = array();
76 83
77 - /**
78 - * Locations.
79 - *
80 - * @var array URLs and Paths used by the plugin.
81 - */
82 - public $locations = array();
83 84
84 - /**
85 - * Protected static variable to hold the single instance of the class.
86 - *
87 - * @var mixed Default null
88 - */
89 - protected static $instance = null;
85 + /**
86 + * Locations.
87 + *
88 + * @var array URLs and Paths used by the plugin.
89 + */
90 + public $locations = array();
90 91
91 - /**
92 - * Return the single instance of the class.
93 - *
94 - * @return mixed $instance The single instance of the class.
95 - */
96 - public static function instance() {
97 - if ( is_null( self::$instance ) ) {
98 - self::$instance = new self();
99 - }
100 - return self::$instance;
101 - }
92 + /**
93 + * Protected static variable to hold the single instance of the class.
94 + *
95 + * @var mixed Default null
96 + */
97 + protected static $instance = null;
102 98
103 - /**
104 - * Plugin constructor.
105 - *
106 - * Run each time the class is called.
107 - */
108 - public function __construct() {
99 + /**
100 + * Return the single instance of the class.
101 + *
102 + * @return mixed $instance The single instance of the class.
103 + */
104 + public static function instance() {
105 + if ( is_null( static::$instance ) ) {
106 + static::$instance = new self();
107 + }
108 + return static::$instance;
109 + }
109 110
110 - $mod_log_dir = MAINWP_MODULES_DIR . 'logs/';
111 - $this->locations = array(
112 - 'dir' => $mod_log_dir,
113 - 'url' => MAINWP_MODULES_URL . 'logs/',
114 - 'inc_dir' => $mod_log_dir . 'includes/',
115 - 'class_dir' => $mod_log_dir . 'classes/',
116 - );
111 + /**
112 + * Plugin constructor.
113 + *
114 + * Run each time the class is called.
115 + */
116 + public function __construct() {
117 117
118 - spl_autoload_register( array( $this, 'autoload' ) );
118 + $mod_log_dir = MAINWP_MODULES_DIR . 'logs/';
119 + $this->locations = array(
120 + 'dir' => $mod_log_dir,
121 + 'url' => MAINWP_MODULES_URL . 'logs/',
122 + 'inc_dir' => $mod_log_dir . 'includes/',
123 + 'class_dir' => $mod_log_dir . 'classes/',
124 + );
119 125
120 - // Load helper functions.
121 - require_once $this->locations['inc_dir'] . 'functions.php';
126 + spl_autoload_register( array( $this, 'autoload' ) );
122 127
123 - $driver = new Log_DB_Driver_WPDB();
124 - $this->db = new Log_DB( $driver );
125 - $this->executor = MainWP_Execution_Helper::instance();
126 - $this->settings = new Log_Settings( $this );
128 + // Load helper functions.
129 + require_once $this->locations['inc_dir'] . 'functions.php'; // NOSONAR - WP compatible.
127 130
128 - // Load logger class.
129 - $this->log = new Log( $this );
131 + $driver = new Log_DB_Driver_WPDB();
132 + $this->db = new Log_DB( $driver );
133 + $this->settings = new Log_Settings( $this );
130 134
131 - // Load settings and connectors after widgets_init and before the default init priority.
132 - add_action( 'init', array( $this, 'init' ), 9 );
135 + // Load logger class.
136 + $this->log = new Log( $this );
133 137
134 - // Change DB driver after plugin loaded if any add-ons want to replace.
135 - add_action( 'plugins_loaded', array( $this, 'plugins_loaded' ), 20 );
138 + // Load settings and connectors after widgets_init and before the default init priority.
139 + add_action( 'init', array( $this, 'init' ), 9 );
136 140
137 - // Load admin area classes.
138 - if ( is_admin() || ( defined( 'WP_CLI' ) && WP_CLI ) ) {
139 - $this->admin = new Log_Admin( $this );
140 - } elseif ( defined( 'DOING_CRON' ) && DOING_CRON ) {
141 - $this->admin = new Log_Admin( $this, $driver );
142 - }
143 - }
141 + // Change DB driver after plugin loaded if any add-ons want to replace.
142 + add_action( 'plugins_loaded', array( $this, 'plugins_loaded' ), 20 );
144 143
145 - /**
146 - * Autoloader for classes.
147 - *
148 - * @param string $class_name class name.
149 - */
150 - public function autoload( $class_name ) {
144 + add_action( 'mainwp_delete_site', array( $this, 'hook_delete_site' ), 10, 3 );
151 145
152 - if ( ! preg_match( '/^(?P<namespace>.+)\\\\(?P<autoload>[^\\\\]+)$/', $class_name, $matches ) ) {
153 - return;
154 - }
146 + // Load admin area classes.
147 + if ( is_admin() || ( defined( 'WP_CLI' ) && WP_CLI ) ) {
148 + $this->admin = new Log_Admin( $this );
149 + } elseif ( defined( 'DOING_CRON' ) && DOING_CRON ) {
150 + $this->admin = new Log_Admin( $this, $driver );
151 + }
155 152
156 - static $reflection;
153 + add_filter( 'mainwp_module_log_enable_insert_log_type', array( $this, 'hook_enable_insert_log_type' ), 10, 2 );
154 + add_filter( 'mainwp_get_cron_jobs_init', array( $this, 'hook_get_cron_jobs_init' ), 10, 2 ); // on/off by change status of use wp cron option.
155 + add_filter( 'mainwp_module_logs_changes_logs_sync_params', array( $this, 'hook_changes_logs_sync_params' ), 10, 2 ); // on/off by change status of use wp cron option.
156 + add_filter( 'mainwp_module_logs_get_log_records', array( $this, 'hook_get_log_records' ), 10, 2 ); // Retrieves MainWP log records based on provided query parameters.
157 157
158 - if ( empty( $reflection ) ) {
159 - $reflection = new \ReflectionObject( $this );
160 - }
158 + if ( $this->is_enabled_auto_archive_logs() && ! empty( $this->settings->options['records_logs_ttl'] ) ) {
159 + add_action( 'mainwp_module_log_cron_job_auto_archive', array( $this, 'cron_module_log_auto_archive' ) );
160 + }
161 161
162 - if ( $reflection->getNamespaceName() !== $matches['namespace'] ) {
163 - return;
164 - }
162 + if ( $this->admin instanceof Log_Admin ) {
163 + if ( ! empty( $this->settings->options['enabled'] ) ) {
164 + add_action( 'mainwp_module_log_render_db_size_notice', array( $this->admin, 'render_logs_db_notice' ), 10, 2 );
165 + }
166 + add_action( 'mainwp_module_log_render_db_update_notice', array( $this->admin, 'render_update_db_notice' ), 10, 1 );
167 + }
168 + }
165 169
166 - $autoload_name = $matches['autoload'];
167 - $autoload_dir = \trailingslashit( $this->locations['dir'] );
168 - $load_dirs = array(
169 - 'classes' => 'class',
170 - 'pages' => 'page',
171 - 'widgets' => 'widget',
172 - );
173 - foreach ( $load_dirs as $dir => $prefix ) {
174 - $dir = $dir . '/';
175 - $autoload_path = sprintf( '%s%s%s-%s.php', $autoload_dir, $dir, $prefix, strtolower( str_replace( '_', '-', $autoload_name ) ) );
176 - if ( is_readable( $autoload_path ) ) {
177 - require_once $autoload_path;
178 - return;
179 - }
180 - }
181 - }
182 170
171 + /**
172 + * Autoloader for classes.
173 + *
174 + * @param string $class_name class name.
175 + */
176 + public function autoload( $class_name ) {
183 177
184 - /**
185 - * Get internal connectors.
186 - */
187 - public function get_internal_connectors() {
188 - return array(
189 - 'compact',
190 - );
191 - }
178 + if ( ! preg_match( '/^(?P<namespace>.+)\\\\(?P<autoload>[^\\\\]+)$/', $class_name, $matches ) ) {
179 + return;
180 + }
192 181
193 - /**
194 - * Load Log_Connectors.
195 - *
196 - * @action init
197 - *
198 - * @uses \MainWP\Dashboard\Module\Log\Log_Connectors
199 - */
200 - public function init() {
201 - $this->connectors = new Log_Connectors( $this );
202 - }
182 + static $reflection;
203 183
204 - /**
205 - * Getter for the version number.
206 - *
207 - * @return string
208 - */
209 - public function get_version() {
210 - return self::VERSION;
211 - }
184 + if ( empty( $reflection ) ) {
185 + $reflection = new \ReflectionObject( $this );
186 + }
212 187
213 - /**
214 - * Change plugin database driver in case driver plugin loaded after logs.
215 - *
216 - * @uses \MainWP\Dashboard\Module\Log\Log_DB
217 - * @uses \MainWP\Dashboard\Module\Log\Log_DB_Driver_WPDB
218 - */
219 - public function plugins_loaded() {
220 - // Load DB helper interface/class.
221 - $driver_class = '\MainWP\Dashboard\Module\Log\Log_DB_Driver_WPDB';
188 + if ( $reflection->getNamespaceName() !== $matches['namespace'] ) {
189 + return;
190 + }
222 191
223 - if ( class_exists( $driver_class ) ) {
224 - $driver = new $driver_class();
225 - $this->db = new Log_DB( $driver );
226 - }
227 - }
192 + $autoload_name = $matches['autoload'];
193 + $autoload_dir = \trailingslashit( $this->locations['dir'] );
194 + $load_dirs = array(
195 + 'classes' => 'class',
196 + 'pages' => 'page',
197 + 'widgets' => 'widget',
198 + );
199 + foreach ( $load_dirs as $dir => $prefix ) {
200 + $dir = $dir . '/';
201 + $autoload_path = sprintf( '%s%s%s-%s.php', $autoload_dir, $dir, $prefix, strtolower( str_replace( '_', '-', $autoload_name ) ) );
202 + if ( is_readable( $autoload_path ) ) {
203 + require_once $autoload_path; // NOSONAR - WP compatible.
204 + return;
205 + }
206 + }
207 + }
208 +
209 +
210 + /**
211 + * Get internal connectors.
212 + */
213 + public function get_internal_connectors() {
214 + return array(
215 + 'compact',
216 + );
217 + }
218 +
219 + /**
220 + * Load Log_Connectors.
221 + *
222 + * @action init
223 + *
224 + * @uses \MainWP\Dashboard\Module\Log\Log_Connectors
225 + */
226 + public function init() {
227 + if ( class_exists( '\MainWP\Dashboard\Module\Log\Log_Connectors' ) ) { // to fix fatal error in case class not found.
228 + $this->connectors = new Log_Connectors( $this );
229 + }
230 + }
231 +
232 +
233 + /**
234 + * Getter for the version number.
235 + *
236 + * @return string
237 + */
238 + public function get_version() {
239 + return static::VERSION;
240 + }
241 +
242 + /**
243 + * Change plugin database driver in case driver plugin loaded after logs.
244 + *
245 + * @uses \MainWP\Dashboard\Module\Log\Log_DB
246 + * @uses \MainWP\Dashboard\Module\Log\Log_DB_Driver_WPDB
247 + */
248 + public function plugins_loaded() {
249 + // Load DB helper interface/class.
250 + $driver_class = '\MainWP\Dashboard\Module\Log\Log_DB_Driver_WPDB';
251 +
252 + if ( class_exists( $driver_class ) ) {
253 + $driver = new $driver_class();
254 + $this->db = new Log_DB( $driver );
255 + }
256 + }
257 +
258 + /**
259 + * Method get_sync_actions_last_created().
260 + *
261 + * Sync site changes logs data.
262 + *
263 + * @param int $site_id site id.
264 + *
265 + * @return bool
266 + */
267 + public function get_sync_actions_last_created( $site_id ) {
268 +
269 + if ( ! isset( static::$last_log_created[ $site_id ] ) ) {
270 + $site_opts = MainWP_DB::instance()->get_website_options_array( $site_id, array( 'non_mainwp_changes_sync_last_created' ) );
271 +
272 + if ( ! is_array( $site_opts ) ) {
273 + $site_opts = array();
274 + }
275 +
276 + static::$last_log_created[ $site_id ] = isset( $site_opts['non_mainwp_changes_sync_last_created'] ) ? $site_opts['non_mainwp_changes_sync_last_created'] : 0;
277 +
278 + // to sure.
279 + if ( empty( static::$last_log_created[ $site_id ] ) ) {
280 + static::$last_log_created[ $site_id ] = time() - DAY_IN_SECONDS;
281 + MainWP_DB::instance()->update_website_option( $site_id, 'non_mainwp_changes_sync_last_created', static::$last_log_created[ $site_id ] );
282 + }
283 + }
284 +
285 + return static::$last_log_created[ $site_id ];
286 + }
287 +
288 +
289 + /**
290 + * Method sync_log_site_actions().
291 + *
292 + * Sync site actions data.
293 + *
294 + * @param int $site_id site id.
295 + * @param array $sync_actions action data.
296 + * @param object $website website data.
297 + *
298 + * @return bool
299 + */
300 + public function sync_log_site_actions( $site_id, $sync_actions, $website ) { // phpcs:ignore -- NOSONAR - complex.
301 +
302 + if ( empty( $sync_actions ) || ! is_array( $sync_actions ) ) {
303 + return false;
304 + }
305 +
306 + MainWP_Utility::array_sort_existed_keys( $sync_actions, 'created', SORT_NUMERIC );
307 +
308 + $sync_last_created = (float) $this->get_sync_actions_last_created( $site_id );
309 +
310 + $new_last_created = 0;
311 +
312 + foreach ( $sync_actions as $data ) {
313 + if ( ! is_array( $data ) || empty( $data['action_user'] ) || empty( $data['created'] ) ) {
314 + continue;
315 + }
316 +
317 + $item_created = round( (float) $data['created'], 4 ); // to fix float comparing issue.
318 +
319 + if ( $item_created <= $sync_last_created ) {
320 + continue;
321 + }
322 +
323 + if ( $new_last_created < $item_created ) {
324 + $new_last_created = $item_created;
325 + }
326 +
327 + $user_meta = array();
328 + $meta_data = array();
329 + $extra_info = false;
330 +
331 + if ( isset( $data['meta_data'] ) && is_array( $data['meta_data'] ) ) {
332 + $meta_data = $data['meta_data'];
333 + if ( isset( $meta_data['user_meta'] ) && is_array( $meta_data['user_meta'] ) ) {
334 + $user_meta = $meta_data['user_meta']; // to compatible old user_meta site changes actions data.
335 + unset( $meta_data['user_meta'] );
336 + } elseif ( isset( $meta_data['meta_data'] ) && ! empty( $meta_data['meta_data'] ) && is_array( $meta_data['meta_data'] ) ) {
337 + $user_meta = $meta_data['meta_data']; // new meta_data site changes actions.
338 + unset( $meta_data['meta_data'] );
339 + }
340 + $meta_data['user_meta_json'] = wp_json_encode( $user_meta );
341 + if ( isset( $meta_data['extra_info'] ) && is_array( $meta_data['extra_info'] ) ) {
342 + $extra_info = $meta_data['extra_info'];
343 + }
344 + }
345 +
346 + $user_login = sanitize_text_field( wp_unslash( $data['action_user'] ) );
347 +
348 + $sum = '';
349 + if ( false !== $extra_info ) {
350 + $meta_data['extra_info'] = wp_json_encode( $extra_info );
351 + $sum .= ! empty( $extra_info['name'] ) ? esc_html( $extra_info['name'] ) : '';
352 + } else {
353 + $sum .= ! empty( $meta_data['name'] ) ? esc_html( $meta_data['name'] ) : '';
354 + }
355 + $sum .= ' ';
356 + $sum .= 'wordpress' !== $data['context'] ? esc_html( ucfirst( rtrim( $data['context'], 's' ) ) ) : 'WordPress'; //phpcs:ignore -- wordpress text.
357 +
358 + if ( 'wordpress' === $data['context'] ) {
359 + $sum = 'WordPress';
360 + }
361 +
362 + if ( isset( $user_meta['wp_user_id'] ) ) {
363 + $user_id = ! empty( $user_meta['wp_user_id'] ) ? sanitize_text_field( $user_meta['wp_user_id'] ) : 0;
364 + } elseif ( ! empty( $user_meta['user_id'] ) ) { // to compatible with old child actions data.
365 + $user_id = sanitize_text_field( $user_meta['user_id'] );
366 + } elseif ( isset( $data['user_id'] ) && ! empty( $data['user_id'] ) ) {
367 + $user_id = $data['user_id']; // new sync changes logs data.
368 + }
369 +
370 + $actions_mapping = array(
371 + 'installed' => 'install',
372 + 'deleted' => 'delete',
373 + 'activated' => 'activate',
374 + 'deactivated' => 'deactivate',
375 + );
376 +
377 + $contexts_mapping = array(
378 + 'plugins' => 'plugin',
379 + 'themes' => 'theme',
380 + 'wordpress' => 'core',
381 + );
382 +
383 + $action = isset( $actions_mapping[ $data['action'] ] ) ? $actions_mapping[ $data['action'] ] : $data['action'];
384 + $context = isset( $contexts_mapping[ $data['context'] ] ) ? $contexts_mapping[ $data['context'] ] : $data['context'];
385 +
386 + $created = isset( $data['created'] ) ? (float) $data['created'] : microtime( true );
387 +
388 + // to fix missing slug meta for theme context issue.
389 + if ( ( 'theme' === $context ) && empty( $meta_data['slug'] ) && is_array( $extra_info ) ) {
390 + if ( ! empty( $extra_info['slug'] ) ) {
391 + $meta_data['slug'] = $extra_info['slug'];
392 + } elseif ( empty( $meta_data['name'] ) && ! empty( $extra_info['name'] ) ) {
393 + $meta_data['name'] = $extra_info['name'];
394 + }
395 + }
396 +
397 + $record_mapping = array(
398 + 'site_id' => $site_id,
399 + 'user_id' => $user_id,
400 + 'user_login' => $user_login,
401 + 'created' => $created,
402 + 'item' => $sum,
403 + 'context' => $context,
404 + 'action' => $action,
405 + 'state' => 1,
406 + 'duration' => isset( $data['duration'] ) ? sanitize_text_field( $data['duration'] ) : 0, // sanitize_text_field for seconds.
407 + 'meta' => $meta_data,
408 + );
409 +
410 + do_action( 'mainwp_sync_site_log_install_actions', $website, $record_mapping );
411 + }
412 +
413 + if ( $new_last_created ) {
414 + MainWP_DB::instance()->update_website_option( $site_id, 'non_mainwp_changes_sync_last_created', $new_last_created );
415 + }
416 +
417 + return true;
418 + }
419 +
420 + /**
421 + * Method is_enabled_auto_archive_logs().
422 + *
423 + * @return bool True|False Enabled auto archive log or not.
424 + */
425 + public function is_enabled_auto_archive_logs() {
426 + return is_array( $this->settings->options ) && ! empty( $this->settings->options['enabled'] ) && ! empty( $this->settings->options['auto_archive'] ) ? true : false;
427 + }
428 +
429 + /**
430 + * Method hook_delete_site()
431 + *
432 + * @param mixed $site site object.
433 + *
434 + * @return bool result.
435 + */
436 + public function hook_delete_site( $site ) {
437 + if ( empty( $site ) ) {
438 + return false;
439 + }
440 + return Log_DB_Helper::instance()->remove_logs_by( $site->id );
441 + }
442 +
443 + /**
444 + * Method hook_enable_insert_log_type()
445 + *
446 + * @param bool $enabled Enable input value.
447 + * @param array $data Log data.
448 + *
449 + * @return bool True: Enable log.
450 + */
451 + public function hook_enable_insert_log_type( $enabled, $data ) {
452 + if ( is_array( $data ) && ! empty( $data['log_type_id'] ) ) {
453 + return Log_Settings::is_action_log_enabled( $data['log_type_id'], 'changeslogs' );
454 + } elseif ( is_array( $data ) && isset( $data['connector'] ) && isset( $data['context'] ) && isset( $data['action'] ) ) {
455 + if ( 'non-mainwp-changes' === $data['connector'] ) {
456 + return Log_Settings::is_action_log_enabled( $data['context'] . '_' . $data['action'], 'nonmainwpchanges' );
457 + } elseif ( 'compact' !== $data['connector'] ) {
458 + return Log_Settings::is_action_log_enabled( $data['context'] . '_' . $data['action'], 'dashboard' );
459 + }
460 + }
461 + return $enabled;
462 + }
463 +
464 + /**
465 + * Method hook_get_cron_jobs_init()
466 + *
467 + * @param array $init_jobs Jobs to init.
468 + *
469 + * @return array Init Jobs.
470 + */
471 + public function hook_get_cron_jobs_init( $init_jobs ) {
472 + if ( $this->is_enabled_auto_archive_logs() ) {
473 + $init_jobs['mainwp_module_log_cron_job_auto_archive'] = 'daily';
474 + }
475 + return $init_jobs;
476 + }
477 +
478 + /**
479 + * Method cron_module_log_auto_archive()
480 + */
481 + public function cron_module_log_auto_archive() {
482 + $ttl = 3 * YEAR_IN_SECONDS;
483 + if ( is_array( $this->settings->options ) && isset( $this->settings->options['records_logs_ttl'] ) ) {
484 + $ttl = intval( $this->settings->options['records_logs_ttl'] );
485 + }
486 + if ( $ttl ) {
487 + do_action( 'mainwp_log_action', 'Module Log :: Archive logs schedule start.', MainWP_Logger::LOGS_AUTO_PURGE_LOG_PRIORITY );
488 + $time = time();
489 + $before = $time - $ttl;
490 + Log_DB_Archive::instance()->archive_sites_changes( $before );
491 + update_option( 'mainwp_module_log_last_time_auto_archive_logs', $time );
492 + update_option( 'mainwp_module_log_next_time_auto_archive_logs', $time + $ttl );
493 + }
494 + }
495 +
496 + /**
497 + * Method hook_changes_logs_sync_params()
498 + *
499 + * @param string $params Input value.
500 + * @param int $site_id Site id.
501 + * @param array $postdata Post data.
502 + *
503 + * @return string Empty or json encoded value.
504 + *
505 + * @since 5.5
506 + */
507 + public function hook_changes_logs_sync_params( $params, $site_id, $postdata = array() ) {
508 +
509 + // if it is not a manual sync data.
510 + $sync_logs = isset( $_POST['action'] ) && 'mainwp_syncsites' === $_POST['action'] ? true : false; //phpcs:ignore --ok.
511 + $sync_logs = apply_filters( 'mainwp_module_logs_sync_changes_log', $sync_logs );
512 +
513 + if ( ! $sync_logs ) {
514 + return $params;
515 + }
516 +
517 + $last_created = Log_Changes_Logs_Helper::instance()->get_sync_changes_logs_last_created( $site_id );
518 + $events_count = apply_filters( 'mainwp_module_log_changes_logs_sync_count', 100, $site_id, $postdata );
519 +
520 + $disabled_changeslogs = Log_Settings::get_disabled_logs_type( 'changeslogs' );
521 + $disabled_nonmainwp_actions = Log_Settings::get_disabled_logs_type( 'nonmainwpchanges' );
522 +
523 + $log_settings = get_option( 'mainwp_module_log_settings', array() );
524 + if ( ! is_array( $log_settings ) ) {
525 + $log_settings = array();
526 + }
527 +
528 + return array(
529 + 'newer_than' => $last_created,
530 + 'events_count' => $events_count,
531 + 'ignore_sync_changes_logs' => ! empty( $disabled_changeslogs ) ? $disabled_changeslogs : -1, // -1 to prevent it removed nested empty array from http query builder.
532 + 'ignore_sync_nonmainwp_actions' => ! empty( $disabled_nonmainwp_actions ) ? $disabled_nonmainwp_actions : -1,
533 + 'child_logs_ttl' => ! empty( $log_settings['child_logs_ttl'] ) ? absint( $log_settings['child_logs_ttl'] ) : 7,
534 + 'child_logs_enabled' => ! empty( $log_settings['enabled'] ) ? 1 : 0,
535 + );
536 + }
537 +
538 + /**
539 + * Method hook_get_log_records()
540 + *
541 + * Retrieves MainWP log records based on provided query parameters.
542 + *
543 + * Available $params arguments (all optional):
544 + *
545 + * Default values:
546 + * <code>
547 + * array(
548 + * // LOG TARGETING
549 + * 'log_id' => 0, // Specific log ID.
550 + * 'wpid' => 0, // Site ID or array of site IDs.
551 + *
552 + * // ACCESS / VIEW
553 + * 'check_access' => true, // Apply access restrictions.
554 + * 'view' => '', // View mode: '', 'events_list', 'api-view'.
555 + *
556 + * // OPTIMIZATION
557 + * 'optimize' => false, // Enable optimized query.
558 + * 'optimize_with_meta' => false, // Fetch meta separately when optimized.
559 + * 'with_all_logs_meta' => false, // Load full logs meta.
560 + *
561 + * // RESULT MODE
562 + * 'count_only' => false, // Return count only.
563 + * 'not_count' => false, // Skip count query.
564 + *
565 + * // SEARCH / FILTERS
566 + * 'search' => '', // Search keyword.
567 + * 'dismiss' => null, // true|false|null.
568 + *
569 + * // GROUP / CLIENT FILTERS
570 + * 'groups_ids' => array(), // Filter by group IDs.
571 + * 'client_ids' => array(), // Filter by client IDs.
572 + *
573 + * // USER FILTERS
574 + * 'usersfilter_sites_ids' => array(), // Format: userId-siteId-isDashboardUser.
575 + * 'user_ids' => array(), // Legacy user filter.
576 + *
577 + * // TIME RANGE
578 + * 'timestart' => 0, // Start timestamp (seconds).
579 + * 'timestop' => 0, // End timestamp (seconds).
580 + *
581 + * // SOURCE FILTER
582 + * 'sources_conds' => '', // 'wp-admin-only'|'dashboard-only'.
583 + *
584 + * // CONTEXT / EVENTS
585 + * 'contexts' => '', // CSV contexts list.
586 + * 'sites_ids' => array(), // Explicit site IDs.
587 + * 'events' => array(), // Actions/events filter.
588 + *
589 + * // PAGINATION
590 + * 'start' => 0, // Offset.
591 + * 'records_per_page' => 0, // LIMIT size (0 = unlimited).
592 + *
593 + * // SORTING
594 + * 'order' => 'DESC', // ASC|DESC.
595 + * 'orderby' => 'created', // Sort column.
596 + *
597 + * // RECENT EVENTS
598 + * 'recent_number' => 0, // Limit to recent logs.
599 + * )
600 + * </code>
601 + *
602 + * @param mixed $input_val Default value.
603 + * @param array $params {
604 + * Optional. Log query parameters.
605 + * }
606 + *
607 + * @return array Results.
608 + *
609 + * @since 6.0.1
610 + */
611 + public function hook_get_log_records( $input_val, $params = array() ) {
612 +
613 + unset( $input_val ); // not used, just for hook compatibility.
614 +
615 + $defaults = array(
616 + // Search param.
617 + 'search' => null,
618 + 'search_field' => 'item',
619 + 'records_per_page' => get_option( 'posts_per_page', 20 ),
620 + 'paged' => 1,
621 + // Order.
622 + 'order' => 'desc',
623 + 'orderby' => 'date',
624 + );
625 +
626 + $args = wp_parse_args( $params, $defaults );
627 +
628 + return (array) $this->db->get_records( $args );
629 + }
630 +
631 +
632 + /**
633 + * Method normalize_to_microseconds()
634 + *
635 + * @param mixed $time float time value or microsecords to check.
636 + *
637 + * @return int Normalize microseconds value.
638 + *
639 + * @since 5.5
640 + */
641 + public static function normalize_to_microseconds( $time ) {
642 + return ( $time < 1e12 ) ? (int) ( $time * 1000000 ) : (int) $time;
643 + }
228 644 }