PluginProbe
Stream – Activity Log & Audit Trail / 3.0.7
Stream – Activity Log & Audit Trail v3.0.7
4.4.0 4.3.0 4.2.2 4.2.1 trunk 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.0.7 3.1 3.1.1 3.10.0 3.2.0 3.2.1 3.2.2 3.2.3 All 50 releases
stream / classes / class-list-table.php

class-list-table.php in Stream – Activity Log & Audit Trail 3.0.7, at classes/class-list-table.php

1,021 lines 30.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace WP_Stream;
3
4 class List_Table extends \WP_List_Table {
5 /**
6 * Hold Plugin class
7 *
8 * @var Plugin
9 */
10 public $plugin;
11
12 /**
13 * Class constructor.
14 *
15 * @param Plugin $plugin The main Plugin class.
16 * @param array $args
17 */
18 function __construct( $plugin, $args = array() ) {
19 $this->plugin = $plugin;
20
21 $screen_id = isset( $args['screen'] ) ? $args['screen'] : null;
22
23 /**
24 * Filter the list table screen ID
25 *
26 * @return string
27 */
28 $screen_id = apply_filters( 'wp_stream_list_table_screen_id', $screen_id );
29
30 parent::__construct(
31 array(
32 'post_type' => 'stream',
33 'plural' => 'records',
34 'screen' => $screen_id,
35 )
36 );
37
38 add_screen_option(
39 'per_page',
40 array(
41 'default' => 20,
42 'label' => __( 'Records per page', 'stream' ),
43 'option' => 'edit_stream_per_page',
44 )
45 );
46
47 // Check for default hidden columns
48 $this->get_hidden_columns();
49
50 add_filter( 'screen_settings', array( $this, 'screen_controls' ), 10, 2 );
51 add_filter( 'set-screen-option', array( $this, 'set_screen_option' ), 10, 3 );
52
53 set_screen_options();
54 }
55
56 function extra_tablenav( $which ) {
57 if ( 'top' === $which ) {
58 echo $this->filters_form(); // xss ok
59 }
60 }
61
62 function no_items() {
63 ?>
64 <div class="stream-list-table-no-items">
65 <p><?php esc_html_e( 'Sorry, no activity records were found.', 'stream' ) ?></p>
66 </div>
67 <?php
68 }
69
70 function get_columns() {
71 /**
72 * Allows devs to add new columns to table
73 *
74 * @return array
75 */
76 return apply_filters(
77 'wp_stream_list_table_columns',
78 array(
79 'date' => __( 'Date', 'stream' ),
80 'summary' => __( 'Summary', 'stream' ),
81 'user_id' => __( 'User', 'stream' ),
82 'context' => __( 'Context', 'stream' ),
83 'action' => __( 'Action', 'stream' ),
84 'ip' => __( 'IP Address', 'stream' ),
85 )
86 );
87 }
88
89 function get_sortable_columns() {
90 return array(
91 'date' => array( 'date', false ),
92 );
93 }
94
95 function get_hidden_columns() {
96 if ( ! $user = wp_get_current_user() ) {
97 return array();
98 }
99
100 // Directly checking the user meta; to check whether user has changed screen option or not
101 $hidden = $this->plugin->admin->get_user_meta( $user->ID, 'manage' . $this->screen->id . 'columnshidden', true );
102
103 // If user meta is not found; add the default hidden column 'id'
104 if ( ! $hidden ) {
105 $hidden = array( 'id' );
106 $this->plugin->admin->update_user_meta( $user->ID, 'manage' . $this->screen->id . 'columnshidden', $hidden );
107 }
108
109 return $hidden;
110 }
111
112 function prepare_items() {
113 $columns = $this->get_columns();
114 $sortable = $this->get_sortable_columns();
115 $hidden = $this->get_hidden_columns();
116 $primary = $columns['summary'];
117
118 $this->_column_headers = array( $columns, $hidden, $sortable, $primary );
119
120 $this->items = $this->get_records();
121
122 $total_items = $this->get_total_found_rows();
123
124 $this->set_pagination_args(
125 array(
126 'total_items' => $total_items,
127 'per_page' => $this->get_items_per_page( 'edit_stream_per_page', 20 ),
128 )
129 );
130 }
131
132 function get_records() {
133 $args = array();
134
135 // Parse sorting params
136 if ( $order = wp_stream_filter_input( INPUT_GET, 'order' ) ) {
137 $args['order'] = $order;
138 }
139
140 if ( $orderby = wp_stream_filter_input( INPUT_GET, 'orderby' ) ) {
141 $args['orderby'] = $orderby;
142 }
143
144 $params = array(
145 'search',
146 'date',
147 'date_from',
148 'date_to',
149 'date_after',
150 'date_before',
151 );
152
153 foreach ( $params as $param ) {
154 $value = wp_stream_filter_input( INPUT_GET, $param );
155
156 if ( $value ) {
157 $args[ $param ] = $value;
158 }
159 }
160
161 // Additional filter properties
162 $properties = array(
163 'record',
164 'site_id',
165 'blog_id',
166 'object_id',
167 'user_id',
168 'user_role',
169 'ip',
170 'connector',
171 'context',
172 'action',
173 );
174
175 // Add property fields to defaults, including their __in/__not_in variations
176 foreach ( $properties as $property ) {
177 $value = wp_stream_filter_input( INPUT_GET, $property );
178
179 // Allow 0 values
180 if ( isset( $value ) && '' !== $value && false !== $value ) {
181 $args[ $property ] = $value;
182 }
183
184 $value_in = wp_stream_filter_input( INPUT_GET, $property . '__in' );
185
186 if ( $value_in ) {
187 $args[ $property . '__in' ] = explode( ',', $value_in );
188 }
189
190 $value_not_in = wp_stream_filter_input( INPUT_GET, $property . '__not_in' );
191
192 if ( $value_not_in ) {
193 $args[ $property . '__not_in' ] = explode( ',', $value_not_in );
194 }
195 }
196
197 $args['paged'] = $this->get_pagenum();
198
199 if ( isset( $args['context'] ) && 0 === strpos( $args['context'], 'group-' ) ) {
200 $args['connector'] = str_replace( 'group-', '', $args['context'] );
201 $args['context'] = '';
202 }
203
204 if ( ! isset( $args['records_per_page'] ) ) {
205 $args['records_per_page'] = $this->get_items_per_page( 'edit_stream_per_page', 20 );
206 }
207 $args['records_per_page'] = apply_filters( 'stream_records_per_page', $args['records_per_page'] );
208
209 $items = $this->plugin->db->query( $args );
210
211 return $items;
212 }
213
214 /**
215 * Get last query found rows
216 *
217 * @return integer
218 */
219 public function get_total_found_rows() {
220 return $this->plugin->db->query->found_records;
221 }
222
223 function column_default( $item, $column_name ) {
224 $out = '';
225 $record = new Record( $item );
226
227 switch ( $column_name ) {
228 case 'date' :
229 $created = date( 'Y-m-d H:i:s', strtotime( $record->created ) );
230 $date_string = sprintf(
231 '<time datetime="%s" class="relative-time record-created">%s</time>',
232 wp_stream_get_iso_8601_extended_date( strtotime( $record->created ) ),
233 get_date_from_gmt( $created, 'Y/m/d' )
234 );
235 $out = $this->column_link( $date_string, 'date', get_date_from_gmt( $created, 'Y/m/d' ) );
236 $out .= '<br />';
237 $out .= get_date_from_gmt( $created, 'h:i:s A' );
238 break;
239
240 case 'summary' :
241 $out = $record->summary;
242 $object_title = $record->get_object_title();
243 $view_all_text = $object_title ? sprintf( esc_html__( 'View all activity for "%s"', 'stream' ), esc_attr( $object_title ) ) : esc_html__( 'View all activity for this object', 'stream' );
244
245 if ( $record->object_id ) {
246 $out .= $this->column_link(
247 '<span class="dashicons dashicons-search stream-filter-object-id"></span>',
248 array(
249 'object_id' => $record->object_id,
250 'context' => $record->context,
251 ),
252 null,
253 esc_attr( $view_all_text )
254 );
255 }
256 $out .= $this->get_action_links( $record );
257 break;
258
259 case 'user_id' :
260 $user = new Author( (int) $record->user_id, (array) maybe_unserialize( $record->user_meta ) );
261
262 $filtered_records_url = add_query_arg(
263 array(
264 'page' => $this->plugin->admin->records_page_slug,
265 'user_id' => absint( $user->id ),
266 ),
267 self_admin_url( $this->plugin->admin->admin_parent_page )
268 );
269
270 $out = sprintf(
271 '<a href="%s">%s <span>%s</span></a>%s%s%s',
272 $filtered_records_url,
273 $user->get_avatar_img( 80 ),
274 $user->get_display_name(),
275 $user->is_deleted() ? sprintf( '<br /><small class="deleted">%s</small>', esc_html__( 'Deleted User', 'stream' ) ) : '',
276 sprintf( '<br /><small>%s</small>', $user->get_role() ),
277 sprintf( '<br /><small>%s</small>', $user->get_agent_label( $user->get_agent() ) )
278 );
279 break;
280
281 case 'context':
282 $connector_title = $this->get_term_title( $record->{'connector'}, 'connector' );
283 $context_title = $this->get_term_title( $record->{'context'}, 'context' );
284
285 $out = $this->column_link( $connector_title, 'connector', $item->{'connector'} );
286 $out .= '<br />&#8627;&nbsp;';
287 $out .= $this->column_link(
288 $context_title,
289 array(
290 'connector' => $record->{'connector'},
291 'context' => $record->{'context'},
292 )
293 );
294 break;
295
296 case 'action':
297 $out = $this->column_link( $this->get_term_title( $record->{$column_name}, $column_name ), $column_name, $record->{$column_name} );
298 break;
299
300 case 'blog_id':
301 $blog = ( $record->blog_id && is_multisite() ) ? get_blog_details( $record->blog_id ) : $this->plugin->admin->network->get_network_blog();
302 $out = $this->column_link( $blog->blogname, 'blog_id', $blog->blog_id );
303 break;
304
305 case 'ip' :
306 $out = $this->column_link( $record->{$column_name}, 'ip', $record->{$column_name} );
307 break;
308
309 default :
310 /**
311 * Registers new Columns to be inserted into the table. The cell contents of this column is set
312 * below with 'wp_stream_inster_column_default-'
313 *
314 * @return array
315 */
316 $inserted_columns = apply_filters( 'wp_stream_register_column_defaults', $new_columns = array() );
317
318 if ( ! empty( $inserted_columns ) && is_array( $inserted_columns ) ) {
319 foreach ( $inserted_columns as $column_title ) {
320 /**
321 * If column title inserted via wp_stream_register_column_defaults ($column_title) exists
322 * among columns registered with get_columns ($column_name) and there is an action associated
323 * with this column, do the action
324 *
325 * Also, note that the action name must include the $column_title registered
326 * with wp_stream_register_column_defaults
327 */
328 if ( $column_title === $column_name && has_filter( "wp_stream_insert_column_default-{$column_title}" ) ) {
329 /**
330 * Allows for the addition of content under a specified column.
331 *
332 * @param object $record Contents of the row
333 *
334 * @return string
335 */
336 $out = apply_filters( "wp_stream_insert_column_default-{$column_title}", $column_name, $record );
337 } else {
338 $out = $column_name;
339 }
340 }
341 } else {
342 $out = $column_name;
343 }
344 }
345
346 $allowed_tags = wp_kses_allowed_html( 'post' );
347 $allowed_tags['time'] = array( 'datetime' => true, 'class' => true );
348 $allowed_tags['img']['srcset'] = true;
349
350 echo wp_kses( $out, $allowed_tags );
351 }
352
353 public function get_action_links( $record ) {
354 $out = '';
355
356 /**
357 * Filter allows modification of action links for a specific connector
358 *
359 * @param array
360 * @param Record
361 *
362 * @return array Action links for this connector
363 */
364 $action_links = apply_filters( 'wp_stream_action_links_' . $record->connector, array(), $record );
365
366 /**
367 * Filter allows addition of custom links for a specific connector
368 *
369 * @param array
370 * @param Record
371 *
372 * @return array Custom links for this connector
373 */
374 $custom_links = apply_filters( 'wp_stream_custom_action_links_' . $record->connector, array(), $record );
375
376 if ( $action_links || $custom_links ) {
377 $out .= '<div class="row-actions">';
378 }
379
380 $links = array();
381 if ( $action_links && is_array( $action_links ) ) {
382 foreach ( $action_links as $al_title => $al_href ) {
383 $links[] = sprintf(
384 '<span><a href="%s" class="action-link">%s</a></span>',
385 $al_href,
386 $al_title
387 );
388 }
389 }
390
391 if ( $custom_links && is_array( $custom_links ) ) {
392 foreach ( $custom_links as $key => $link ) {
393 $links[] = $link;
394 }
395 }
396
397 $out .= implode( ' | ', $links );
398
399 if ( $action_links || $custom_links ) {
400 $out .= '</div>';
401 }
402
403 return $out;
404 }
405
406 function column_link( $display, $key, $value = null, $title = null ) {
407 $url = add_query_arg(
408 array(
409 'page' => $this->plugin->admin->records_page_slug,
410 ),
411 self_admin_url( $this->plugin->admin->admin_parent_page )
412 );
413
414 $args = ! is_array( $key ) ? array( $key => $value ) : $key;
415
416 foreach ( $args as $k => $v ) {
417 $url = add_query_arg( $k, $v, $url );
418 }
419
420 return sprintf(
421 '<a href="%s" title="%s">%s</a>',
422 esc_url( $url ),
423 esc_attr( $title ),
424 $display
425 );
426 }
427
428 public function get_term_title( $term, $type ) {
429 if ( ! isset( $this->plugin->connectors->term_labels[ "stream_$type" ][ $term ] ) ) {
430 return $term;
431 }
432
433 return $this->plugin->connectors->term_labels[ "stream_$type" ][ $term ];
434 }
435
436 /**
437 * Assembles records for display in search filters
438 *
439 * Gathers list of all users/connectors, then compares it to
440 * results of existing records. All items that do not exist in records
441 * get assigned a disabled value of "true".
442 *
443 * @param string $column List table column name
444 *
445 * @return array Options to be displayed in search filters
446 */
447 function assemble_records( $column ) {
448 // @todo eliminate special condition for authors, especially using a WP_User object as the value; should use string or stringifiable object
449 if ( 'user_id' === $column ) {
450 $all_records = array();
451
452 // If the number of users exceeds the max users constant value then return an empty array and use AJAX instead
453 $user_count = count_users();
454 $total_users = $user_count['total_users'];
455
456 if ( $total_users > $this->plugin->admin->preload_users_max ) {
457 $selected_user = wp_stream_filter_input( INPUT_GET, 'user_id' );
458 if ( $selected_user ) {
459 $user = new Author( $selected_user );
460 return array( $selected_user => $user->get_display_name() );
461 } else {
462 return array();
463 }
464 }
465
466 $users = array_map(
467 function( $user_id ) {
468 return new Author( $user_id );
469 },
470 get_users( array( 'fields' => 'ID' ) )
471 );
472
473 if ( is_multisite() && is_super_admin() ) {
474 $super_admins = array_map(
475 function( $login ) {
476 $user = get_user_by( 'login', $login );
477 return new Author( $user->ID );
478 },
479 get_super_admins()
480 );
481 $users = array_unique( array_merge( $users, $super_admins ) );
482 }
483
484 $users[] = new Author( 0, array( 'is_wp_cli' => true ) );
485
486 foreach ( $users as $user ) {
487 $all_records[ $user->id ] = $user->get_display_name();
488 }
489 } else {
490 $prefixed_column = sprintf( 'stream_%s', $column );
491 $all_records = $this->plugin->connectors->term_labels[ $prefixed_column ];
492 }
493
494 $existing_records = $this->plugin->db->existing_records( $column );
495 $active_records = array();
496 $disabled_records = array();
497
498 foreach ( $all_records as $record => $label ) {
499 if ( array_key_exists( $record, $existing_records ) ) {
500 $active_records[ $record ] = array( 'label' => $label, 'disabled' => '' );
501 } else {
502 $disabled_records[ $record ] = array( 'label' => $label, 'disabled' => 'disabled="disabled"' );
503 }
504 }
505
506 // Remove WP-CLI pseudo user if no records with user=0 exist
507 if ( isset( $disabled_records[0] ) ) {
508 unset( $disabled_records[0] );
509 }
510
511 $sort = function( $a, $b ) use ( $column ) {
512 $label_a = (string) $a['label'];
513 $label_b = (string) $b['label'];
514
515 if ( $label_a === $label_b ) {
516 return 0;
517 }
518
519 return ( strtolower( $label_a ) < strtolower( $label_b ) ) ? -1 : 1;
520 };
521
522 uasort( $active_records, $sort );
523 uasort( $disabled_records, $sort );
524
525 // Not using array_merge() in order to preserve the array index for the users dropdown which uses the user_id as the key
526 $all_records = $active_records + $disabled_records;
527
528 return $all_records;
529 }
530
531 public function get_filters() {
532 $filters = array();
533
534 $date_interval = new Date_Interval();
535
536 $filters['date'] = array(
537 'title' => __( 'dates', 'stream' ),
538 'items' => $date_interval->intervals,
539 );
540
541 $users = $this->get_users_dropdown_items(
542 $this->assemble_records( 'user_id' )
543 );
544
545 $filters['user_id'] = array(
546 'title' => __( 'users', 'stream' ),
547 'items' => $users,
548 'ajax' => count( $users ) <= 0,
549 );
550
551 $filters['context'] = array(
552 'title' => __( 'contexts', 'stream' ),
553 'items' => $this->assemble_records( 'context' ),
554 );
555
556 $filters['action'] = array(
557 'title' => __( 'actions', 'stream' ),
558 'items' => $this->assemble_records( 'action' ),
559 );
560
561 /**
562 * Filter allows additional filters in the list table dropdowns
563 * Note the format of the filters above, with they key and array
564 * containing a title and array of items.
565 *
566 * @return array
567 */
568 return apply_filters( 'wp_stream_list_table_filters', $filters );
569 }
570
571 function filters_form() {
572 $filters = $this->get_filters();
573
574 $filters_string = sprintf( '<input type="hidden" name="page" value="%s" />', 'wp_stream' );
575 $filters_string .= sprintf( '<span class="filter_info hidden">%s</span>', esc_html__( 'Show filter controls via the screen options tab above.', 'stream' ) );
576
577 foreach ( $filters as $name => $data ) {
578
579 $data = wp_parse_args( $data, array(
580 'title' => '',
581 'items' => array(),
582 'ajax' => false,
583 ) );
584
585 if ( 'date' === $name ) {
586 $filters_string .= $this->filter_date( $data['items'] );
587 } else {
588 if ( 'context' === $name ) {
589 // Add Connectors as parents, and apply the Contexts as children
590 $connectors = $this->assemble_records( 'connector' );
591 $context_items = array();
592
593 foreach ( $connectors as $connector => $item ) {
594 $context_items[ $connector ]['label'] = $item['label'];
595
596 foreach ( $data['items'] as $context_value => $context_item ) {
597 if ( isset( $this->plugin->connectors->contexts[ $connector ] ) && array_key_exists( $context_value, $this->plugin->connectors->contexts[ $connector ] ) ) {
598 $context_items[ $connector ]['children'][ $context_value ] = $context_item;
599 }
600 }
601
602 if ( isset( $context_items[ $connector ]['children'] ) ) {
603 $labels = wp_list_pluck( $context_items[ $connector ]['children'], 'label' );
604
605 // Sort child items by label
606 array_multisort( $labels, SORT_ASC, $context_items[ $connector ]['children'] );
607 }
608 }
609
610 foreach ( $context_items as $context_value => $context_item ) {
611 if ( ! isset( $context_item['children'] ) || empty( $context_item['children'] ) ) {
612 unset( $context_items[ $context_value ] );
613 }
614 }
615
616 $data['items'] = $context_items;
617
618 $labels = wp_list_pluck( $data['items'], 'label' );
619
620 // Sort top-level items by label
621 array_multisort( $labels, SORT_ASC, $data['items'] );
622
623 // Output a hidden input to handle the connector value
624 $filters_string .= sprintf(
625 '<input type="hidden" name="connector" class="record-filter-connector" value="%s" />',
626 esc_attr( wp_stream_filter_input( INPUT_GET, 'connector' ) )
627 );
628 }
629
630 $filters_string .= $this->filter_select( $name, $data['title'], $data['items'], $data['ajax'] );
631 }
632 }
633
634 $filters_string .= sprintf( '<input type="submit" id="record-query-submit" class="button" value="%s" />', __( 'Filter', 'stream' ) );
635
636 // Parse all query vars into an array
637 $query_vars = array();
638
639 if ( isset( $_SERVER['QUERY_STRING'] ) ) {
640 parse_str( urldecode( $_SERVER['QUERY_STRING'] ), $query_vars );
641 }
642
643 // Ignore certain query vars and query vars that are empty
644 foreach ( $query_vars as $query_var => $value ) {
645 if ( '' === $value || 'page' === $query_var || 'paged' === $query_var ) {
646 unset( $query_vars[ $query_var ] );
647 }
648 }
649
650 $url = add_query_arg(
651 array(
652 'page' => $this->plugin->admin->records_page_slug,
653 ),
654 self_admin_url( $this->plugin->admin->admin_parent_page )
655 );
656
657 // Display reset action if records are being filtered
658 if ( ! empty( $query_vars ) ) {
659 $filters_string .= sprintf( '<a href="%s" id="record-query-reset"><span class="dashicons dashicons-dismiss"></span> <span class="record-query-reset-text">%s</span></a>', esc_url( $url ), __( 'Reset filters', 'stream' ) );
660 }
661
662 return sprintf( '<div class="alignleft actions">%s</div>', $filters_string ); // xss ok
663 }
664
665 function filter_select( $name, $title, $items, $ajax = false ) {
666 if ( $ajax ) {
667 $out = sprintf(
668 '<input type="hidden" name="%s" class="chosen-select" value="%s" data-placeholder="%s" />',
669 esc_attr( $name ),
670 esc_attr( wp_stream_filter_input( INPUT_GET, $name ) ),
671 esc_attr( $title )
672 );
673 } else {
674 $options = array( '<option value=""></option>' );
675 $selected = wp_stream_filter_input( INPUT_GET, $name );
676
677 foreach ( $items as $key => $item ) {
678 $value = isset( $item['children'] ) ? 'group-' . $key : $key;
679 $option_args = array(
680 'value' => $value,
681 'selected' => selected( $value, $selected, false ),
682 'disabled' => isset( $item['disabled'] ) ? $item['disabled'] : null,
683 'icon' => isset( $item['icon'] ) ? $item['icon'] : null,
684 'group' => isset( $item['children'] ) ? $key : null,
685 'tooltip' => isset( $item['tooltip'] ) ? $item['tooltip'] : null,
686 'class' => isset( $item['children'] ) ? 'level-1' : null,
687 'label' => isset( $item['label'] ) ? $item['label'] : null,
688 );
689 $options[] = $this->filter_option( $option_args );
690
691 if ( isset( $item['children'] ) ) {
692 foreach ( $item['children'] as $child_value => $child_item ) {
693 $option_args = array(
694 'value' => $child_value,
695 'selected' => selected( $child_value, $selected, false ),
696 'disabled' => isset( $child_item['disabled'] ) ? $child_item['disabled'] : null,
697 'icon' => isset( $child_item['icon'] ) ? $child_item['icon'] : null,
698 'group' => $key,
699 'tooltip' => isset( $child_item['tooltip'] ) ? $child_item['tooltip'] : null,
700 'class' => 'level-2',
701 'label' => isset( $child_item['label'] ) ? '- ' . $child_item['label'] : null,
702 );
703 $options[] = $this->filter_option( $option_args );
704 }
705 }
706 }
707 $out = sprintf(
708 '<select name="%s" class="chosen-select" data-placeholder="%s">%s</select>',
709 esc_attr( $name ),
710 sprintf( esc_attr__( 'Show all %s', 'stream' ), $title ),
711 implode( '', $options )
712 );
713 }
714
715 return $out;
716 }
717
718 function filter_option( $args ) {
719 $defaults = array(
720 'value' => null,
721 'selected' => null,
722 'disabled' => null,
723 'icon' => null,
724 'group' => null,
725 'tooltip' => null,
726 'class' => null,
727 'label' => null,
728 );
729 wp_parse_args( $args, $defaults );
730
731 return sprintf(
732 '<option value="%s" %s %s %s %s %s class="%s">%s</option>',
733 esc_attr( $args['value'] ),
734 $args['selected'],
735 $args['disabled'],
736 $args['icon'] ? sprintf( 'data-icon="%s"', esc_attr( $args['icon'] ) ) : null,
737 $args['group'] ? sprintf( 'data-group="%s"', esc_attr( $args['group'] ) ) : null,
738 $args['tooltip'] ? sprintf( 'title="%s"', esc_attr( $args['tooltip'] ) ) : null,
739 $args['class'] ? esc_attr( $args['class'] ) : null,
740 esc_html( $args['label'] )
741 );
742 }
743
744 function filter_search() {
745 $search = null;
746 if ( isset( $_GET['search'] ) ) {
747 // @TODO: Make this pass phpcs
748 $search = esc_attr( wp_unslash( $_GET['search'] ) ); // input var okay
749 }
750 $out = sprintf(
751 '<p class="search-box">
752 <label class="screen-reader-text" for="record-search-input">%1$s:</label>
753 <input type="search" id="record-search-input" name="search" value="%2$s" />
754 <input type="submit" name="" id="search-submit" class="button" value="%1$s" />
755 </p>',
756 esc_attr__( 'Search Records', 'stream' ),
757 $search
758 );
759
760 return $out;
761 }
762
763 function filter_date( $items ) {
764 wp_enqueue_style( 'jquery-ui' );
765 wp_enqueue_style( 'wp-stream-datepicker' );
766 wp_enqueue_script( 'jquery-ui-datepicker' );
767
768 $date_predefined = wp_stream_filter_input( INPUT_GET, 'date_predefined' );
769 $date_from = wp_stream_filter_input( INPUT_GET, 'date_from' );
770 $date_to = wp_stream_filter_input( INPUT_GET, 'date_to' );
771
772 ob_start();
773 ?>
774 <div class="date-interval">
775
776 <select class="field-predefined hide-if-no-js" name="date_predefined" data-placeholder="<?php esc_attr_e( 'All Time', 'stream' ) ?>">
777 <option></option>
778 <option value="custom" <?php selected( 'custom' === $date_predefined ); ?>><?php esc_attr_e( 'Custom', 'stream' ) ?></option>
779 <?php
780 foreach ( $items as $key => $interval ) {
781 $end = isset( $interval['end'] ) ? $interval['end']->format( 'Y/m/d' ) : null;
782
783 printf(
784 '<option value="%s" data-from="%s" data-to="%s" %s>%s</option>',
785 esc_attr( $key ),
786 esc_attr( $interval['start']->format( 'Y/m/d' ) ),
787 esc_attr( $end ),
788 selected( $key === $date_predefined ),
789 esc_html( $interval['label'] )
790 );
791 }
792 ?>
793 </select>
794
795 <div class="date-inputs">
796 <div class="box">
797 <i class="date-remove dashicons"></i>
798 <input type="text" name="date_from" class="date-picker field-from" placeholder="<?php esc_attr_e( 'Start Date', 'stream' ) ?>" value="<?php echo esc_attr( $date_from ) ?>" />
799 </div>
800 <span class="connector dashicons"></span>
801
802 <div class="box">
803 <i class="date-remove dashicons"></i>
804 <input type="text" name="date_to" class="date-picker field-to" placeholder="<?php esc_attr_e( 'End Date', 'stream' ) ?>" value="<?php echo esc_attr( $date_to ) ?>" />
805 </div>
806 </div>
807
808 </div>
809 <?php
810
811 return ob_get_clean();
812 }
813
814 /**
815 * Output a Select dropdown of actions relating to the Stream records
816 *
817 * @return string
818 */
819 function record_actions_form() {
820 /**
821 * Filter the records screen actions dropdown menu
822 *
823 * @return array Should be in the format of action_slug => 'Action Name'
824 */
825 $actions = apply_filters( 'wp_stream_record_actions_menu', array() );
826
827 if ( empty( $actions ) ) {
828 return '';
829 }
830
831 ob_start();
832 printf( '<div class="alignleft actions recordactions"><select name="%s">', esc_attr( 'record-actions' ) );
833 printf( '<option value="">%s</option>', esc_attr__( 'Record Actions', 'stream' ) );
834 foreach ( $actions as $value => $name ) {
835 printf(
836 '<option value="%s">%s</option>',
837 esc_attr( $value ),
838 esc_attr( $name )
839 );
840 }
841 echo '</select></div>';
842 wp_nonce_field( 'stream_record_actions_nonce', 'stream_record_actions_nonce' );
843
844 printf( '<input type="hidden" name="page" value="%s">', esc_attr( wp_stream_filter_input( INPUT_GET, 'page' ) ) );
845 printf( '<input type="hidden" name="date_predefined" value="%s">', esc_attr( wp_stream_filter_input( INPUT_GET, 'date_predefined' ) ) );
846 printf( '<input type="hidden" name="date_from" value="%s">', esc_attr( wp_stream_filter_input( INPUT_GET, 'date_from' ) ) );
847 printf( '<input type="hidden" name="date_to" value="%s">', esc_attr( wp_stream_filter_input( INPUT_GET, 'date_to' ) ) );
848 printf( '<input type="hidden" name="user_id" value="%s">', esc_attr( wp_stream_filter_input( INPUT_GET, 'user_id' ) ) );
849 printf( '<input type="hidden" name="connector" value="%s">', esc_attr( wp_stream_filter_input( INPUT_GET, 'connector' ) ) );
850 printf( '<input type="hidden" name="context" value="%s">', esc_attr( wp_stream_filter_input( INPUT_GET, 'context' ) ) );
851 printf( '<input type="hidden" name="action" value="%s">', esc_attr( wp_stream_filter_input( INPUT_GET, 'action' ) ) );
852
853 printf( '<input type="submit" name="" id="record-actions-submit" class="button" value="%s">', esc_attr__( 'Apply', 'stream' ) );
854 echo '<div class="clear"></div>';
855
856 return ob_get_clean();
857 }
858
859 function display() {
860 $url = self_admin_url( $this->plugin->admin->admin_parent_page );
861
862 echo '<form method="get" action="' . esc_url( $url ) . '" id="record-filter-form">';
863 echo $this->filter_search(); // xss ok
864 parent::display();
865 echo '</form>';
866
867 echo '<form method="get" action="' . esc_url( $url ) . '" id="record-actions-form">';
868 echo $this->record_actions_form(); // xss ok
869 echo '</form>';
870 }
871
872 function display_tablenav( $which ) {
873 if ( 'top' === $which ) : ?>
874 <div class="tablenav <?php echo esc_attr( $which ); ?>">
875 <?php
876 $this->pagination( $which );
877 $this->extra_tablenav( $which );
878 ?>
879
880 <br class="clear" />
881 </div>
882 <?php else : ?>
883 <div class="tablenav <?php echo esc_attr( $which ); ?>">
884 <?php
885 /**
886 * Fires after the list table is displayed.
887 */
888 do_action( 'wp_stream_after_list_table' );
889 $this->pagination( $which );
890 $this->extra_tablenav( $which );
891 ?>
892
893 <br class="clear" />
894 </div>
895 <?php
896 endif;
897 }
898
899 function set_screen_option( $dummy, $option, $value ) {
900 if ( 'edit_stream_per_page' === $option ) {
901 return $value;
902 } else {
903 return $dummy;
904 }
905 }
906
907 function set_live_update_option( $dummy, $option, $value ) {
908 unset( $value );
909
910 // @codingStandardsIgnoreStart
911 if (
912 $this->plugin->admin->live_update->user_meta_key === $option
913 &&
914 isset( $_POST[ $this->plugin->admin->live_update->user_meta_key ] )
915 ) {
916 $value = esc_attr( $_POST[ $this->plugin->admin->live_update->user_meta_key ] ); //input var okay
917
918 return $value;
919 }
920 // @codingStandardsIgnoreEnd
921
922 return $dummy;
923 }
924
925 public function screen_controls( $status, $args ) {
926 unset( $status );
927 unset( $args );
928
929 $user_id = get_current_user_id();
930 $option = $this->plugin->admin->get_user_meta( $user_id, $this->plugin->admin->live_update->user_meta_key, true );
931 $heartbeat = wp_script_is( 'heartbeat', 'done' ) ? 'true' : 'false';
932
933 if ( 'on' === $option && 'false' === $heartbeat ) {
934 $option = 'off';
935
936 $this->plugin->admin->update_user_meta( $user_id, $this->plugin->admin->live_update->user_meta_key, 'off' );
937 }
938
939 $nonce = wp_create_nonce( $this->plugin->admin->live_update->user_meta_key . '_nonce' );
940
941 ob_start();
942 ?>
943 <fieldset>
944 <h5><?php esc_html_e( 'Live updates', 'stream' ) ?></h5>
945
946 <div>
947 <input type="hidden" name="stream_live_update_nonce" id="stream_live_update_nonce" value="<?php echo esc_attr( $nonce ) ?>" />
948 </div>
949 <div>
950 <input type="hidden" name="enable_live_update_user" id="enable_live_update_user" value="<?php echo absint( $user_id ) ?>" />
951 </div>
952 <div class="metabox-prefs stream-live-update-checkbox">
953 <label for="enable_live_update">
954 <input type="checkbox" value="on" name="enable_live_update" id="enable_live_update" data-heartbeat="<?php echo esc_attr( $heartbeat ) ?>" <?php checked( $option, 'on' ) ?> />
955 <?php esc_html_e( 'Enabled', 'stream' ) ?><span class="spinner"></span>
956 </label>
957 </div>
958 </fieldset>
959 <?php
960 return ob_get_clean();
961 }
962
963 /**
964 * This function is use to map List table column name with excluded setting keys
965 *
966 * @param string $column List table column name
967 *
968 * @return string setting name for that column
969 */
970 function get_column_excluded_setting_key( $column ) {
971 switch ( $column ) {
972 case 'connector':
973 $output = 'connectors';
974 break;
975 case 'context':
976 $output = 'contexts';
977 break;
978 case 'action':
979 $output = 'action';
980 break;
981 case 'ip':
982 $output = 'ip_addresses';
983 break;
984 case 'user_id':
985 $output = 'users';
986 break;
987 default:
988 $output = false;
989 }
990
991 return $output;
992 }
993
994 /**
995 * Get users as dropdown items
996 *
997 * @param array $users
998 *
999 * @return array
1000 */
1001 public function get_users_dropdown_items( $users ) {
1002 $record_meta = array();
1003
1004 foreach ( $users as $user_id => $args ) {
1005 $user = new Author( $user_id );
1006 $disabled = isset( $args['disabled'] ) ? $args['disabled'] : null;
1007
1008 $record_meta[ $user_id ] = array(
1009 'text' => $user->get_display_name(),
1010 'id' => $user_id,
1011 'label' => $user->get_display_name(),
1012 'icon' => $user->get_avatar_src( 32 ),
1013 'title' => '',
1014 'disabled' => $disabled,
1015 );
1016 }
1017
1018 return $record_meta;
1019 }
1020 }
1021