PluginProbe
MainWP Dashboard: Self-hosted WordPress Management for Agencies / 5.3
MainWP Dashboard: Self-hosted WordPress Management for Agencies v5.3
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 5.2.2 5.3 All 153 releases
mainwp / modules / logs / classes / class-log-list-table.php

class-log-list-table.php in MainWP Dashboard: Self-hosted WordPress Management for Agencies 5.3, at modules/logs/classes/class-log-list-table.php

679 lines 23.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Manage Logs List Table.
4 *
5 * @package MainWP/Dashboard
6 */
7
8 namespace MainWP\Dashboard\Module\Log;
9
10 use MainWP\Dashboard\MainWP_DB;
11 use MainWP\Dashboard\MainWP_Utility;
12 /**
13 * Class Log_List_Table - Table class for development only.
14 *
15 * @package MainWP\Dashboard
16 */
17 class Log_List_Table {
18
19 /**
20 * Holds instance of manager object
21 *
22 * @var Log_Manager
23 */
24 public $manager;
25
26
27 /**
28 * Public variable to hold Items information.
29 *
30 * @var array
31 */
32 public $items;
33
34 /**
35 * Public variable to hold total items number.
36 *
37 * @var integer
38 */
39 public $total_items;
40
41 /**
42 * Protected variable to hold columns headers
43 *
44 * @var array
45 */
46 protected $column_headers;
47
48 /**
49 * Class constructor.
50 *
51 * Run each time the class is called.
52 *
53 * @param Log_Manager $manager Instance of manager object.
54 */
55 public function __construct( $manager ) {
56 $this->manager = $manager;
57 }
58
59 /**
60 * Get the default primary column name.
61 *
62 * @return string Child Site name.
63 */
64 protected function get_default_primary_column_name() {
65 return 'site';
66 }
67
68 /**
69 * Returns the column content for the provided item and column.
70 *
71 * @param array $item Record data.
72 * @param string $column_name Column name.
73 * @return string $out Output.
74 */
75 public function column_default( $item, $column_name ) {
76 $out = '';
77
78 $record = new Log_Record( $item );
79
80 $escaped = false;
81 switch ( $column_name ) {
82 case 'date':
83 $created = gmdate( 'Y-m-d H:i:s', $record->created );
84 $out = get_date_from_gmt( $created, 'Y/m/d' );
85 $out .= '<br />';
86 $out .= get_date_from_gmt( $created, 'h:i:s A' );
87 break;
88 case 'item':
89 $out = $record->item;
90 break;
91
92 case 'log_site_name':
93 $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';
94 $escaped = true;
95 break;
96
97 case 'url':
98 $out = ! empty( $record->url ) ? '<a href="' . esc_url( $record->url ) . '" target="_blank">' . esc_html( $record->url ) . '</a>' : 'N/A';
99 $escaped = true;
100 break;
101
102 case 'user_id':
103 $user = new Log_Author( (int) $record->user_id, (array) $record->user_meta );
104 $out = $user->get_display_name() . sprintf( '<br /><small>%s</small>', $user->get_agent_label( $user->get_agent() ) );
105 $escaped = true;
106 break;
107
108 case 'context':
109 $connector_title = $this->get_term_title( $record->connector, 'connector' );
110 $context_title = $this->get_term_title( $record->context, 'context' );
111
112 $out = $connector_title;
113 $out .= '<br />&#8627;&nbsp;';
114 $out .= $context_title;
115 break;
116
117 case 'action':
118 $out = $this->get_term_title( $record->action, 'action' );
119 break;
120 case 'state':
121 $out = $this->get_state_title( $record );
122 break;
123 case 'duration':
124 $out = $record->duration;
125 break;
126 default:
127 }
128
129 if ( empty( $out ) ) {
130 return '';
131 }
132
133 if ( ! $escaped ) {
134 $allowed_tags = wp_kses_allowed_html( 'post' );
135 $allowed_tags['time'] = array(
136 'datetime' => true,
137 'class' => true,
138 );
139
140 $allowed_tags['img']['srcset'] = true;
141
142 return wp_kses( $out, $allowed_tags );
143 } else {
144 return $out; //phpcs:ignore -- escaped.
145 }
146 }
147
148
149 /**
150 * Returns the label for a status.
151 *
152 * @param object $record record item.
153 *
154 * @return string
155 */
156 public function get_state_title( $record ) {
157
158 $state = esc_html__( 'Undefined', 'mainwp' );
159 if ( is_null( $record->state ) ) {
160 $state = 'N/A';
161 } elseif ( '0' === $record->state ) {
162 $state = esc_html__( 'Failed', 'mainwp' );
163 } elseif ( '1' === $record->state ) {
164 $state = esc_html__( 'Success', 'mainwp' );
165 }
166 return $state;
167 }
168
169 /**
170 * Returns the label for a connector term.
171 *
172 * @param string $term Connector label type.
173 * @param string $type Connector term.
174 * @return string
175 */
176 public function get_term_title( $term, $type ) {
177
178 if ( ! isset( $this->manager->connectors->term_labels[ 'logs_' . $type ][ $term ] ) ) {
179 $title = $term;
180 } else {
181 $title = $this->manager->connectors->term_labels[ 'logs_' . $type ][ $term ];
182 }
183
184 $title = is_string( $title ) ? ucfirst( $title ) : $title;
185 return $title;
186 }
187
188 /**
189 * Get sortable columns.
190 *
191 * @return array $sortable_columns Array of sortable column names.
192 */
193 public function get_sortable_columns() {
194 return array(
195 'date' => array( 'date', false ),
196 'log_site_name' => array( 'site', false ),
197 'url' => array( 'site', false ),
198 'user_id' => array( 'user_id', false ),
199 'context' => array( 'context', false ),
200 'action' => array( 'action', false ),
201 'state' => array( 'state', false ),
202 'duration' => array( 'duration', false ),
203 );
204 }
205
206 /**
207 * Get default columns.
208 *
209 * @return array Array of default column names.
210 */
211 public function get_default_columns() {
212 return array(
213 'date' => esc_html__( 'Date', 'mainwp' ),
214 'log_site_name' => esc_html__( 'Site', 'mainwp' ),
215 'url' => esc_html__( 'Url', 'mainwp' ),
216 'item' => esc_html__( 'Item', 'mainwp' ),
217 'user_id' => esc_html__( 'User', 'mainwp' ),
218 'context' => esc_html__( 'Context', 'mainwp' ),
219 'action' => esc_html__( 'Action', 'mainwp' ),
220 'state' => esc_html__( 'State', 'mainwp' ),
221 'duration' => esc_html__( 'Duration', 'mainwp' ),
222 );
223 }
224
225 /**
226 * Method get_columns()
227 *
228 * Combine all columns.
229 *
230 * @return array $columns Array of column names.
231 */
232 public function get_columns() {
233 return $this->get_default_columns();
234 }
235
236 /**
237 * Instantiate Columns.
238 *
239 * @return array $init_cols
240 */
241 public function get_columns_init() {
242 $cols = $this->get_columns();
243 $init_cols = array();
244 foreach ( $cols as $key => $val ) {
245 $init_cols[] = array( 'data' => esc_html( $key ) );
246 }
247 return $init_cols;
248 }
249
250 /**
251 * Get column defines.
252 *
253 * @return array $defines
254 */
255 public function get_columns_defines() {
256 $defines = array();
257 $defines[] = array(
258 'targets' => 'no-sort',
259 'orderable' => false,
260 );
261 $defines[] = array(
262 'targets' => 'manage-site-column',
263 'className' => 'column-site-bulk mainwp-site-cell',
264 );
265 $defines[] = array(
266 'targets' => 'manage-url-column',
267 'className' => 'mainwp-url-cell',
268 );
269 $defines[] = array(
270 'targets' => 'manage-date-column',
271 'className' => 'mainwp-date-cell',
272 );
273 $defines[] = array(
274 'targets' => 'manage-state-column',
275 'className' => 'mainwp-state-cell',
276 );
277 $defines[] = array(
278 'targets' => array( 'extra-column' ),
279 'className' => 'collapsing',
280 );
281 $defines[] = array(
282 'targets' => array( 'manage-site_actions-column' ),
283 'className' => 'collapsing not-selectable',
284 );
285 return $defines;
286 }
287
288
289 /**
290 * Html output if no Child Sites are connected.
291 *
292 * @uses \MainWP\Dashboard\MainWP_DB::instance()::get_websites_count()
293 */
294 public function no_items() {
295 ?>
296 <div class="ui center aligned segment">
297 <i class="globe massive icon"></i>
298 <div class="ui header">
299 <?php esc_html_e( 'No records found.', 'mainwp' ); ?>
300 </div>
301 </div>
302 <?php
303 }
304
305 /**
306 * Method has_items().
307 *
308 * Verify if items exist.
309 */
310 public function has_items() {
311 return ! empty( $this->items );
312 }
313
314 /**
315 * Get last query found rows
316 *
317 * @return integer
318 */
319 public function get_total_found_rows() {
320 return $this->total_items;
321 }
322
323 /**
324 * Prepare the items to be listed.
325 *
326 * @uses \MainWP\Dashboard\MainWP_DB::fetch_object()
327 * @uses \MainWP\Dashboard\MainWP_DB::data_seek()
328 * @uses \MainWP\Dashboard\MainWP_DB::num_rows()
329 * @uses \MainWP\Dashboard\MainWP_DB::free_result()
330 * @uses \MainWP\Dashboard\MainWP_Utility::update_option()
331 */
332 public function prepare_items() {
333
334 $req_orderby = '';
335 $req_order = null;
336
337 // phpcs:disable WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
338 if ( isset( $_REQUEST['order'] ) ) {
339 $order_values = MainWP_Utility::instance()->get_table_orders( $_REQUEST );
340 $req_orderby = $order_values['orderby'];
341 $req_order = $order_values['order'];
342 }
343
344 // phpcs:enable
345
346 // phpcs:disable WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
347 $perPage = isset( $_REQUEST['length'] ) ? intval( $_REQUEST['length'] ) : 25;
348 if ( -1 === (int) $perPage ) {
349 $perPage = 9999;
350 }
351 $start = isset( $_REQUEST['start'] ) ? intval( $_REQUEST['start'] ) : 0;
352
353 $search = isset( $_REQUEST['search']['value'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['search']['value'] ) ) : '';
354
355 // phpcs:enable
356
357 $args = array(
358 'order' => ( 'asc' === $req_order ) ? 'asc' : 'desc',
359 'orderby' => $req_orderby,
360 'start' => $start,
361 'search' => $search,
362 );
363
364 $args['records_per_page'] = $perPage ? $perPage : 20;
365
366 $this->items = $this->manager->db->get_records( $args );
367 $this->total_items = $this->manager->db->get_found_records_count();
368 }
369
370
371 /**
372 * Display the table.
373 */
374 public function display() {
375
376 $sites_per_page = get_option( 'mainwp_default_sites_per_page', 25 );
377
378 $sites_per_page = intval( $sites_per_page );
379
380 $pages_length = array(
381 25 => '25',
382 10 => '10',
383 50 => '50',
384 100 => '100',
385 300 => '300',
386 );
387
388 $pages_length = $pages_length + array( $sites_per_page => $sites_per_page );
389 ksort( $pages_length );
390
391 if ( isset( $pages_length[-1] ) ) {
392 unset( $pages_length[-1] );
393 }
394
395 $pagelength_val = implode( ',', array_keys( $pages_length ) );
396 $pagelength_title = implode( ',', array_values( $pages_length ) );
397
398 ?>
399 <table id="mainwp-module-log-records-table" style="width:100%" class="ui single line selectable unstackable table mainwp-with-preview-table">
400 <thead>
401 <tr><?php $this->print_column_headers( true ); ?></tr>
402 </thead>
403 <tfoot>
404 <tr><?php $this->print_column_headers( false ); ?></tr>
405 </tfoot>
406 </table>
407 <?php
408 $count = $this->get_total_found_rows();
409 if ( empty( $count ) ) {
410 ?>
411 <div id="sites-table-count-empty" style="display: none;">
412 <?php $this->no_items(); ?>
413 </div>
414 <?php
415 }
416 ?>
417 <div id="mainwp-loading-sites" style="display: none;">
418 <div class="ui active inverted dimmer">
419 <div class="ui indeterminate large text loader"><?php esc_html_e( 'Loading ...', 'mainwp' ); ?></div>
420 </div>
421 </div>
422 <?php
423 $table_features = array(
424 'searching' => 'true',
425 'paging' => 'true',
426 'pagingType' => 'full_numbers',
427 'info' => 'true',
428 'colReorder' => '{columns:":not(.check-column):not(:last-child)"}',
429 'stateSave' => 'true',
430 'stateDuration' => '0',
431 'order' => '[]',
432 'scrollX' => 'true',
433 'responsive' => 'true',
434 'fixedColumns' => '',
435 );
436 ?>
437
438 <script type="text/javascript">
439 let responsive = <?php echo esc_js( $table_features['responsive'] ); ?>;
440 if( jQuery( window ).width() > 1140 ) {
441 responsive = false;
442 }
443 jQuery( document ).ready( function( $ ) {
444 try {
445 jQuery( '#mainwp-sites-table-loader' ).hide();
446 $module_log_table = jQuery( '#mainwp-module-log-records-table' ).on( 'processing.dt', function ( e, settings, processing ) {
447 jQuery( '#mainwp-loading-sites' ).css( 'display', processing ? 'block' : 'none' );
448 if (!processing) {
449 let tb = jQuery( '#mainwp-module-log-records-table' );
450 tb.find( 'th[cell-cls]' ).each( function(){
451 let ceIdx = this.cellIndex;
452 let cls = jQuery( this ).attr( 'cell-cls' );
453 jQuery( '#mainwp-module-log-records-table tr' ).each(function(){
454 jQuery(this).find( 'td:eq(' + ceIdx + ')' ).addClass(cls);
455 } );
456 } );
457 $( '#mainwp-module-log-records-table .ui.dropdown' ).dropdown();
458 $( '#mainwp-module-log-records-table .ui.checkbox' ).checkbox();
459 }
460 } ).DataTable( {
461 "ajax": {
462 "url": ajaxurl,
463 "type": "POST",
464 "data": function ( d ) {
465 return $.extend( {}, d, mainwp_secure_data( {
466 action: 'mainwp_module_log_display_rows',
467 } )
468 );
469 },
470 "dataSrc": function ( json ) {
471 for ( let i=0, ien=json.data.length ; i < ien ; i++ ) {
472 json.data[i].rowClass = json.rowsInfo[i].rowClass;
473 json.data[i].log_id = json.rowsInfo[i].log_id;
474 json.data[i].created_sort = json.rowsInfo[i].created;
475 json.data[i].state_sort = json.rowsInfo[i].state;
476 }
477 return json.data;
478 }
479 },
480 "responsive": responsive,
481 "searching" : <?php echo esc_js( $table_features['searching'] ); ?>,
482 "paging" : <?php echo esc_js( $table_features['paging'] ); ?>,
483 "pagingType" : "<?php echo esc_js( $table_features['pagingType'] ); ?>",
484 "info" : <?php echo esc_js( $table_features['info'] ); ?>,
485 "colReorder" : <?php echo $table_features['colReorder']; // phpcs:ignore -- specical chars. ?>,
486 "scrollX" : <?php echo esc_js( $table_features['scrollX'] ); ?>,
487 "stateSave" : <?php echo esc_js( $table_features['stateSave'] ); ?>,
488 "stateDuration" : <?php echo esc_js( $table_features['stateDuration'] ); ?>,
489 "order" : <?php echo $table_features['order']; // phpcs:ignore -- specical chars. ?>,
490 "fixedColumns" : <?php echo ! empty( $table_features['fixedColumns'] ) ? esc_js( $table_features['fixedColumns'] ) : '""'; ?>,
491 "lengthMenu" : [ [<?php echo esc_js( $pagelength_val ); ?>, -1 ], [<?php echo esc_js( $pagelength_title ); ?>, "All"] ],
492 "serverSide": true,
493 "pageLength": <?php echo intval( $sites_per_page ); ?>,
494 "columnDefs": <?php echo wp_json_encode( $this->get_columns_defines() ); ?>,
495 "columns": <?php echo wp_json_encode( $this->get_columns_init() ); ?>,
496 "language": {
497 "emptyTable": "<?php esc_html_e( 'No websites found.', 'mainwp' ); ?>"
498 },
499 "drawCallback": function( settings ) {
500 this.api().tables().body().to$().attr( 'id', 'mainwp-module-log-records-body-table' );
501 mainwp_datatable_fix_menu_overflow();
502 if ( typeof mainwp_preview_init_event !== "undefined" ) {
503 mainwp_preview_init_event();
504 }
505 jQuery( '#mainwp-sites-table-loader' ).hide();
506 if ( jQuery('#mainwp-module-log-records-body-table td.dt-empty').length > 0 && jQuery('#sites-table-count-empty').length ){
507 jQuery('#mainwp-module-log-records-body-table td.dt-empty').html(jQuery('#sites-table-count-empty').html());
508 }
509 },
510 "initComplete": function( settings, json ) {
511 },
512 rowCallback: function (row, data) {
513 jQuery( row ).addClass(data.rowClass);
514 jQuery( row ).attr( 'id', "log-row-" + data.log_id );
515 jQuery( row ).find('.mainwp-date-cell').attr('data-sort', data.created_sort );
516 jQuery( row ).find('.mainwp-state-cell').attr('data-sort', data.state_sort );
517 }
518 } ).on( 'columns-reordered', function () {
519 setTimeout(() => {
520 $( '#mainwp-module-log-records-table .ui.dropdown' ).dropdown();
521 $( '#mainwp-module-log-records-table .ui.checkbox' ).checkbox();
522 mainwp_datatable_fix_menu_overflow();
523 }, 1000 );
524 } );
525 } catch(err) {
526 // to fix js error.
527 }
528 } );
529
530 mainwp_module_log_records_filter = function() {
531 try {
532 $module_log_table.ajax.reload();
533 } catch(err) {
534 // to fix js error.
535 }
536 };
537 </script>
538 <?php
539 }
540
541 /**
542 * Get the column count.
543 *
544 * @return int Column Count.
545 */
546 public function get_column_count() {
547 list( $columns ) = $this->get_column_info();
548 return count( $columns );
549 }
550
551 /**
552 * Echo the column headers.
553 */
554 public function print_column_headers() {
555 list( $columns, $sortable ) = $this->get_column_info();
556
557 $def_columns = $this->get_default_columns();
558 $def_columns['site_actions'] = '';
559
560 foreach ( $columns as $column_log_key => $column_display_name ) {
561
562 $class = array( 'manage-' . $column_log_key . '-column' );
563 $attr = '';
564 if ( ! isset( $def_columns[ $column_log_key ] ) ) {
565 $class[] = 'extra-column';
566 $attr = 'cell-cls="' . esc_html( "collapsing $column_log_key column-$column_log_key" ) . '"';
567 }
568
569 if ( ! isset( $sortable[ $column_log_key ] ) ) {
570 $class[] = 'no-sort';
571 }
572
573 $tag = 'th';
574 $id = "id='$column_log_key'";
575
576 if ( ! empty( $class ) ) {
577 $class = "class='" . join( ' ', $class ) . "'";
578 }
579
580 echo "<$tag $id $class $attr>$column_display_name</$tag>"; // phpcs:ignore WordPress.Security.EscapeOutput
581 }
582 }
583
584 /**
585 * Get column info.
586 */
587 protected function get_column_info() {
588
589 if ( isset( $this->column_headers ) && is_array( $this->column_headers ) ) {
590 $column_headers = array( array(), array(), array(), $this->get_default_primary_column_name() );
591 foreach ( $this->column_headers as $key => $value ) {
592 $column_headers[ $key ] = $value;
593 }
594
595 return $column_headers;
596 }
597
598 $columns = $this->get_columns();
599
600 $sortable_columns = $this->get_sortable_columns();
601
602 $_sortable = $sortable_columns;
603
604 $sortable = array();
605 foreach ( $_sortable as $id => $data ) {
606 if ( empty( $data ) ) {
607 continue;
608 }
609
610 $data = (array) $data;
611 if ( ! isset( $data[1] ) ) {
612 $data[1] = false;
613 }
614
615 $sortable[ $id ] = $data;
616 }
617
618 $primary = $this->get_default_primary_column_name();
619 $this->column_headers = array( $columns, $sortable, $primary );
620
621 return $this->column_headers;
622 }
623
624
625 /**
626 * Get table rows.
627 *
628 * Optimize for shared hosting or big networks.
629 *
630 * @return array Rows html.
631 *
632 * @uses \MainWP\Dashboard\MainWP_Connect::get_favico_url()
633 * @uses \MainWP\Dashboard\MainWP_DB::instance()::get_website_options_array()
634 * @uses \MainWP\Dashboard\MainWP_Utility::get_http_codes()
635 * @uses \MainWP\Dashboard\MainWP_Utility::sanitize_file_name()
636 * @uses \MainWP\Dashboard\MainWP_Utility::get_site_health()
637 * @uses \MainWP\Dashboard\MainWP_Utility::esc_content()
638 * @uses \MainWP\Dashboard\MainWP_Utility::format_timestamp()
639 * @uses \MainWP\Dashboard\MainWP_Utility::get_timestamp()
640 */
641 public function ajax_get_datatable_rows() {
642
643 $all_rows = array();
644 $info_rows = array();
645
646 if ( $this->items ) {
647 foreach ( $this->items as $log ) {
648 $rw_classes = 'log-item mainwp-log-item-' . intval( $log->log_id );
649
650 $info_item = array(
651 'rowClass' => esc_html( $rw_classes ),
652 'log_id' => $log->log_id,
653 'site_id' => ! empty( $log->site_id ) ? $log->site_id : 0,
654 'created' => $log->created,
655 'state' => is_null( $log->state ) ? - 1 : $log->state,
656 );
657
658 $columns = $this->get_columns();
659
660 $cols_data = array();
661
662 foreach ( $columns as $column_name => $column_display_name ) {
663 ob_start();
664 echo $this->column_default( $log, $column_name ); // phpcs:ignore WordPress.Security.EscapeOutput
665 $cols_data[ $column_name ] = ob_get_clean();
666 }
667 $all_rows[] = $cols_data;
668 $info_rows[] = $info_item;
669 }
670 }
671 return array(
672 'data' => $all_rows,
673 'recordsTotal' => $this->total_items,
674 'recordsFiltered' => $this->total_items,
675 'rowsInfo' => $info_rows,
676 );
677 }
678 }
679