PluginProbe
Stream – Activity Log & Audit Trail / 3.0.6
Stream – Activity Log & Audit Trail v3.0.6
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.6, at classes/class-list-table.php

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