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.3 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 All 156 releases
← All changes | modules/logs/classes/class-log-events-list-table.php +914 -156 5.2 → 6.2.1 View file →
@@ -7,12 +7,20 @@
7 7 */
8 8
9 9 namespace MainWP\Dashboard\Module\Log;
10 10
11 -use MainWP\Dashboard\MainWP_DB;
12 11 use MainWP\Dashboard\MainWP_Utility;
12 +use MainWP\Dashboard\MainWP_UI;
13 +use MainWP\Dashboard\MainWP_Connect;
14 +use MainWP\Dashboard\MainWP_Manage_Sites;
13 15 use MainWP\Dashboard\MainWP_Updates_Helper;
16 +use MainWP\Dashboard\MainWP_Site_Open;
14 17
18 +// Exit if accessed directly.
19 +if ( ! defined( 'ABSPATH' ) ) {
20 + exit;
21 +}
22 +
15 23 /**
16 24 * Class Log_Events_List_Table
17 25 *
18 26 * @package MainWP\Dashboard
@@ -33,9 +41,17 @@
33 41 * @var array
34 42 */
35 43 public $items;
36 44
45 +
37 46 /**
47 + * Public variable to hold Items information.
48 + *
49 + * @var array
50 + */
51 + public $sites_opts = array();
52 +
53 + /**
38 54 * Public variable to hold Previous Items information.
39 55 *
40 56 * @var array
41 57 */
@@ -42,8 +58,16 @@
42 58 public $items_prev;
43 59
44 60
45 61 /**
62 + * Public variable to hold type value.
63 + *
64 + * @var array
65 + */
66 + public $table_id_prefix = null;
67 +
68 +
69 + /**
46 70 * Public variable to hold total items number.
47 71 *
48 72 * @var integer
49 73 */
@@ -49,8 +73,15 @@
49 73 */
50 74 public $total_items;
51 75
52 76 /**
77 + * Public variable to hold extra data.
78 + *
79 + * @var integer
80 + */
81 + public $items_extra_data;
82 +
83 + /**
53 84 * Protected variable to hold columns headers
54 85 *
55 86 * @var array
56 87 */
@@ -55,17 +86,37 @@
55 86 * @var array
56 87 */
57 88 protected $column_headers;
58 89
90 +
59 91 /**
92 + * Private static variable to hold the optimize value.
93 + *
94 + * @var mixed Default null
95 + */
96 + private $optimize_table = false;
97 +
98 +
99 + /**
100 + * Private static variable to hold the forced modified events title value.
101 + *
102 + * @var mixed Default null
103 + */
104 + private $forced_modified_events = null;
105 +
106 + /**
60 107 * Class constructor.
61 108 *
62 109 * Run each time the class is called.
63 110 *
64 111 * @param Log_Manager $manager Instance of manager object.
112 + * @param Strings $type Events table type: manage_events|widget_overview|widget_insight.
113 + * @param bool $optimize Whether optimize table.
65 114 */
66 - public function __construct( $manager ) {
67 - $this->manager = $manager;
115 + public function __construct( $manager, $type = '', $optimize = false ) {
116 + $this->manager = $manager;
117 + $this->table_id_prefix = $type;
118 + $this->optimize_table = $optimize;
68 119 }
69 120
70 121 /**
71 122 * Get the default primary column name.
@@ -83,11 +134,15 @@
83 134 * @return array $sortable_columns Array of sortable column names.
84 135 */
85 136 public function get_sortable_columns() {
86 137 return array(
87 - 'created' => array( 'created', false ),
88 - 'log_site_name' => array( 'name', false ),
89 - 'user_id' => array( 'user_id', false ),
138 + 'event' => array( 'event', false ),
139 + 'action' => array( 'action', false ),
140 + 'log_object' => array( 'log_object', false ),
141 + 'created' => array( 'created', false ),
142 + 'name' => array( 'name', false ),
143 + 'user_id' => array( 'user_id', false ),
144 + 'source' => array( 'source', false ),
90 145 );
91 146 }
92 147
93 148 /**
@@ -95,13 +150,45 @@
95 150 *
96 151 * @return array Array of default column names.
97 152 */
98 153 public function get_default_columns() {
99 - return array(
100 - 'created' => esc_html__( 'Event', 'mainwp' ),
101 - 'log_site_name' => esc_html__( 'Website', 'mainwp' ),
102 - 'user_id' => esc_html__( 'User', 'mainwp' ),
103 - );
154 + if ( 'widget-overview' === $this->table_id_prefix ) {
155 + $columns = array(
156 + 'created' => esc_html__( 'Time', 'mainwp' ),
157 + 'log_object' => esc_html__( 'Object', 'mainwp' ),
158 + 'event' => esc_html__( 'Event', 'mainwp' ),
159 + 'name' => esc_html__( 'Site', 'mainwp' ),
160 + );
161 + } else {
162 + $columns = array(
163 + 'cb' => '<input type="checkbox" />',
164 + 'created' => esc_html__( 'Date', 'mainwp' ),
165 + 'user_id' => esc_html__( 'User', 'mainwp' ),
166 + 'action' => esc_html__( 'Action', 'mainwp' ),
167 + 'log_object' => esc_html__( 'Object', 'mainwp' ),
168 + 'icon' => '',
169 + 'name' => esc_html__( 'Website', 'mainwp' ),
170 + 'event' => esc_html__( 'Event', 'mainwp' ),
171 + 'source' => esc_html__( 'Source', 'mainwp' ),
172 + 'col_action' => '',
173 + );
174 + }
175 +
176 + if ( 'manage-events' !== $this->table_id_prefix ) {
177 + unset( $columns['source'] );
178 + }
179 +
180 + if ( 'widget-overview' === $this->table_id_prefix ) {
181 + unset( $columns['log_site_name'] );
182 + unset( $columns['icon'] );
183 + unset( $columns['user_id'] );
184 + unset( $columns['action'] );
185 + unset( $columns['source'] );
186 + unset( $columns['col_action'] );
187 + unset( $columns['cb'] );
188 + }
189 +
190 + return $columns;
104 191 }
105 192
106 193 /**
107 194 * Method get_columns()
@@ -139,12 +226,20 @@
139 226 'targets' => 'no-sort',
140 227 'orderable' => false,
141 228 );
142 229 $defines[] = array(
230 + 'targets' => 'manage-cb-column',
231 + 'className' => 'check-column',
232 + );
233 + $defines[] = array(
143 234 'targets' => 'manage-created-column',
144 235 'className' => 'mainwp-created-cell',
145 236 );
146 237 $defines[] = array(
238 + 'targets' => 'manage-icon-column',
239 + 'className' => 'manage-icon-cell center aligned collapsing',
240 + );
241 + $defines[] = array(
147 242 'targets' => 'manage-site-column',
148 243 'className' => 'column-site-bulk mainwp-site-cell',
149 244 );
150 245 $defines[] = array(
@@ -151,11 +246,16 @@
151 246 'targets' => 'manage-user-column',
152 247 'className' => 'mainwp-user-cell',
153 248 );
154 249 $defines[] = array(
155 - 'targets' => array( 'extra-column' ),
250 + 'targets' => array( 'manage-col_action-column' ),
156 251 'className' => 'collapsing',
157 252 );
253 + $defines[] = array(
254 + 'targets' => array( 'manage-log_object-column' ),
255 + 'className' => 'mainwp-sites-changes-object-cell',
256 + );
257 +
158 258 return $defines;
159 259 }
160 260 // @NO_SONAR_END@ .
161 261
@@ -161,13 +261,15 @@
161 261
162 262 /**
163 263 * Returns the column content for the provided item and column.
164 264 *
165 - * @param array $item Record data.
265 + * @param object $item Record data.
166 266 * @param string $column_name Column name.
267 + * @param array $site_opts Site options.
268 + *
167 269 * @return string $out Output.
168 270 */
169 - public function column_default( $item, $column_name ) {
271 + public function column_default( $item, $column_name ) { //phpcs:ignore -- NOSONAR -complex.
170 272 $out = '';
171 273
172 274 $record = new Log_Record( $item );
173 275
@@ -172,30 +274,132 @@
172 274 $record = new Log_Record( $item );
173 275
174 276 $escaped = false;
175 277 switch ( $column_name ) {
278 + case 'cb':
279 + $out = '<div class="ui checkbox">
280 + <input type="checkbox" value="' . (int) $record->log_id . '" name="" aria-label="' . esc_attr__( 'Select the change.', 'mainwp' ) . '"/>
281 + </div>';
282 + $escaped = true;
283 + break;
284 + case 'event':
285 + $out = $this->get_event_title( $record, 'action', true );
286 + $escaped = true;
287 + break;
288 + case 'action':
289 + $out = $this->get_action_title( $record );
290 + $escaped = true;
291 + break;
292 + case 'log_object':
293 + $out = $this->get_object_title( $record );
294 + $escaped = true;
295 + break;
176 296 case 'created':
177 - $event_title = $this->parse_event_title( $record );
178 - $act_label = $this->get_action_title( $record->action, 'action', true );
179 - $date_string = sprintf(
180 - '%s<br>%s<br><time datetime="%s" class="relative-time record-created">%s</time>',
181 - $event_title,
182 - $act_label,
183 - mainwp_module_log_get_iso_8601_extended_date( $record->created ),
184 - MainWP_Utility::format_timestamp( $record->created )
185 - );
186 - $out = $date_string;
187 - $escaped = true;
297 + $site_info = is_array( $this->sites_opts ) && isset( $this->sites_opts[ $record->site_id ] ) && isset( $this->sites_opts[ $record->site_id ]['site_info'] ) ? $this->sites_opts[ $item->site_id ]['site_info'] : array();
298 + $site_dtf = is_array( $site_info ) && isset( $site_info['format_datetime'] ) ? $site_info['format_datetime'] : false;
299 +
300 + $child_time = MainWP_Utility::format_timezone( (int) $record->created, false, $site_dtf );
301 + if ( ! empty( $child_time ) ) {
302 + /* translators: %s: Child site time */
303 + $tooltip_text = esc_attr__( 'Child Site time: %s', 'mainwp' );
304 + $date_string = sprintf(
305 + '<span data-tooltip="' . $tooltip_text . ' " created-time="' . esc_attr( $record->created ) . '" data-inverted="" data-position="right center"><time datetime="%s" class="relative-time record-created">%s</time></span>',
306 + $child_time,
307 + mainwp_module_log_get_iso_8601_extended_date( $record->created ),
308 + MainWP_Utility::format_timezone( $record->created )
309 + );
310 + } else {
311 + $date_string = sprintf(
312 + '<time datetime="%s" created-time="' . esc_attr( $record->created ) . '" class="relative-time record-created">%s</time>',
313 + mainwp_module_log_get_iso_8601_extended_date( $record->created ),
314 + MainWP_Utility::format_timezone( $record->created )
315 + );
316 + }
317 + $out = $date_string;
318 + $escaped = true;
188 319 break;
189 - case 'log_site_name':
190 - $out = ! empty( $record->log_site_name ) ? '<a href="admin.php?page=managesites&dashboard=' . intval( $record->site_id ) . '">' . esc_html( $record->log_site_name ) . '</a>' : 'N/A';
320 + case 'icon':
321 + $out = 'N/A';
322 + if ( ! empty( $record->log_site_name ) ) {
323 + $site_opts = is_array( $this->sites_opts ) && isset( $this->sites_opts[ $record->site_id ] ) ? $this->sites_opts[ $record->site_id ] : array();
324 + $siteObj = (object) array(
325 + 'id' => $record->site_id,
326 + 'url' => $record->url,
327 + 'name' => $record->log_site_name,
328 + 'favi_icon' => is_array( $site_opts ) && isset( $site_opts['favi_icon'] ) ? $site_opts['favi_icon'] : '',
329 + );
330 + $favi_url = MainWP_Connect::get_favico_url( $siteObj );
331 + $site_icon = MainWP_Manage_Sites::get_instance()->get_site_icon_display( is_array( $site_opts ) && isset( $site_opts['cust_site_icon_info'] ) ? $site_opts['cust_site_icon_info'] : '', $favi_url );
332 +
333 + ob_start();
334 + echo $site_icon; // phpcs:ignore WordPress.Security.EscapeOutput
335 + $out = ob_get_clean();
336 + }
191 337 $escaped = true;
192 338 break;
339 + case 'name':
340 + $out = 'N/A';
341 +
342 + if ( ! empty( $record->log_site_name ) ) {
343 + ob_start();
344 + if ( \mainwp_current_user_can( 'dashboard', 'access_wpadmin_on_child_sites' ) ) : ?>
345 + <a href="<?php MainWP_Site_Open::get_open_site_url( $record->site_id ); ?>" class="open_newwindow_wpadmin" target="_blank"><i class="sign in icon"></i></a>
346 + <?php endif; ?>
347 + <a href="<?php echo 'admin.php?page=managesites&dashboard=' . intval( $record->site_id ); ?>">
348 + <?php echo esc_attr( stripslashes( $record->log_site_name ) ); ?>
349 + </a>
350 + <div>
351 + <span class="ui small text">
352 + <a href="<?php echo esc_url( $record->url ); ?>" class="mainwp-may-hide-referrer open_site_url ui grey text" target="_blank">
353 + <?php echo esc_html( MainWP_Utility::get_nice_url( $record->url ) ); ?>
354 + </a>
355 + </span>
356 + </div>
357 + <?php
358 + $out = ob_get_clean();
359 + }
360 + $escaped = true;
361 + break;
193 362 case 'user_id':
194 - $user = new Log_Author( (int) $record->user_id, (array) $record->user_meta );
195 - $out = $user->get_display_name() . sprintf( '<br /><small>%s</small>', $user->get_agent_label( $user->get_agent() ) );
363 + $user_meta = ! empty( $record->user_meta ) ? $record->user_meta : array();
364 +
365 + if ( empty( $user_meta['full_name'] ) && isset( $record->meta['first_name'] ) && isset( $record->meta['last_name'] ) ) {
366 + $user_meta['wp_user_id'] = $record->user_id;
367 + $user_meta['full_name'] = $record->meta['first_name'] . ' ' . $record->meta['last_name'];
368 + $user_meta['ip'] = ! empty( $record->meta['client_ip'] ) ? $record->meta['client_ip'] : '';
369 + }
370 +
371 + $user = new Log_Author( $record->user_id, $user_meta );
372 +
373 + if ( empty( $out ) ) {
374 + if ( ! empty( $record->log_type_id ) || 'non-mainwp-changes' === $record->connector ) {
375 + $out = $user->get_full_name();
376 + } else {
377 + $out = $user->get_display_name();
378 + }
379 + }
380 +
381 + if ( empty( $out ) ) {
382 + $out = $user->get_agent_label( $user->get_agent() );
383 + }
196 384 $escaped = true;
197 385 break;
386 + case 'source':
387 + if ( ! empty( $record->source ) ) {
388 + $out = $record->source; // sub query field.
389 + } else {
390 + $out = ( 'non-mainwp-changes' === $record->connector ) ? 'WP Admin' : 'Dashboard';
391 + }
392 + break;
393 + case 'col_action':
394 + ob_start();
395 + ?>
396 + <div action-id="<?php echo intval( $record->log_id ); ?>">
397 + <a class="ui mini green button insights-actions-row-dismiss" href="javascript:void(0)" data-tooltip="<?php esc_attr_e( 'Dismiss the change.', 'mainwp' ); ?>" data-position="left center" data-inverted=""><?php esc_html_e( 'Dismiss', 'mainwp' ); ?></a>
398 + </div>
399 + <?php
400 + $out = ob_get_clean();
401 + break;
198 402 default:
199 403 }
200 404
201 405 if ( empty( $out ) ) {
@@ -240,43 +444,193 @@
240 444
241 445 /**
242 446 * Returns the label for a connector term.
243 447 *
244 - * @param string $act Action type.
448 + * @param object $record Event data.
449 + * @return string
450 + */
451 + public function get_action_title( $record ) {
452 + if ( ! empty( $record->log_type_id ) ) {
453 + $action = $this->parse_changes_action_title( $record );
454 + } else {
455 + $act = $record->action;
456 + $type = 'action';
457 +
458 + if ( ! isset( $this->manager->connectors->term_labels[ 'logs_' . $type ][ $act ] ) ) {
459 + $title = $act;
460 + } else {
461 + $title = $this->manager->connectors->term_labels[ 'logs_' . $type ][ $act ];
462 + }
463 + $title = is_string( $title ) ? ucfirst( $title ) : $title;
464 + $action = $title;
465 + }
466 + return $action;
467 + }
468 +
469 + /**
470 + * Returns the forced modified event title.
471 + *
472 + * @return array Logs type ids.
473 + */
474 + public function get_forced_modified_event_title() {
475 + if ( null === $this->forced_modified_events ) {
476 + $defaults = array( 1460, 1330, 1335, 1495, 1720, 1721, 1725, 1726 );
477 + $this->forced_modified_events = apply_filters( 'mainwp_module_logs_forced_modified_event_title', $defaults );
478 + }
479 + if ( ! is_array( $this->forced_modified_events ) ) {
480 + $this->forced_modified_events = array();
481 + }
482 + return $this->forced_modified_events;
483 + }
484 +
485 +
486 + /**
487 + * Returns the label for a connector term.
488 + *
489 + * @param string $record Log data.
245 490 * @param string $type Connector term.
246 491 * @param bool $coloring Coloring term.
247 492 * @return string
248 493 */
249 - public function get_action_title( $act, $type, $coloring = false ) {
494 + public function get_event_title( $record, $type, $coloring = false ) { //phpcs:ignore -- NOSONAR - complex.
250 495
251 - if ( ! isset( $this->manager->connectors->term_labels[ 'logs_' . $type ][ $act ] ) ) {
496 + $act = $record->action;
497 +
498 + if ( ! empty( $record->log_type_id ) ) {
252 499 $title = $act;
500 + if ( in_array( (int) $record->log_type_id, $this->get_forced_modified_event_title() ) ) {
501 + $title = esc_html__( 'Modified', 'mainwp' );
502 + } else {
503 + $title = ucfirst( $title );
504 + }
253 505 } else {
254 - $title = $this->manager->connectors->term_labels[ 'logs_' . $type ][ $act ];
506 + if ( ! isset( $this->manager->connectors->term_labels[ 'logs_' . $type ][ $act ] ) ) {
507 + $title = $act;
508 + } else {
509 + $title = $this->manager->connectors->term_labels[ 'logs_' . $type ][ $act ];
510 + }
511 + $title = is_string( $title ) ? ucfirst( $title ) : $title;
255 512 }
256 513
257 - $title = is_string( $title ) ? ucfirst( $title ) : $title;
258 514 if ( $coloring ) {
259 - $format_title = '<span class="ui medium text">%s</span>';
260 - if ( 'deactivate' === $act || 'deleted' === $act || 'delete' === $act ) {
261 - $format_title = '<span class="ui medium red text">%s</span>';
262 - } elseif ( 'activate' === $act || 'updated' === $act || 'update' === $act ) {
263 - $format_title = '<span class="ui medium blue text">%s</span>';
264 - } elseif ( 'install' === $act || 'created' === $act || 'added' === $act || 'sync' === $act ) {
265 - $format_title = '<span class="ui medium green text">%s</span>';
515 +
516 + $color = '';
517 +
518 + if ( in_array( $act, array( 'deleted', 'removed', 'revoked', 'deactivated', 'disabled', 'suspended', 'trashed' ), true ) ) {
519 + $color = 'red';
520 + } elseif ( in_array( $act, array( 'updated', 'modified', 'unapproved', 'spammed' ), true ) ) {
521 + $color = 'orange';
522 + } elseif ( in_array( $act, array( 'added', 'activated', 'created', 'published', 'enabled', 'approved' ), true ) ) {
523 + $color = 'green';
524 + } elseif ( in_array( $act, array( 'synced', 'installed', 'uploaded' ), true ) ) {
525 + $color = 'teal';
526 + } elseif ( in_array( $act, array( 'opened', 'logged-in', 'logged-out', 'unspammed' ), true ) ) {
527 + $color = 'blue';
528 + } else {
529 + $color = 'grey'; // fallback / unknown event
266 530 }
267 - $title = sprintf( $format_title, esc_html( $title ) );
531 +
532 + /* Compatibility aliases */
533 + if ( 'delete' === $act ) {
534 + $color = 'red';
535 + } elseif ( 'deactivate' === $act ) {
536 + $color = 'red';
537 + } elseif ( 'update' === $act ) {
538 + $color = 'orange';
539 + } elseif ( in_array( $act, array( 'install', 'activate' ), true ) ) {
540 + $color = 'teal';
541 + }
542 +
543 + $title = sprintf( '<span class="ui mini basic %s label">%s</span>', $color, esc_html( $title ) );
268 544 }
545 +
269 546 return $title;
270 547 }
271 548
272 549 /**
550 + * Returns the icons for object.
551 + *
552 + * @param string $record Log data.
553 + * @return string
554 + */
555 + public function get_object_icon( $record ) {
556 + $context = $record->context;
557 + $icon = '';
558 + switch ( $context ) {
559 + case 'post':
560 + $icon = 'file text';
561 + break;
562 + case 'file':
563 + $icon = 'file';
564 + break;
565 + case 'system-setting':
566 + $icon = 'cogs';
567 + break;
568 + case 'category':
569 + $icon = 'layer group';
570 + break;
571 + case 'tag':
572 + $icon = 'tag';
573 + break;
574 + case 'widget':
575 + $icon = 'puzzle piece';
576 + break;
577 + case 'plugin':
578 + $icon = 'plug';
579 + break;
580 + case 'theme':
581 + $icon = 'tint icon';
582 + break;
583 + case 'menu':
584 + $icon = 'bars';
585 + break;
586 + case 'comment':
587 + $icon = 'comment';
588 + break;
589 + case 'user':
590 + $icon = 'user';
591 + break;
592 + case 'database':
593 + $icon = 'database';
594 + break;
595 + case 'cron':
596 + $icon = 'clock';
597 + break;
598 + case 'sites':
599 + $icon = 'globe';
600 + break;
601 + // To compatible.
602 + case 'translation':
603 + $icon = 'language';
604 + break;
605 + case 'core':
606 + $icon = 'wordpress icon';
607 + break;
608 + case 'posts':
609 + $icon = 'file text';
610 + break;
611 + case 'clients':
612 + $icon = 'address card';
613 + break;
614 + case 'users':
615 + $icon = 'users';
616 + break;
617 + default:
618 + break;
619 + }
620 + return ! empty( $icon ) ? sprintf( '<i class="%s icon"></i>', $icon ) : '';
621 + }
622 +
623 + /**
273 624 * Parse event title.
274 625 *
275 626 * @param object $record Log record object.
627 + * @param bool $with_icon Return with icon.
628 + * @param bool $with_context_suffix Return name object with context suffix.
629 + *
276 630 * @return string
277 631 */
278 - public function parse_event_title( $record ) {
632 + public function get_object_title( $record, $with_icon = true, $with_context_suffix = true ) { //phpcs:ignore -- NOSONAR - complex.
279 633 $extra_meta = ! empty( $record->extra_meta ) ? json_decode( $record->extra_meta, true ) : array();
280 634 if ( ! is_array( $extra_meta ) ) {
281 635 $extra_meta = array();
282 636 }
@@ -288,8 +642,13 @@
288 642 $roll_msg = MainWP_Updates_Helper::get_roll_msg( $extra_meta['rollback_info'], true ) . ' ';
289 643 }
290 644 } elseif ( 'site' === $record->connector ) {
291 645 $title = esc_html__( 'Website', 'mainwp' );
646 + } elseif ( 'non-mainwp-changes' === $record->connector ) {
647 + $title = esc_html( $record->item );
648 + if ( ! empty( $record->log_type_id ) ) {
649 + $title = $this->get_changes_object_title( $record );
650 + }
292 651 } elseif ( isset( $extra_meta['name'] ) ) {
293 652 $title = $extra_meta['name'];
294 653 if ( 'installer' === $record->connector && ! empty( $extra_meta['rollback_info'] ) ) {
295 654 $roll_msg = MainWP_Updates_Helper::get_roll_msg( $extra_meta['rollback_info'], true ) . ' ';
@@ -294,46 +653,162 @@
294 653 if ( 'installer' === $record->connector && ! empty( $extra_meta['rollback_info'] ) ) {
295 654 $roll_msg = MainWP_Updates_Helper::get_roll_msg( $extra_meta['rollback_info'], true ) . ' ';
296 655 }
297 656 }
298 - $title = $roll_msg . esc_html( $title ) . $this->get_context_title( $record->context, $record->connector );
657 +
658 + if ( empty( $record->log_type_id && $with_context_suffix ) ) {
659 + $title = $roll_msg . $this->get_context_title( $title, $record->context, $record->connector );
660 + }
661 +
662 + if ( ! $with_context_suffix ) {
663 + $title = trim( $title );
664 + $title = preg_replace( '/( ?(plugin|theme))$/i', '', $title );
665 + }
666 +
667 + if ( ! empty( $record->log_type_id ) ) {
668 + $title = Log_Changes_Logs_Helper::get_changes_logs_object_title( $record, $title );
669 + }
670 +
671 + if ( $with_icon ) {
672 + $obj_icon = $this->get_object_icon( $record );
673 + return $obj_icon . $title;
674 + }
675 +
299 676 return $title;
300 677 }
301 678
302 679 /**
680 + * Method get_log_author_name().
681 + *
682 + * @param object $record Logs record.
683 + *
684 + * @return string Author name.
685 + */
686 + public function get_log_author_name( $record ) { //phpcs:ignore -- NOSONAR - long function.
687 + $name = '';
688 + $user_meta = ! empty( $record->user_meta ) ? $record->user_meta : array();
689 +
690 + if ( empty( $user_meta['full_name'] ) && isset( $record->meta['first_name'] ) && isset( $record->meta['last_name'] ) ) {
691 + $user_meta['wp_user_id'] = $record->user_id;
692 + $user_meta['full_name'] = $record->meta['first_name'] . ' ' . $record->meta['last_name'];
693 + $user_meta['ip'] = ! empty( $record->meta['client_ip'] ) ? $record->meta['client_ip'] : '';
694 + }
695 +
696 + $user = new Log_Author( $record->user_id, $user_meta );
697 +
698 + if ( ! empty( $record->log_type_id ) || 'non-mainwp-changes' === $record->connector ) {
699 + $name = $user->get_full_name();
700 + } else {
701 + $name = $user->get_display_name();
702 + }
703 +
704 + return ! empty( $name ) ? $name : 'N/A';
705 + }
706 +
707 + /**
708 + * Parse event changes logs title.
709 + *
710 + * @param object $record Log record object.
711 + * @return string
712 + */
713 + public function parse_changes_action_title( $record ) {
714 + $data = array( 'action' => ucfirst( $record->action ) );
715 + $meta = ! empty( $record->meta ) && is_array( $record->meta ) ? $record->meta : array();
716 + $na = 'N/A';
717 + switch ( (int) $record->log_type_id ) {
718 + case 1455:
719 + $name = ! empty( $meta['name'] ) ? $meta['name'] : '';
720 + if ( empty( $name ) ) {
721 + $name = ! empty( $meta['plugin'] ) ? $meta['plugin'] : $na;
722 + }
723 + $data['plugin'] = $name;
724 + break;
725 + case 1465:
726 + $data['theme'] = ! empty( $meta['theme'] ) ? basename( $meta['theme'] ) : $na;
727 + break;
728 + case 1460:
729 + case 1470:
730 + $data['name'] = ! empty( $meta['name'] ) ? $meta['name'] : $na;
731 + break;
732 + default:
733 + break;
734 + }
735 + $parse_title = Log_Changes_Logs_Helper::get_changes_log_title( $record->log_type_id, $data, 'action' );
736 + return ! empty( $parse_title ) ? $parse_title : ucfirst( $record->action );
737 + }
738 +
739 + /**
740 + * Parse object changes logs title.
741 + *
742 + * @param string $title Object title.
743 + * @param object $record Log record object.
744 + * @return string
745 + */
746 + public function get_changes_formatted_object_title( $title, $record ) {
747 + $meta = ! empty( $record->meta ) && is_array( $record->meta ) ? $record->meta : array();
748 + $na = 'N/A';
749 + $data = array();
750 + switch ( (int) $record->log_type_id ) { // NOSONAR - switch is ok.
751 + case 1461:
752 + case 1965:
753 + $name = ! empty( $meta['name'] ) ? $meta['name'] : '';
754 + if ( empty( $name ) ) {
755 + $name = ! empty( $meta['plugin'] ) ? $meta['plugin'] : $na;
756 + }
757 + $data['plugin'] = $name;
758 + break;
759 + default:
760 + break;
761 + }
762 + if ( ! empty( $data ) ) {
763 + $formatted_title = Log_Changes_Logs_Helper::get_changes_log_title( $record->log_type_id, $data, 'object' );
764 + if ( ! empty( $formatted_title ) ) {
765 + return $formatted_title;
766 + }
767 + }
768 + return $title;
769 + }
770 +
771 + /**
303 772 * Returns the label for a context.
304 773 *
774 + * @param string $title Current title.
305 775 * @param string $context Log context.
306 776 * @param string $connector Log connector.
307 777 * @return string
308 778 */
309 - public function get_context_title( $context, $connector ) {
310 - $title = '';
779 + public function get_context_title( $title, $context, $connector ) {
780 + $context_title = '';
311 781
782 + if ( in_array( $context, array( 'plugin', 'theme' ) ) ) {
783 + $title = preg_replace( '/( ?(plugin|theme|translation))$/i', '', $title );
784 + $title = trim( $title );
785 + }
786 +
312 787 if ( 'plugin' === $context ) {
313 - $title = esc_html__( 'Plugin', 'mainwp' );
788 + $context_title = esc_html__( 'Plugin', 'mainwp' );
314 789 } elseif ( 'theme' === $context ) {
315 - $title = esc_html__( 'Theme', 'mainwp' );
790 + $context_title = esc_html__( 'Theme', 'mainwp' );
316 791 } elseif ( 'translation' === $context ) {
317 - $title = esc_html__( 'Translation', 'mainwp' );
792 + $context_title = esc_html__( 'Translation', 'mainwp' );
318 793 } elseif ( 'core' === $context ) {
319 - $title = esc_html__( 'WP Core WordPress', 'mainwp' );
794 + $context_title = esc_html__( 'WordPress', 'mainwp' );
320 795 } elseif ( 'posts' === $connector ) {
321 796 if ( 'post' === $context ) {
322 - $title = esc_html__( 'Post', 'mainwp' );
797 + $context_title = esc_html__( 'Post', 'mainwp' );
323 798 } elseif ( 'page' === $context ) {
324 - $title = esc_html__( 'Page', 'mainwp' );
799 + $context_title = esc_html__( 'Page', 'mainwp' );
325 800 } else {
326 - $title = esc_html__( 'Custom Post', 'mainwp' );
801 + $context_title = esc_html__( 'Custom Post', 'mainwp' );
327 802 }
328 803 } elseif ( 'clients' === $context ) {
329 - $title = esc_html__( 'Client', 'mainwp' );
804 + $context_title = esc_html__( 'Client', 'mainwp' );
330 805 } elseif ( 'users' === $context ) {
331 - $title = esc_html__( 'User', 'mainwp' );
806 + $context_title = esc_html__( 'User', 'mainwp' );
332 807 }
333 808
334 - if ( ! empty( $title ) ) {
335 - $title = ' ' . $title;
809 + if ( ! empty( $context_title ) ) {
810 + $title .= ' ' . $context_title;
336 811 }
337 812
338 813 return $title;
339 814 }
@@ -338,21 +813,24 @@
338 813 return $title;
339 814 }
340 815
341 816 /**
817 + * Parse changes logs object title.
818 + *
819 + * @param object $record Log record object.
820 + * @return string
821 + */
822 + public function get_changes_object_title( $record ) {
823 + $title = esc_html( ucwords( str_replace( '-', ' ', $record->context ) ) );
824 + $title = $this->get_changes_formatted_object_title( $title, $record );
825 + return $title;
826 + }
827 +
828 + /**
342 829 * Html output if no Child Sites are connected.
343 - *
344 - * @uses \MainWP\Dashboard\MainWP_DB::instance()::get_websites_count()
345 830 */
346 831 public function no_items() {
347 - ?>
348 - <div class="ui center aligned segment">
349 - <i class="globe massive icon"></i>
350 - <div class="ui header">
351 - <?php esc_html_e( 'No records found.', 'mainwp' ); ?>
352 - </div>
353 - </div>
354 - <?php
832 + MainWP_UI::render_empty_element_placeholder( __( 'No Activity Logged Yet', 'mainwp' ), __( 'Site actions and updates will appear here once activity is detected.', 'mainwp' ), '<em data-emoji=":calendar_spiral:" class="medium"></em>' );
355 833 }
356 834
357 835 /**
358 836 * Method has_items().
@@ -375,11 +853,11 @@
375 853 /**
376 854 * Prepare the items to be listed.
377 855 *
378 856 * @param bool $with_prev_data To get previous data.
379 - * @param array $insights_filters Insights filters.
857 + * @param array $insights_filters Required: Insights filters.
380 858 */
381 - public function prepare_items( $with_prev_data = false, $insights_filters = array() ) { //phpcs:ignore -- NOSONAR - complex method.
859 + public function prepare_items( $with_prev_data, $insights_filters ) { //phpcs:ignore -- NOSONAR - complex method.
382 860
383 861 $req_orderby = '';
384 862 $req_order = null;
385 863
@@ -389,14 +867,18 @@
389 867 $req_orderby = $order_values['orderby'];
390 868 $req_order = $order_values['order'];
391 869 }
392 870
393 - $filter_dtsstart = '';
394 - $filter_dtsstop = '';
395 - $array_clients_ids = array();
396 - $array_groups_ids = array();
397 - $array_users_ids = array();
871 + $filter_dtsstart = '';
872 + $filter_dtsstop = '';
873 + $array_clients_ids = array();
874 + $array_groups_ids = array();
875 + $array_usersfilter_sites_ids = array();
398 876
877 + $sources_conds = '';
878 + $array_sites_ids = array();
879 + $array_events_list = array();
880 +
399 881 extract( $insights_filters ); //phpcs:ignore -- ok.
400 882
401 883 if ( ! empty( $filter_dtsstart ) && ! empty( $filter_dtsstop ) && ! is_numeric( $filter_dtsstart ) && ! is_numeric( $filter_dtsstop ) ) { // after extract.
402 884 // to fix string of date.
@@ -402,15 +884,19 @@
402 884 // to fix string of date.
403 885 $filter_dtsstart = gmdate( 'Y-m-d', strtotime( $filter_dtsstart ) );
404 886 $filter_dtsstop = gmdate( 'Y-m-d', strtotime( $filter_dtsstop ) );
405 887 }
888 + // phpcs:enable WordPress.Security.NonceVerification
406 889
407 - // phpcs:enable
408 -
409 890 // phpcs:disable WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
410 891 $perPage = isset( $_REQUEST['length'] ) ? intval( $_REQUEST['length'] ) : false;
892 +
893 + if ( 'widget-overview' === $this->table_id_prefix && ( false === $perPage || -1 === (int) $perPage ) ) {
894 + $perPage = 25;
895 + }
896 +
411 897 if ( -1 === (int) $perPage || empty( $perPage ) ) {
412 - $perPage = 3999999;
898 + $perPage = 9999999;
413 899 }
414 900 $start = isset( $_REQUEST['start'] ) ? intval( $_REQUEST['start'] ) : 0;
415 901
416 902 $search = isset( $_REQUEST['search']['value'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['search']['value'] ) ) : '';
@@ -416,30 +902,63 @@
416 902 $search = isset( $_REQUEST['search']['value'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['search']['value'] ) ) : '';
417 903
418 904 $recent_number = isset( $_REQUEST['recent_number'] ) ? intval( $_REQUEST['recent_number'] ) : 0;
419 905
420 - // phpcs:enable
906 + $now = time();
421 907
908 + // Get last 24 hours items.
909 + if ( 'widget-overview' === $this->table_id_prefix ) {
910 + if ( empty( $filter_dtsstart ) && empty( $filter_dtsstop ) ) {
911 + $filter_dtsstart = $now - DAY_IN_SECONDS;
912 + $filter_dtsstop = $now;
913 + }
914 + } else {
915 + $filter_dtsstart = ! empty( $filter_dtsstart ) ? strtotime( $filter_dtsstart . ' 00:00:00' ) : '';
916 + $filter_dtsstop = ! empty( $filter_dtsstop ) ? strtotime( $filter_dtsstop . ' 23:59:59' ) : '';
917 + }
918 +
919 + // phpcs:enable WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
920 +
422 921 $args = array(
423 - 'order' => ( 'asc' === $req_order ) ? 'asc' : 'desc',
424 - 'orderby' => $req_orderby,
425 - 'start' => $start,
426 - 'recent_number' => $recent_number,
427 - 'search' => $search,
428 - 'groups_ids' => $array_groups_ids,
429 - 'client_ids' => $array_clients_ids,
430 - 'user_ids' => $array_users_ids,
431 - 'timestart' => strtotime( $filter_dtsstart . ' 00:00:00' ),
432 - 'timestop' => strtotime( $filter_dtsstop . ' 23:59:59' ),
922 + 'order' => ( 'asc' === $req_order ) ? 'asc' : 'desc',
923 + 'orderby' => $req_orderby,
924 + 'start' => $start,
925 + 'recent_number' => $recent_number,
926 + 'search' => $search,
927 + 'groups_ids' => $array_groups_ids,
928 + 'client_ids' => $array_clients_ids,
929 + 'usersfilter_sites_ids' => $array_usersfilter_sites_ids, // format: userid-siteid, siteid = 0 => dashboard user.
930 + 'timestart' => $filter_dtsstart,
931 + 'timestop' => $filter_dtsstop,
932 + 'dismiss' => 0,
933 + 'view' => 'events_list',
934 + 'wpid' => ! empty( $insights_filters['wpid'] ) ? $insights_filters['wpid'] : 0, // int or array of site ids.
935 + 'sources_conds' => $sources_conds,
936 + 'sites_ids' => $array_sites_ids,
937 + 'events' => $array_events_list,
433 938 );
434 939
940 + if ( isset( $_REQUEST['optimize_table'] ) && 1 === intval( $_REQUEST['optimize_table'] ) ) { //phpcs:ignore --ok.
941 + $args['optimize'] = 1;
942 + $args['optimize_with_meta'] = 1;
943 + }
944 +
435 945 $args['records_per_page'] = $perPage;
946 + $args['dev_log_query'] = 0; // 1 for dev logs.
436 947
437 - $this->items = $this->manager->db->get_records( $args );
948 + if ( 'widget-overview' === $this->table_id_prefix ) {
949 + $args['optimize'] = 1;
950 + $args['optimize_with_meta'] = 1;
951 + $args['not_count'] = true;
952 + $args['optimize_has_more'] = true;
953 + } else {
954 + $args['with_all_logs_meta'] = 1; // so it will enable optimize_with_meta too.
955 + }
438 956
439 - if ( isset( $_REQUEST['recent_number'] ) ) { //phpcs:ignore -- ok.
440 - $this->total_items = $this->manager->db->get_found_records_count(); // get this value for recent events request only.
441 - }
957 + $this->items = $this->manager->db->get_records( $args );
958 + $this->total_items = $this->manager->db->get_found_records_count(); // get this value for recent events request only.
959 + $this->sites_opts = $this->manager->db->get_logs_sites_opts();
960 + $this->items_extra_data = $this->manager->db->get_logs_extra_data();
442 961
443 962 $this->items_prev = array();
444 963 if ( $with_prev_data && ! empty( $args['timestart'] ) && ! empty( $args['timestop'] ) && $args['timestart'] < $args['timestop'] ) {
445 964 $timestart_prev = $args['timestart'] - ( $args['timestop'] - $args['timestart'] );
@@ -455,9 +974,9 @@
455 974 * Display the table.
456 975 */
457 976 public function display() {
458 977
459 - $sites_per_page = get_option( 'mainwp_default_sites_per_page', 25 );
978 + $sites_per_page = get_option( 'mainwp_default_manage_insights_events_per_page', 25 );
460 979
461 980 $sites_per_page = intval( $sites_per_page );
462 981
463 982 $pages_length = array(
@@ -467,9 +986,12 @@
467 986 100 => '100',
468 987 300 => '300',
469 988 );
470 989
471 - $pages_length = $pages_length + array( $sites_per_page => $sites_per_page );
990 + if ( ! isset( $pages_length[ $sites_per_page ] ) ) {
991 + $pages_length = $pages_length + array( $sites_per_page => $sites_per_page );
992 + }
993 +
472 994 ksort( $pages_length );
473 995
474 996 if ( isset( $pages_length[-1] ) ) {
475 997 unset( $pages_length[-1] );
@@ -474,36 +996,61 @@
474 996 if ( isset( $pages_length[-1] ) ) {
475 997 unset( $pages_length[-1] );
476 998 }
477 999
1000 + // @since version 5.5.
1001 + $pages_length = apply_filters( 'mainwp_site_changes_table_pages_length', $pages_length, $this->table_id_prefix );
1002 +
1003 + if ( 'widget-overview' === $this->table_id_prefix ) {
1004 + $pages_length = array(
1005 + 25 => '25',
1006 + );
1007 + $sites_per_page = 25;
1008 + }
1009 +
478 1010 $pagelength_val = implode( ',', array_keys( $pages_length ) );
479 1011 $pagelength_title = implode( ',', array_values( $pages_length ) );
480 1012
1013 + $ajaxaction = 'mainwp_module_log_manage_events_display_rows';
1014 + if ( 'widget-insight' === $this->table_id_prefix ) {
1015 + $ajaxaction = 'mainwp_module_log_widget_insights_display_rows';
1016 + } elseif ( 'widget-overview' === $this->table_id_prefix ) {
1017 + $ajaxaction = 'mainwp_module_log_widget_events_overview_display_rows';
1018 + }
1019 +
1020 + $events_tbl_id = 'mainwp-module-log-records-table';
1021 + if ( ! empty( $this->table_id_prefix ) ) {
1022 + $events_tbl_id .= '-' . esc_attr( $this->table_id_prefix );
1023 + }
1024 +
1025 + if ( 'manage-events' === $this->table_id_prefix ) {
1026 + ?>
1027 + <div class="ui padded segment">
1028 + <?php
1029 + }
481 1030 ?>
482 - <table id="mainwp-module-log-records-table" style="width:100%" class="ui single line selectable unstackable table mainwp-with-preview-table">
483 - <thead>
484 - <tr><?php $this->print_column_headers( true ); ?></tr>
485 - </thead>
486 - <tfoot>
487 - <tr><?php $this->print_column_headers( false ); ?></tr>
488 - </tfoot>
489 - </table>
1031 + <div id="mainwp-module-log-records-table-container" style="opacity:0;">
1032 + <table id="<?php echo esc_attr( $events_tbl_id ); ?>" style="width:100%" class="ui single line <?php echo 'manage-events' === $this->table_id_prefix ? 'selectable' : ''; ?> unstackable table mainwp-with-preview-table">
1033 + <thead>
1034 + <tr><?php $this->print_column_headers( true ); ?></tr>
1035 + </thead>
1036 + </table>
1037 + </div>
490 1038 <?php
491 - $count = $this->get_total_found_rows();
492 - if ( empty( $count ) ) {
1039 + if ( 'manage-events' === $this->table_id_prefix ) {
493 1040 ?>
494 - <div id="sites-table-count-empty" style="display: none;">
495 - <?php $this->no_items(); ?>
496 1041 </div>
497 1042 <?php
498 1043 }
1044 + if ( 'widget-overview' !== $this->table_id_prefix ) {
499 1045 ?>
500 - <div id="mainwp-loading-sites" style="display: none;">
501 - <div class="ui active inverted dimmer">
502 - <div class="ui indeterminate large text loader"><?php esc_html_e( 'Loading ...', 'mainwp' ); ?></div>
503 - </div>
504 - </div>
1046 + <div id="mainwp-loading-sites">
1047 + <div class="ui active page dimmer">
1048 + <div class="ui double text loader"><?php esc_html_e( 'Loading...', 'mainwp' ); ?></div>
1049 + </div>
1050 + </div>
505 1051 <?php
1052 + }
506 1053 $table_features = array(
507 1054 'searching' => 'true',
508 1055 'paging' => 'true',
509 1056 'pagingType' => 'full_numbers',
@@ -509,14 +1056,26 @@
509 1056 'pagingType' => 'full_numbers',
510 1057 'info' => 'true',
511 1058 'colReorder' => '{columns:":not(.check-column):not(:last-child)"}',
512 1059 'stateSave' => 'true',
513 - 'stateDuration' => '0',
1060 + 'stateDuration' => '60 * 60 * 24 * 30',
514 1061 'order' => '[]',
515 1062 'scrollX' => 'true',
516 1063 'responsive' => 'true',
517 1064 'fixedColumns' => '',
1065 + 'searchDelay' => 350,
1066 + 'numbers' => 7,
518 1067 );
1068 +
1069 + // Fix for widget state save overview table.
1070 + if ( 'widget-overview' === $this->table_id_prefix ) {
1071 + $table_features['stateSave'] = 'false';
1072 + $table_features['searching'] = 'false';
1073 + $table_features['paging'] = 'true';
1074 + $table_features['info'] = 'false';
1075 + $table_features['numbers'] = 3;
1076 + }
1077 +
519 1078 ?>
520 1079
521 1080 <script type="text/javascript">
522 1081 var responsive = <?php echo esc_js( $table_features['responsive'] ); ?>;
@@ -522,25 +1081,43 @@
522 1081 var responsive = <?php echo esc_js( $table_features['responsive'] ); ?>;
523 1082 if( jQuery( window ).width() > 1140 ) {
524 1083 responsive = false;
525 1084 }
1085 + var $module_log_table = null;
526 1086 jQuery( document ).ready( function( $ ) {
527 - let $module_log_table = null;
1087 + const manage_tbl_id = '#<?php echo esc_js( $events_tbl_id ); ?>';
1088 + const ajax_action = '<?php echo esc_js( $ajaxaction ); ?>';
1089 +
1090 + let widgetViewSource = '';
1091 +
1092 + if( jQuery('#widget-sites-changes-dropdown-selector').length ){
1093 + widgetViewSource = mainwp_ui_state_load('sites-changes-widget');
1094 + widgetViewSource = ['wp-admin', 'dashboard', '' ].includes(widgetViewSource) ? widgetViewSource : 'wp-admin';
1095 + }
1096 +
528 1097 try {
529 - jQuery( '#mainwp-sites-table-loader' ).hide();
530 - $module_log_table = jQuery( '#mainwp-module-log-records-table' ).on( 'processing.dt', function ( e, settings, processing ) {
531 - jQuery( '#mainwp-loading-sites' ).css( 'display', processing ? 'block' : 'none' );
1098 +
1099 + const nextButton = document.createElement('a');
1100 + nextButton.href = '#';
1101 + nextButton.className = 'ui tiny basic button';
1102 + nextButton.innerHTML = '<?php echo esc_js( __( 'More', 'mainwp' ) ); ?>';
1103 +
1104 + //jQuery( '#mainwp-sites-table-loader' ).hide();
1105 + $module_log_table = jQuery( manage_tbl_id ).on( 'processing.dt', function ( e, settings, processing ) {
1106 + if(jQuery( '#mainwp-loading-sites' ).length){
1107 + jQuery( '#mainwp-loading-sites' ).css( 'display', processing ? 'block' : 'none' );
1108 + }
532 1109 if (!processing) {
533 - let tb = jQuery( '#mainwp-module-log-records-table' );
1110 + let tb = jQuery( manage_tbl_id );
534 1111 tb.find( 'th[cell-cls]' ).each( function(){
535 1112 let ceIdx = this.cellIndex;
536 1113 let cls = jQuery( this ).attr( 'cell-cls' );
537 - jQuery( '#mainwp-module-log-records-table tr' ).each(function(){
1114 + jQuery( manage_tbl_id + ' tr' ).each(function(){
538 1115 jQuery(this).find( 'td:eq(' + ceIdx + ')' ).addClass(cls);
539 1116 } );
540 1117 } );
541 - $( '#mainwp-module-log-records-table .ui.dropdown' ).dropdown();
542 - $( '#mainwp-module-log-records-table .ui.checkbox' ).checkbox();
1118 + $( manage_tbl_id + ' .ui.dropdown' ).dropdown();
1119 + $( manage_tbl_id + ' .ui.checkbox' ).checkbox();
543 1120 }
544 1121 } ).DataTable( {
545 1122 "ajax": {
546 1123 "url": ajaxurl,
@@ -546,17 +1123,53 @@
546 1123 "url": ajaxurl,
547 1124 "type": "POST",
548 1125 "data": function ( d ) {
549 1126 let data = mainwp_secure_data( {
550 - action: 'mainwp_module_log_events_display_rows',
551 - range: $( '#mainwp-module-log-filter-ranges').dropdown('get value'),
552 - group: $( '#mainwp-module-log-filter-groups').dropdown('get value'),
553 - client: $( '#mainwp-module-log-filter-clients').dropdown('get value'),
554 - user: $( '#mainwp-module-log-filter-users').dropdown('get value'),
555 - dtsstart: $('#mainwp-module-log-filter-dtsstart input[type=text]').val(),
556 - dtsstop: $('#mainwp-module-log-filter-dtsstop input[type=text]').val(),
557 - recent_number: 100,
1127 + action: ajax_action,
1128 + range: $( '#mainwp-module-log-filter-ranges').length ? $( '#mainwp-module-log-filter-ranges').dropdown('get value') : '',
1129 + group: $( '#mainwp-module-log-filter-groups').length ? $( '#mainwp-module-log-filter-groups').dropdown('get value') : '',
1130 + client: $( '#mainwp-module-log-filter-clients').length ? $( '#mainwp-module-log-filter-clients').dropdown('get value') : 0,
1131 + user: $( '#mainwp-module-log-filter-users').length ? $( '#mainwp-module-log-filter-users').dropdown('get value') : 0,
1132 + dtsstart: $('#mainwp-module-log-filter-dtsstart input[type=text]').length ? $('#mainwp-module-log-filter-dtsstart input[type=text]').val() : '',
1133 + dtsstop: $('#mainwp-module-log-filter-dtsstop input[type=text]').length ? $('#mainwp-module-log-filter-dtsstop input[type=text]').val() : '',
1134 + current_client_id: $( '#mainwp-widget-filter-current-client-id').length ? $( '#mainwp-widget-filter-current-client-id').val() : 0,
1135 + current_site_id: $( '#mainwp-widget-filter-current-site-id').length ? $( '#mainwp-widget-filter-current-site-id').val() : 0,
558 1136 } );
1137 +
1138 + <?php if ( $this->optimize_table ) { ?>
1139 + data.optimize_table = 1;
1140 + <?php } ?>
1141 +
1142 + if('mainwp_module_log_manage_events_display_rows' === ajax_action ){
1143 + data.source = $( '#mainwp-module-log-filter-source').length ? $( '#mainwp-module-log-filter-source').dropdown('get value') : '';
1144 + data.sites = $( '#mainwp-module-log-filter-sites').length ? $( '#mainwp-module-log-filter-sites').dropdown('get value') : '';
1145 + data.events = $( '#mainwp-module-log-filter-events').length ? $( '#mainwp-module-log-filter-events').dropdown('get value') : '';
1146 + } else {
1147 + if( 'mainwp_module_log_widget_events_overview_display_rows' === ajax_action ){
1148 + data.source = widgetViewSource;
1149 + } else if( 'mainwp_module_log_widget_insights_display_rows' === ajax_action ) {
1150 + // set recent number for none-manage-events table.
1151 + data.recent_number = $( '#mainwp-widget-filter-events-limit').length ? $( '#mainwp-widget-filter-events-limit').val() : 100;
1152 + }
1153 + }
1154 +
1155 + if('mainwp_module_log_manage_events_display_rows' === ajax_action ){
1156 + if( ( data.source == '' || data.source == 'allsource' ) &&
1157 + ( data.events == '' || data.events == 'allevents' ) &&
1158 + ( data.sites == '' || data.sites == 'allsites' ) &&
1159 + ( data.group == '' || data.group == 'alltags' ) &&
1160 + ( data.client == '' || data.client == 'allclients' ) &&
1161 + ( data.user == '' || data.user == 'allusers' ) &&
1162 + data.range == 'thismonth' &&
1163 + data.current_client_id == '' &&
1164 + data.current_site_id == ''
1165 + ){
1166 + jQuery('#mainwp-module-log-filters-row').fadeOut(300);
1167 + } else{
1168 + jQuery('#mainwp-module-log-filters-row').fadeIn(300);
1169 + }
1170 + }
1171 +
559 1172 return $.extend( {}, d, data );
560 1173 },
561 1174 "dataSrc": function ( json ) {
562 1175 for ( let i=0, ien=json.data.length ; i < ien ; i++ ) {
@@ -564,13 +1177,45 @@
564 1177 json.data[i].log_id = json.rowsInfo[i].log_id;
565 1178 json.data[i].created_sort = json.rowsInfo[i].created;
566 1179 json.data[i].state_sort = json.rowsInfo[i].state;
567 1180 }
1181 +
1182 + <?php if ( 'widget-overview' === $this->table_id_prefix ) { ?>
1183 + if (json?.has_more) {
1184 + nextButton.classList.remove('disabled');
1185 + nextButton.removeAttribute('aria-disabled');
1186 + nextButton.removeAttribute('tabindex');
1187 + nextButton.setAttribute('href', '#');
1188 + } else {
1189 + nextButton.classList.add('disabled');
1190 + nextButton.setAttribute('aria-disabled', 'true');
1191 + nextButton.setAttribute('tabindex', '-1');
1192 + nextButton.removeAttribute('href');
1193 + }
1194 + <?php } ?>
568 1195 return json.data;
569 1196 }
570 1197 },
571 - "responsive": responsive,
572 - "searching" : <?php echo esc_js( $table_features['searching'] ); ?>,
1198 + "layout": {
1199 + <?php
1200 + if ( 'widget-overview' === $this->table_id_prefix ) {
1201 + ?>
1202 + "topStart": null,
1203 + "bottomEnd": nextButton
1204 + <?php
1205 + } else {
1206 + ?>
1207 + "bottomEnd": {
1208 + "paging": {
1209 + "numbers": <?php echo intval( $table_features['numbers'] ); ?>
1210 + }
1211 + }
1212 + <?php
1213 + }
1214 + ?>
1215 + },
1216 + 'responsive': responsive,
1217 + 'searching' : <?php echo esc_js( $table_features['searching'] ); ?>,
573 1218 "paging" : <?php echo esc_js( $table_features['paging'] ); ?>,
574 1219 "pagingType" : "<?php echo esc_js( $table_features['pagingType'] ); ?>",
575 1220 "info" : <?php echo esc_js( $table_features['info'] ); ?>,
576 1221 "colReorder" : <?php echo $table_features['colReorder']; // phpcs:ignore -- specical chars. ?>,
@@ -578,50 +1223,122 @@
578 1223 "stateSave" : <?php echo esc_js( $table_features['stateSave'] ); ?>,
579 1224 "stateDuration" : <?php echo esc_js( $table_features['stateDuration'] ); ?>,
580 1225 "order" : <?php echo $table_features['order']; // phpcs:ignore -- specical chars. ?>,
581 1226 "fixedColumns" : <?php echo ! empty( $table_features['fixedColumns'] ) ? esc_js( $table_features['fixedColumns'] ) : '""'; ?>,
582 - "lengthMenu" : [ [<?php echo esc_js( $pagelength_val ); ?>, -1 ], [<?php echo esc_js( $pagelength_title ); ?>, "All"] ],
1227 + "lengthMenu" : [ [<?php echo esc_js( $pagelength_val ); ?>], [<?php echo esc_js( $pagelength_title ); ?>] ],
583 1228 "serverSide": true,
584 1229 "pageLength": <?php echo intval( $sites_per_page ); ?>,
585 1230 "columnDefs": <?php echo wp_json_encode( $this->get_columns_defines() ); ?>,
586 1231 "columns": <?php echo wp_json_encode( $this->get_columns_init() ); ?>,
587 1232 "language": {
588 - "emptyTable": "<?php esc_html_e( 'No events found.', 'mainwp' ); ?>"
1233 + "emptyTable": "<?php echo 'widget-overview' === $this->table_id_prefix ? esc_html__( 'No matching activity was found in the last 24 hours.', 'mainwp' ) : esc_html__( 'No events found.', 'mainwp' ); ?>"
589 1234 },
590 1235 "drawCallback": function( settings ) {
591 1236 this.api().tables().body().to$().attr( 'id', 'mainwp-module-log-records-body-table' );
592 - mainwp_datatable_fix_menu_overflow();
1237 + jQuery( '#mainwp-module-log-records-table-container' ).css( 'opacity', '1' );
1238 + mainwp_datatable_fix_menu_overflow(manage_tbl_id);
593 1239 if ( typeof mainwp_preview_init_event !== "undefined" ) {
594 1240 mainwp_preview_init_event();
595 1241 }
596 - jQuery( '#mainwp-sites-table-loader' ).hide();
1242 + //jQuery( '#mainwp-sites-table-loader' ).hide();
597 1243 if ( jQuery('#mainwp-module-log-records-body-table td.dt-empty').length > 0 && jQuery('#sites-table-count-empty').length ){
598 1244 jQuery('#mainwp-module-log-records-body-table td.dt-empty').html(jQuery('#sites-table-count-empty').html());
599 1245 }
1246 + if( 'manage-events' === '<?php echo esc_js( $this->table_id_prefix ); ?>' ){
1247 + setTimeout(() => {
1248 + jQuery(manage_tbl_id + ' .ui.checkbox').checkbox();
1249 + mainwp_datatable_fix_menu_overflow(manage_tbl_id);
1250 + mainwp_table_check_columns_init(manage_tbl_id);
1251 + if (typeof mainwp_sites_changes_update_dismiss_button_state !== 'undefined') {
1252 + mainwp_sites_changes_update_dismiss_button_state();
1253 + }
1254 + }, 1000);
1255 + }
600 1256 },
601 1257 "initComplete": function( settings, json ) {
1258 + if( 'widget-overview' === '<?php echo esc_js( $this->table_id_prefix ); ?>' ){
1259 + setTimeout(() => {
1260 + jQuery('#mainwp-module-log-records-table-container div.dt-search #dt-search-1').val('');// to fix issue autofill for chrome.
1261 + }, 100);
1262 + }
602 1263 },
603 1264 rowCallback: function (row, data) {
604 1265 jQuery( row ).addClass(data.rowClass);
605 1266 jQuery( row ).attr( 'id', "log-row-" + data.log_id );
1267 + jQuery( row ).attr( 'log-id', data.log_id );
606 1268 jQuery( row ).find('.mainwp-date-cell').attr('data-sort', data.created_sort );
607 1269 jQuery( row ).find('.mainwp-state-cell').attr('data-sort', data.state_sort );
1270 + },
1271 + stateSaveParams: function (settings, data) {
1272 + data._mwpv = mainwpParams.mainwpVersion || 'dev';
1273 + },
1274 + stateLoadParams: function (settings, data) {
1275 + if ((mainwpParams.mainwpVersion || 'dev') !== data._mwpv) return false;
1276 + },
1277 + search: { regex: false, smart: false },
1278 + orderMulti: false,
1279 + searchDelay: <?php echo intval( $table_features['searchDelay'] ); ?>
1280 + <?php
1281 + if ( 'manage-events' === $this->table_id_prefix ) {
1282 + echo ",select: {
1283 + items: 'row',
1284 + style: 'multi+shift',
1285 + selector: 'tr>td.check-column'
1286 + }"; // phpcs:ignore -- NOSONAR -- ok.
608 1287 }
1288 + ?>
1289 + })
1290 +
1291 + if( 'manage-events' === '<?php echo esc_js( $this->table_id_prefix ); ?>' ){
1292 + $module_log_table.on('select', function (e, dt, type, indexes) {
1293 + if( 'row' == type ){
1294 + dt.rows(indexes)
1295 + .nodes()
1296 + .to$().find('td.check-column .ui.checkbox' ).checkbox('set checked');
1297 + }
1298 + }).on('deselect', function (e, dt, type, indexes) {
1299 + if( 'row' == type ){
1300 + dt.rows(indexes)
1301 + .nodes()
1302 + .to$().find('td.check-column .ui.checkbox' ).checkbox('set unchecked');
1303 + }
1304 + });
1305 + }
1306 +
1307 +
1308 + nextButton.addEventListener('click', function (e) {
1309 + e.preventDefault();
1310 +
1311 + if (nextButton.classList.contains('disabled')) {
1312 + return;
1313 + }
1314 + $module_log_table.page('next').draw('page');
609 1315 });
1316 +
610 1317 } catch(err) {
611 1318 // to fix js error.
612 1319 console.log(err);
613 1320 }
614 1321
615 - mainwp_module_log_events_filter = function() {
616 - try {
617 - $module_log_table.ajax.reload();
618 - } catch(err) {
619 - // to fix js error.
620 - console.log(err);
1322 + // Delay dropdown initialization to prevent it from being overwritten.
1323 + setTimeout(() => {
1324 + jQuery( '#widget-sites-changes-dropdown-selector' ).dropdown( {
1325 + onChange: function( value ) {
1326 + mainwp_ui_state_save('sites-changes-widget', value);
1327 + if(widgetViewSource !== value ){
1328 + widgetViewSource = value;
1329 + $module_log_table.ajax.reload();
1330 + }
1331 + }
1332 + } ).dropdown("set selected", widgetViewSource);
1333 + }, 1000);
1334 +
1335 +
1336 + mainwp_module_log_overview_content_filter = function() {
1337 + if(jQuery( '#mainwp-common-filter-segments-model-name').length && 'manage-events' === jQuery( '#mainwp-common-filter-segments-model-name').val() ){
1338 + mainwp_module_log_manage_events_filter();
1339 + return;
621 1340 }
622 - };
623 - mainwp_module_log_overview_content_filter = function() {
624 1341 let range = jQuery( '#mainwp-module-log-filter-ranges').dropdown('get value');
625 1342 let group = jQuery( '#mainwp-module-log-filter-groups').dropdown('get value');
626 1343 let client = jQuery( '#mainwp-module-log-filter-clients').dropdown('get value');
627 1344 let user = jQuery( '#mainwp-module-log-filter-users').dropdown('get value');
@@ -639,14 +1356,14 @@
639 1356 return false;
640 1357 };
641 1358 mainwp_module_log_overview_content_reset_filters = function(resetObj) {
642 1359 try {
643 - let range = jQuery( '#mainwp-module-log-filter-ranges').dropdown('set selected', 'thismonth');
644 - let group = jQuery( '#mainwp-module-log-filter-groups').dropdown('clear');
645 - let client = jQuery( '#mainwp-module-log-filter-clients').dropdown('clear');
646 - let user = jQuery( '#mainwp-module-log-filter-users').dropdown('clear');
647 - let dtsstart = jQuery('#mainwp-module-log-filter-dtsstart input[type=text]').val('');
648 - let dtsstop = jQuery('#mainwp-module-log-filter-dtsstop input[type=text]').val('');
1360 + jQuery( '#mainwp-module-log-filter-ranges').dropdown('set selected', 'thismonth');
1361 + jQuery( '#mainwp-module-log-filter-groups').dropdown('clear');
1362 + jQuery( '#mainwp-module-log-filter-clients').dropdown('clear');
1363 + jQuery( '#mainwp-module-log-filter-users').dropdown('clear');
1364 + jQuery('#mainwp-module-log-filter-dtsstart input[type=text]').val('');
1365 + jQuery('#mainwp-module-log-filter-dtsstop input[type=text]').val('');
649 1366 jQuery(resetObj).attr('disabled', 'disabled');
650 1367 mainwp_module_log_overview_content_filter();
651 1368 } catch(err) {
652 1369 // to fix js error.
@@ -652,11 +1369,40 @@
652 1369 // to fix js error.
653 1370 console.log(err);
654 1371 }
655 1372 };
1373 + _init_manage_events_screen();
1374 + } );
656 1375
657 - } );
1376 + _init_manage_events_screen = function() {
1377 + jQuery( '#mainwp-manage-events-screen-options-modal input[type=checkbox][id^="mainwp_show_column_"]' ).each( function() {
1378 + let check_id = jQuery( this ).attr( 'id' );
1379 + col_id = check_id.replace( "mainwp_show_column_", "" );
1380 + try {
1381 + $module_log_table.column( '#' + col_id ).visible( jQuery(this).is( ':checked' ) );
1382 + } catch(err) {
1383 + // to fix js error.
1384 + }
1385 + } );
1386 + };
658 1387
1388 + mainwp_manage_events_screen_options = function () {
1389 + jQuery( '#mainwp-manage-events-screen-options-modal' ).modal( {
1390 + allowMultiple: true,
1391 + onHide: function () {
1392 + //ok.
1393 + }
1394 + } ).modal( 'show' );
1395 +
1396 + jQuery( '#manage-events-screen-options-form' ).submit( function() {
1397 + if ( jQuery('input[name=reset_manage_events_columns_order]').attr('value') == 1 ) {
1398 + $module_log_table.colReorder.reset();
1399 + }
1400 + jQuery( '#mainwp-manage-events-screen-options-modal' ).modal( 'hide' );
1401 + } );
1402 + return false;
1403 + };
1404 +
659 1405 </script>
660 1406 <?php
661 1407 }
662 1408
@@ -671,15 +1417,22 @@
671 1417 }
672 1418
673 1419 /**
674 1420 * Echo the column headers.
1421 + *
1422 + * @param bool $top Top header.
1423 + * @return void
675 1424 */
676 - public function print_column_headers() {
1425 + public function print_column_headers( $top ) {
677 1426 list( $columns, $sortable ) = $this->get_column_info();
678 1427
679 1428 $def_columns = $this->get_default_columns();
680 1429 $def_columns['site_actions'] = '';
681 1430
1431 + if ( ! empty( $columns['cb'] ) ) {
1432 + $columns['cb'] = '<div class="ui checkbox"><input id="' . ( $top ? 'cb-select-all-top' : 'cb-select-all-bottom' ) . '" type="checkbox" aria-label="Select all clients." /></div>';
1433 + }
1434 +
682 1435 foreach ( $columns as $column_event_key => $column_display_name ) {
683 1436
684 1437 $class = array( 'manage-' . $column_event_key . '-column' );
685 1438 $attr = '';
@@ -691,8 +1444,13 @@
691 1444 if ( ! isset( $sortable[ $column_event_key ] ) ) {
692 1445 $class[] = 'no-sort';
693 1446 }
694 1447
1448 + if ( 'cb' === $column_event_key ) {
1449 + $class[] = 'check-column';
1450 + $class[] = 'collapsing';
1451 + }
1452 +
695 1453 $tag = 'th';
696 1454 $id = "id='$column_event_key'";
697 1455
698 1456 if ( ! empty( $class ) ) {
@@ -755,24 +1513,23 @@
755 1513
756 1514 $all_rows = array();
757 1515 $info_rows = array();
758 1516
1517 + $columns = $this->get_columns();
1518 +
759 1519 if ( $this->items ) {
760 1520 foreach ( $this->items as $log ) {
761 - $rw_classes = 'log-item mainwp-log-item-' . intval( $log->log_id );
1521 + $created_time = intval( $log->created / 1000000 ); // Seconds.
1522 + $rw_classes = 'log-item mainwp-log-item-' . intval( $log->log_id );
762 1523
763 1524 $info_item = array(
764 1525 'rowClass' => esc_html( $rw_classes ),
765 1526 'log_id' => $log->log_id,
766 1527 'site_id' => ! empty( $log->site_id ) ? $log->site_id : 0,
767 - 'created' => $log->created,
1528 + 'created' => $created_time,
768 1529 'state' => is_null( $log->state ) ? - 1 : $log->state,
769 1530 );
770 -
771 - $columns = $this->get_columns();
772 -
773 1531 $cols_data = array();
774 -
775 1532 foreach ( $columns as $column_name => $column_display_name ) {
776 1533 ob_start();
777 1534 echo $this->column_default( $log, $column_name ); // phpcs:ignore WordPress.Security.EscapeOutput
778 1535 $cols_data[ $column_name ] = ob_get_clean();
@@ -785,7 +1542,8 @@
785 1542 'data' => $all_rows,
786 1543 'recordsTotal' => $this->total_items,
787 1544 'recordsFiltered' => $this->total_items,
788 1545 'rowsInfo' => $info_rows,
1546 + 'has_more' => is_array( $this->items_extra_data ) && ! empty( $this->items_extra_data['has_more'] ) ? true : false,
789 1547 );
790 1548 }
791 1549 }