PluginProbe
Stream – Activity Log & Audit Trail / 3.4.2
Stream – Activity Log & Audit Trail v3.4.2
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
← All changes | classes/class-list-table.php +247 -89 3.0.13.4.2 View file →
@@ -1,10 +1,13 @@
1 1 <?php
2 +
2 3 namespace WP_Stream;
3 4
4 5 class List_Table extends \WP_List_Table {
6 +
5 7 /**
6 8 * Hold Plugin class
9 + *
7 10 * @var Plugin
8 11 */
9 12 public $plugin;
10 13
@@ -11,11 +14,11 @@
11 14 /**
12 15 * Class constructor.
13 16 *
14 17 * @param Plugin $plugin The main Plugin class.
15 - * @param array $args
18 + * @param array $args
16 19 */
17 - function __construct( $plugin, $args = array() ) {
20 + public function __construct( $plugin, $args = array() ) {
18 21 $this->plugin = $plugin;
19 22
20 23 $screen_id = isset( $args['screen'] ) ? $args['screen'] : null;
21 24
@@ -45,29 +48,45 @@
45 48
46 49 // Check for default hidden columns
47 50 $this->get_hidden_columns();
48 51
49 - add_filter( 'screen_settings', array( $this, 'screen_controls' ), 10, 2 );
50 - add_filter( 'set-screen-option', array( $this, 'set_screen_option' ), 10, 3 );
52 + add_filter(
53 + 'screen_settings',
54 + array(
55 + $this,
56 + 'screen_controls',
57 + ),
58 + 10,
59 + 2
60 + );
61 + add_filter(
62 + 'set-screen-option',
63 + array(
64 + $this,
65 + 'set_screen_option',
66 + ),
67 + 10,
68 + 3
69 + );
51 70
52 71 set_screen_options();
53 72 }
54 73
55 - function extra_tablenav( $which ) {
74 + public function extra_tablenav( $which ) {
56 75 if ( 'top' === $which ) {
57 - echo $this->filters_form(); //xss ok
76 + echo $this->filters_form(); // xss ok
58 77 }
59 78 }
60 79
61 - function no_items() {
80 + public function no_items() {
62 81 ?>
63 82 <div class="stream-list-table-no-items">
64 - <p><?php esc_html_e( 'Sorry, no activity records were found.', 'stream' ) ?></p>
83 + <p><?php esc_html_e( 'Sorry, no activity records were found.', 'stream' ); ?></p>
65 84 </div>
66 85 <?php
67 86 }
68 87
69 - function get_columns() {
88 + public function get_columns() {
70 89 /**
71 90 * Allows devs to add new columns to table
72 91 *
73 92 * @return array
@@ -84,16 +103,17 @@
84 103 )
85 104 );
86 105 }
87 106
88 - function get_sortable_columns() {
107 + public function get_sortable_columns() {
89 108 return array(
90 109 'date' => array( 'date', false ),
91 110 );
92 111 }
93 112
94 - function get_hidden_columns() {
95 - if ( ! $user = wp_get_current_user() ) {
113 + public function get_hidden_columns() {
114 + $user = wp_get_current_user();
115 + if ( ! $user ) {
96 116 return array();
97 117 }
98 118
99 119 // Directly checking the user meta; to check whether user has changed screen option or not
@@ -107,15 +127,20 @@
107 127
108 128 return $hidden;
109 129 }
110 130
111 - function prepare_items() {
131 + public function prepare_items() {
112 132 $columns = $this->get_columns();
113 133 $sortable = $this->get_sortable_columns();
114 134 $hidden = $this->get_hidden_columns();
115 135 $primary = $columns['summary'];
116 136
117 - $this->_column_headers = array( $columns, $hidden, $sortable, $primary );
137 + $this->_column_headers = array(
138 + $columns,
139 + $hidden,
140 + $sortable,
141 + $primary,
142 + );
118 143
119 144 $this->items = $this->get_records();
120 145
121 146 $total_items = $this->get_total_found_rows();
@@ -127,17 +152,19 @@
127 152 )
128 153 );
129 154 }
130 155
131 - function get_records() {
156 + public function get_records() {
132 157 $args = array();
133 158
134 159 // Parse sorting params
135 - if ( $order = wp_stream_filter_input( INPUT_GET, 'order' ) ) {
160 + $order = wp_stream_filter_input( INPUT_GET, 'order' );
161 + if ( $order ) {
136 162 $args['order'] = $order;
137 163 }
138 164
139 - if ( $orderby = wp_stream_filter_input( INPUT_GET, 'orderby' ) ) {
165 + $orderby = wp_stream_filter_input( INPUT_GET, 'orderby' );
166 + if ( $orderby ) {
140 167 $args['orderby'] = $orderby;
141 168 }
142 169
143 170 $params = array(
@@ -202,10 +229,11 @@
202 229
203 230 if ( ! isset( $args['records_per_page'] ) ) {
204 231 $args['records_per_page'] = $this->get_items_per_page( 'edit_stream_per_page', 20 );
205 232 }
233 + $args['records_per_page'] = apply_filters( 'stream_records_per_page', $args['records_per_page'] );
206 234
207 - $items = $this->plugin->db->query->query( $args );
235 + $items = $this->plugin->db->get_records( $args );
208 236
209 237 return $items;
210 238 }
211 239
@@ -214,17 +242,17 @@
214 242 *
215 243 * @return integer
216 244 */
217 245 public function get_total_found_rows() {
218 - return $this->plugin->db->query->found_records;
246 + return $this->plugin->db->get_found_records_count();
219 247 }
220 248
221 - function column_default( $item, $column_name ) {
222 - $out = '';
249 + public function column_default( $item, $column_name ) {
250 + $out = '';
223 251 $record = new Record( $item );
224 252
225 253 switch ( $column_name ) {
226 - case 'date' :
254 + case 'date':
227 255 $created = date( 'Y-m-d H:i:s', strtotime( $record->created ) );
228 256 $date_string = sprintf(
229 257 '<time datetime="%s" class="relative-time record-created">%s</time>',
230 258 wp_stream_get_iso_8601_extended_date( strtotime( $record->created ) ),
@@ -229,16 +257,17 @@
229 257 '<time datetime="%s" class="relative-time record-created">%s</time>',
230 258 wp_stream_get_iso_8601_extended_date( strtotime( $record->created ) ),
231 259 get_date_from_gmt( $created, 'Y/m/d' )
232 260 );
233 - $out = $this->column_link( $date_string, 'date', get_date_from_gmt( $created, 'Y/m/d' ) );
234 - $out .= '<br />';
235 - $out .= get_date_from_gmt( $created, 'h:i:s A' );
261 + $out = $this->column_link( $date_string, 'date', get_date_from_gmt( $created, 'Y/m/d' ) );
262 + $out .= '<br />';
263 + $out .= get_date_from_gmt( $created, 'h:i:s A' );
236 264 break;
237 265
238 - case 'summary' :
239 - $out = $record->summary;
240 - $object_title = $record->get_object_title();
266 + case 'summary':
267 + $out = $record->summary;
268 + $object_title = $record->get_object_title();
269 + // translators: Placeholder refers to the title of any object, like a Post (e.g. "Hello World")
241 270 $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' );
242 271
243 272 if ( $record->object_id ) {
244 273 $out .= $this->column_link(
@@ -253,19 +282,27 @@
253 282 }
254 283 $out .= $this->get_action_links( $record );
255 284 break;
256 285
257 - case 'user_id' :
258 - $user = new Author( (int) $record->user_id, (array) maybe_unserialize( $record->user_meta ) );
286 + case 'user_id':
287 + $user = new Author( (int) $record->user_id, (array) $record->user_meta );
259 288
289 + $filtered_records_url = add_query_arg(
290 + array(
291 + 'page' => $this->plugin->admin->records_page_slug,
292 + 'user_id' => absint( $user->id ),
293 + ),
294 + self_admin_url( $this->plugin->admin->admin_parent_page )
295 + );
296 +
260 297 $out = sprintf(
261 298 '<a href="%s">%s <span>%s</span></a>%s%s%s',
262 - $user->get_records_page_url(),
299 + $filtered_records_url,
263 300 $user->get_avatar_img( 80 ),
264 301 $user->get_display_name(),
265 302 $user->is_deleted() ? sprintf( '<br /><small class="deleted">%s</small>', esc_html__( 'Deleted User', 'stream' ) ) : '',
266 - $user->get_role() ? sprintf( '<br /><small>%s</small>', $user->get_role() ) : '',
267 - $user->get_agent() ? sprintf( '<br /><small>%s</small>', $user->get_agent_label( $user->get_agent() ) ) : ''
303 + sprintf( '<br /><small>%s</small>', $user->get_role() ),
304 + sprintf( '<br /><small>%s</small>', $user->get_agent_label( $user->get_agent() ) )
268 305 );
269 306 break;
270 307
271 308 case 'context':
@@ -291,20 +328,21 @@
291 328 $blog = ( $record->blog_id && is_multisite() ) ? get_blog_details( $record->blog_id ) : $this->plugin->admin->network->get_network_blog();
292 329 $out = $this->column_link( $blog->blogname, 'blog_id', $blog->blog_id );
293 330 break;
294 331
295 - case 'ip' :
332 + case 'ip':
296 333 $out = $this->column_link( $record->{$column_name}, 'ip', $record->{$column_name} );
297 334 break;
298 335
299 - default :
336 + default:
300 337 /**
301 - * Registers new Columns to be inserted into the table. The cell contents of this column is set
302 - * below with 'wp_stream_inster_column_default-'
338 + * Registers new Columns to be inserted into the table. The cell contents of this column is set
339 + * below with 'wp_stream_insert_column_default_'
303 340 *
304 341 * @return array
305 342 */
306 - $inserted_columns = apply_filters( 'wp_stream_register_column_defaults', $new_columns = array() );
343 + $new_columns = array();
344 + $inserted_columns = apply_filters( 'wp_stream_register_column_defaults', $new_columns );
307 345
308 346 if ( ! empty( $inserted_columns ) && is_array( $inserted_columns ) ) {
309 347 foreach ( $inserted_columns as $column_title ) {
310 348 /**
@@ -314,17 +352,17 @@
314 352 *
315 353 * Also, note that the action name must include the $column_title registered
316 354 * with wp_stream_register_column_defaults
317 355 */
318 - if ( $column_title === $column_name && has_filter( "wp_stream_insert_column_default-{$column_title}" ) ) {
356 + if ( $column_title === $column_name && has_filter( "wp_stream_insert_column_default_{$column_title}" ) ) {
319 357 /**
320 358 * Allows for the addition of content under a specified column.
321 359 *
322 - * @param object $record Contents of the row
360 + * @param object $record Contents of the row
323 361 *
324 362 * @return string
325 363 */
326 - $out = apply_filters( "wp_stream_insert_column_default-{$column_title}", $column_name, $record );
364 + $out = apply_filters( "wp_stream_insert_column_default_{$column_title}", $column_name, $record );
327 365 } else {
328 366 $out = $column_name;
329 367 }
330 368 }
@@ -332,9 +370,16 @@
332 370 $out = $column_name;
333 371 }
334 372 }
335 373
336 - echo $out; // xss ok
374 + $allowed_tags = wp_kses_allowed_html( 'post' );
375 + $allowed_tags['time'] = array(
376 + 'datetime' => true,
377 + 'class' => true,
378 + );
379 + $allowed_tags['img']['srcset'] = true;
380 +
381 + echo wp_kses( $out, $allowed_tags );
337 382 }
338 383
339 384 public function get_action_links( $record ) {
340 385 $out = '';
@@ -388,9 +433,9 @@
388 433
389 434 return $out;
390 435 }
391 436
392 - function column_link( $display, $key, $value = null, $title = null ) {
437 + public function column_link( $display, $key, $value = null, $title = null ) {
393 438 $url = add_query_arg(
394 439 array(
395 440 'page' => $this->plugin->admin->records_page_slug,
396 441 ),
@@ -396,9 +441,11 @@
396 441 ),
397 442 self_admin_url( $this->plugin->admin->admin_parent_page )
398 443 );
399 444
400 - $args = ! is_array( $key ) ? array( $key => $value ) : $key;
445 + $args = ! is_array( $key ) ? array(
446 + $key => $value,
447 + ) : $key;
401 448
402 449 foreach ( $args as $k => $v ) {
403 450 $url = add_query_arg( $k, $v, $url );
404 451 }
@@ -411,13 +458,13 @@
411 458 );
412 459 }
413 460
414 461 public function get_term_title( $term, $type ) {
415 - if ( ! isset( $this->plugin->connectors->term_labels[ "stream_$type" ][ $term ] ) ) {
462 + if ( ! isset( $this->plugin->connectors->term_labels[ 'stream_' . $type ][ $term ] ) ) {
416 463 return $term;
417 464 }
418 465
419 - return $this->plugin->connectors->term_labels[ "stream_$type" ][ $term ];
466 + return $this->plugin->connectors->term_labels[ 'stream_' . $type ][ $term ];
420 467 }
421 468
422 469 /**
423 470 * Assembles records for display in search filters
@@ -429,9 +476,9 @@
429 476 * @param string $column List table column name
430 477 *
431 478 * @return array Options to be displayed in search filters
432 479 */
433 - function assemble_records( $column ) {
480 + public function assemble_records( $column ) {
434 481 // @todo eliminate special condition for authors, especially using a WP_User object as the value; should use string or stringifiable object
435 482 if ( 'user_id' === $column ) {
436 483 $all_records = array();
437 484
@@ -439,20 +486,50 @@
439 486 $user_count = count_users();
440 487 $total_users = $user_count['total_users'];
441 488
442 489 if ( $total_users > $this->plugin->admin->preload_users_max ) {
443 - return array();
490 + $selected_user = wp_stream_filter_input( INPUT_GET, 'user_id' );
491 + if ( $selected_user ) {
492 + $user = new Author( $selected_user );
493 +
494 + return array(
495 + $selected_user => $user->get_display_name(),
496 + );
497 + } else {
498 + return array();
499 + }
444 500 }
445 501
446 502 $users = array_map(
447 - function( $user_id ) {
503 + function ( $user_id ) {
448 504 return new Author( $user_id );
449 505 },
450 - get_users( array( 'fields' => 'ID' ) )
506 + get_users(
507 + array(
508 + 'fields' => 'ID',
509 + )
510 + )
451 511 );
452 512
453 - $users[] = new Author( 0, array( 'is_wp_cli' => true ) );
513 + if ( is_multisite() && is_super_admin() ) {
514 + $super_admins = array_map(
515 + function ( $login ) {
516 + $user = get_user_by( 'login', $login );
454 517
518 + return new Author( $user->ID );
519 + },
520 + get_super_admins()
521 + );
522 + $users = array_unique( array_merge( $users, $super_admins ) );
523 + }
524 +
525 + $users[] = new Author(
526 + 0,
527 + array(
528 + 'is_wp_cli' => true,
529 + )
530 + );
531 +
455 532 foreach ( $users as $user ) {
456 533 $all_records[ $user->id ] = $user->get_display_name();
457 534 }
458 535 } else {
@@ -465,11 +542,17 @@
465 542 $disabled_records = array();
466 543
467 544 foreach ( $all_records as $record => $label ) {
468 545 if ( array_key_exists( $record, $existing_records ) ) {
469 - $active_records[ $record ] = array( 'label' => $label, 'disabled' => '' );
546 + $active_records[ $record ] = array(
547 + 'label' => $label,
548 + 'disabled' => '',
549 + );
470 550 } else {
471 - $disabled_records[ $record ] = array( 'label' => $label, 'disabled' => 'disabled="disabled"' );
551 + $disabled_records[ $record ] = array(
552 + 'label' => $label,
553 + 'disabled' => 'disabled="disabled"',
554 + );
472 555 }
473 556 }
474 557
475 558 // Remove WP-CLI pseudo user if no records with user=0 exist
@@ -476,9 +559,9 @@
476 559 if ( isset( $disabled_records[0] ) ) {
477 560 unset( $disabled_records[0] );
478 561 }
479 562
480 - $sort = function( $a, $b ) use ( $column ) {
563 + $sort = function ( $a, $b ) use ( $column ) {
481 564 $label_a = (string) $a['label'];
482 565 $label_b = (string) $b['label'];
483 566
484 567 if ( $label_a === $label_b ) {
@@ -484,9 +567,9 @@
484 567 if ( $label_a === $label_b ) {
485 568 return 0;
486 569 }
487 570
488 - return ( strtolower( $label_a ) < strtolower( $label_b ) ) ? -1 : 1;
571 + return ( strtolower( $label_a ) < strtolower( $label_b ) ) ? - 1 : 1;
489 572 };
490 573
491 574 uasort( $active_records, $sort );
492 575 uasort( $disabled_records, $sort );
@@ -536,10 +619,9 @@
536 619 */
537 620 return apply_filters( 'wp_stream_list_table_filters', $filters );
538 621 }
539 622
540 - function filters_form() {
541 - $user_id = get_current_user_id();
623 + public function filters_form() {
542 624 $filters = $this->get_filters();
543 625
544 626 $filters_string = sprintf( '<input type="hidden" name="page" value="%s" />', 'wp_stream' );
545 627 $filters_string .= sprintf( '<span class="filter_info hidden">%s</span>', esc_html__( 'Show filter controls via the screen options tab above.', 'stream' ) );
@@ -544,8 +626,18 @@
544 626 $filters_string = sprintf( '<input type="hidden" name="page" value="%s" />', 'wp_stream' );
545 627 $filters_string .= sprintf( '<span class="filter_info hidden">%s</span>', esc_html__( 'Show filter controls via the screen options tab above.', 'stream' ) );
546 628
547 629 foreach ( $filters as $name => $data ) {
630 +
631 + $data = wp_parse_args(
632 + $data,
633 + array(
634 + 'title' => '',
635 + 'items' => array(),
636 + 'ajax' => false,
637 + )
638 + );
639 +
548 640 if ( 'date' === $name ) {
549 641 $filters_string .= $this->filter_date( $data['items'] );
550 642 } else {
551 643 if ( 'context' === $name ) {
@@ -582,13 +674,16 @@
582 674
583 675 // Sort top-level items by label
584 676 array_multisort( $labels, SORT_ASC, $data['items'] );
585 677
586 - // Ouput a hidden input to handle the connector value
587 - $filters_string .= '<input type="hidden" name="connector" class="record-filter-connector" />';
678 + // Output a hidden input to handle the connector value
679 + $filters_string .= sprintf(
680 + '<input type="hidden" name="connector" class="record-filter-connector" value="%s" />',
681 + esc_attr( wp_stream_filter_input( INPUT_GET, 'connector' ) )
682 + );
588 683 }
589 684
590 - $filters_string .= $this->filter_select( $name, $data['title'], $data['items'] );
685 + $filters_string .= $this->filter_select( $name, $data['title'], $data['items'], $data['ajax'] );
591 686 }
592 687 }
593 688
594 689 $filters_string .= sprintf( '<input type="submit" id="record-query-submit" class="button" value="%s" />', __( 'Filter', 'stream' ) );
@@ -621,9 +716,9 @@
621 716
622 717 return sprintf( '<div class="alignleft actions">%s</div>', $filters_string ); // xss ok
623 718 }
624 719
625 - function filter_select( $name, $title, $items, $ajax = false ) {
720 + public function filter_select( $name, $title, $items, $ajax = false ) {
626 721 if ( $ajax ) {
627 722 $out = sprintf(
628 723 '<input type="hidden" name="%s" class="chosen-select" value="%s" data-placeholder="%s" />',
629 724 esc_attr( $name ),
@@ -645,13 +740,13 @@
645 740 'tooltip' => isset( $item['tooltip'] ) ? $item['tooltip'] : null,
646 741 'class' => isset( $item['children'] ) ? 'level-1' : null,
647 742 'label' => isset( $item['label'] ) ? $item['label'] : null,
648 743 );
649 - $options[] = $this->filter_option( $option_args );
744 + $options[] = $this->filter_option( $option_args );
650 745
651 746 if ( isset( $item['children'] ) ) {
652 747 foreach ( $item['children'] as $child_value => $child_item ) {
653 - $option_args = array(
748 + $option_args = array(
654 749 'value' => $child_value,
655 750 'selected' => selected( $child_value, $selected, false ),
656 751 'disabled' => isset( $child_item['disabled'] ) ? $child_item['disabled'] : null,
657 752 'icon' => isset( $child_item['icon'] ) ? $child_item['icon'] : null,
@@ -659,9 +754,9 @@
659 754 'tooltip' => isset( $child_item['tooltip'] ) ? $child_item['tooltip'] : null,
660 755 'class' => 'level-2',
661 756 'label' => isset( $child_item['label'] ) ? '- ' . $child_item['label'] : null,
662 757 );
663 - $options[] = $this->filter_option( $option_args );
758 + $options[] = $this->filter_option( $option_args );
664 759 }
665 760 }
666 761 }
667 762 $out = sprintf(
@@ -666,8 +761,9 @@
666 761 }
667 762 $out = sprintf(
668 763 '<select name="%s" class="chosen-select" data-placeholder="%s">%s</select>',
669 764 esc_attr( $name ),
765 + // translators: Placeholder refers to the title of the dropdown menu (e.g. "users")
670 766 sprintf( esc_attr__( 'Show all %s', 'stream' ), $title ),
671 767 implode( '', $options )
672 768 );
673 769 }
@@ -674,9 +770,9 @@
674 770
675 771 return $out;
676 772 }
677 773
678 - function filter_option( $args ) {
774 + public function filter_option( $args ) {
679 775 $defaults = array(
680 776 'value' => null,
681 777 'selected' => null,
682 778 'disabled' => null,
@@ -700,13 +796,12 @@
700 796 esc_html( $args['label'] )
701 797 );
702 798 }
703 799
704 - function filter_search() {
800 + public function filter_search() {
705 801 $search = null;
706 - if ( isset( $_GET['search'] ) ) {
707 - // @TODO: Make this pass phpcs
708 - $search = esc_attr( wp_unslash( $_GET['search'] ) ); // input var okay
802 + if ( isset( $_GET['search'] ) ) { // CSRF okay
803 + $search = esc_attr( wp_unslash( $_GET['search'] ) ); // input var okay, CSRF okay
709 804 }
710 805 $out = sprintf(
711 806 '<p class="search-box">
712 807 <label class="screen-reader-text" for="record-search-input">%1$s:</label>
@@ -719,9 +814,9 @@
719 814
720 815 return $out;
721 816 }
722 817
723 - function filter_date( $items ) {
818 + public function filter_date( $items ) {
724 819 wp_enqueue_style( 'jquery-ui' );
725 820 wp_enqueue_style( 'wp-stream-datepicker' );
726 821 wp_enqueue_script( 'jquery-ui-datepicker' );
727 822
@@ -732,11 +827,11 @@
732 827 ob_start();
733 828 ?>
734 829 <div class="date-interval">
735 830
736 - <select class="field-predefined hide-if-no-js" name="date_predefined" data-placeholder="<?php esc_attr_e( 'All Time', 'stream' ) ?>">
831 + <select class="field-predefined hide-if-no-js chosen-select" name="date_predefined" data-placeholder="<?php esc_attr_e( 'All Time', 'stream' ); ?>">
737 832 <option></option>
738 - <option value="custom" <?php selected( 'custom' === $date_predefined ); ?>><?php esc_attr_e( 'Custom', 'stream' ) ?></option>
833 + <option value="custom" <?php selected( 'custom' === $date_predefined ); ?>><?php esc_attr_e( 'Custom', 'stream' ); ?></option>
739 834 <?php
740 835 foreach ( $items as $key => $interval ) {
741 836 $end = isset( $interval['end'] ) ? $interval['end']->format( 'Y/m/d' ) : null;
742 837
@@ -754,15 +849,15 @@
754 849
755 850 <div class="date-inputs">
756 851 <div class="box">
757 852 <i class="date-remove dashicons"></i>
758 - <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 ) ?>" />
853 + <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 ); ?>"/>
759 854 </div>
760 855 <span class="connector dashicons"></span>
761 856
762 857 <div class="box">
763 858 <i class="date-remove dashicons"></i>
764 - <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 ) ?>" />
859 + <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 ); ?>"/>
765 860 </div>
766 861 </div>
767 862
768 863 </div>
@@ -770,20 +865,81 @@
770 865
771 866 return ob_get_clean();
772 867 }
773 868
774 - function display() {
869 + /**
870 + * Output a Select dropdown of actions relating to the Stream records
871 + *
872 + * @return string
873 + */
874 + public function record_actions_form() {
875 + /**
876 + * Filter the records screen actions dropdown menu
877 + *
878 + * @return array Should be in the format of action_slug => 'Action Name'
879 + */
880 + $actions = apply_filters( 'wp_stream_record_actions_menu', array() );
881 +
882 + if ( empty( $actions ) ) {
883 + return '';
884 + }
885 +
886 + ob_start();
887 + printf( '<div class="alignleft actions recordactions"><select name="%s">', esc_attr( 'record-actions' ) );
888 + printf( '<option value="">%s</option>', esc_attr__( 'Record Actions', 'stream' ) );
889 + foreach ( $actions as $value => $name ) {
890 + printf(
891 + '<option value="%s">%s</option>',
892 + esc_attr( $value ),
893 + esc_attr( $name )
894 + );
895 + }
896 + echo '</select></div>';
897 + wp_nonce_field( 'stream_record_actions_nonce', 'stream_record_actions_nonce' );
898 +
899 + printf( '<input type="hidden" name="page" value="%s">', esc_attr( wp_stream_filter_input( INPUT_GET, 'page' ) ) );
900 + printf( '<input type="hidden" name="date_predefined" value="%s">', esc_attr( wp_stream_filter_input( INPUT_GET, 'date_predefined' ) ) );
901 + printf( '<input type="hidden" name="date_from" value="%s">', esc_attr( wp_stream_filter_input( INPUT_GET, 'date_from' ) ) );
902 + printf( '<input type="hidden" name="date_to" value="%s">', esc_attr( wp_stream_filter_input( INPUT_GET, 'date_to' ) ) );
903 + printf( '<input type="hidden" name="user_id" value="%s">', esc_attr( wp_stream_filter_input( INPUT_GET, 'user_id' ) ) );
904 + printf( '<input type="hidden" name="connector" value="%s">', esc_attr( wp_stream_filter_input( INPUT_GET, 'connector' ) ) );
905 + printf( '<input type="hidden" name="context" value="%s">', esc_attr( wp_stream_filter_input( INPUT_GET, 'context' ) ) );
906 + printf( '<input type="hidden" name="action" value="%s">', esc_attr( wp_stream_filter_input( INPUT_GET, 'action' ) ) );
907 +
908 + printf( '<input type="submit" name="" id="record-actions-submit" class="button" value="%s">', esc_attr__( 'Apply', 'stream' ) );
909 + echo '<div class="clear"></div>';
910 +
911 + return ob_get_clean();
912 + }
913 +
914 + public function display() {
775 915 $url = self_admin_url( $this->plugin->admin->admin_parent_page );
776 916
777 917 echo '<form method="get" action="' . esc_url( $url ) . '" id="record-filter-form">';
778 918 echo $this->filter_search(); // xss ok
919 + parent::display();
920 + echo '</form>';
779 921
780 - parent::display();
922 + echo '<form method="get" action="' . esc_url( $url ) . '" id="record-actions-form">';
923 + echo $this->record_actions_form(); // xss ok
781 924 echo '</form>';
782 925 }
783 926
784 - function display_tablenav( $which ) {
785 - if ( 'top' === $which ) : ?>
927 + public function single_row( $item ) {
928 + $classes = apply_filters( 'wp_stream_record_classes', array(), $item );
929 + $class_string = '';
930 + if ( ! empty( $classes ) ) {
931 + $class_string = ' class="' . esc_attr( join( ' ', $classes ) ) . '"';
932 + }
933 +
934 + echo sprintf( '<tr%s>', $class_string ); // xss ok
935 + $this->single_row_columns( $item );
936 + echo '</tr>';
937 + }
938 +
939 + public function display_tablenav( $which ) {
940 + if ( 'top' === $which ) :
941 + ?>
786 942 <div class="tablenav <?php echo esc_attr( $which ); ?>">
787 943 <?php
788 944 $this->pagination( $which );
789 945 $this->extra_tablenav( $which );
@@ -788,9 +944,9 @@
788 944 $this->pagination( $which );
789 945 $this->extra_tablenav( $which );
790 946 ?>
791 947
792 - <br class="clear" />
948 + <br class="clear"/>
793 949 </div>
794 950 <?php else : ?>
795 951 <div class="tablenav <?php echo esc_attr( $which ); ?>">
796 952 <?php
@@ -801,15 +957,15 @@
801 957 $this->pagination( $which );
802 958 $this->extra_tablenav( $which );
803 959 ?>
804 960
805 - <br class="clear" />
961 + <br class="clear"/>
806 962 </div>
807 - <?php
963 + <?php
808 964 endif;
809 965 }
810 966
811 - function set_screen_option( $dummy, $option, $value ) {
967 + public function set_screen_option( $dummy, $option, $value ) {
812 968 if ( 'edit_stream_per_page' === $option ) {
813 969 return $value;
814 970 } else {
815 971 return $dummy;
@@ -815,9 +971,9 @@
815 971 return $dummy;
816 972 }
817 973 }
818 974
819 - function set_live_update_option( $dummy, $option, $value ) {
975 + public function set_live_update_option( $dummy, $option, $value ) {
820 976 unset( $value );
821 977
822 978 // @codingStandardsIgnoreStart
823 979 if (
@@ -828,8 +984,9 @@
828 984 $value = esc_attr( $_POST[ $this->plugin->admin->live_update->user_meta_key ] ); //input var okay
829 985
830 986 return $value;
831 987 }
988 +
832 989 // @codingStandardsIgnoreEnd
833 990
834 991 return $dummy;
835 992 }
@@ -852,20 +1009,21 @@
852 1009
853 1010 ob_start();
854 1011 ?>
855 1012 <fieldset>
856 - <h5><?php esc_html_e( 'Live updates', 'stream' ) ?></h5>
1013 + <h5><?php esc_html_e( 'Live updates', 'stream' ); ?></h5>
857 1014
858 1015 <div>
859 - <input type="hidden" name="stream_live_update_nonce" id="stream_live_update_nonce" value="<?php echo esc_attr( $nonce ) ?>" />
1016 + <input type="hidden" name="stream_live_update_nonce" id="stream_live_update_nonce" value="<?php echo esc_attr( $nonce ); ?>"/>
860 1017 </div>
861 1018 <div>
862 - <input type="hidden" name="enable_live_update_user" id="enable_live_update_user" value="<?php echo absint( $user_id ) ?>" />
1019 + <input type="hidden" name="enable_live_update_user" id="enable_live_update_user" value="<?php echo absint( $user_id ); ?>"/>
863 1020 </div>
864 1021 <div class="metabox-prefs stream-live-update-checkbox">
865 1022 <label for="enable_live_update">
866 - <input type="checkbox" value="on" name="enable_live_update" id="enable_live_update" data-heartbeat="<?php echo esc_attr( $heartbeat ) ?>" <?php checked( $option, 'on' ) ?> />
867 - <?php esc_html_e( 'Enabled', 'stream' ) ?><span class="spinner"></span>
1023 + <input type="checkbox" value="on" name="enable_live_update" id="enable_live_update" data-heartbeat="<?php echo esc_attr( $heartbeat ); ?>" <?php checked( $option, 'on' ); ?> />
1024 + <?php esc_html_e( 'Enabled', 'stream' ); ?>
1025 + <span class="spinner"></span>
868 1026 </label>
869 1027 </div>
870 1028 </fieldset>
871 1029 <?php
@@ -878,9 +1036,9 @@
878 1036 * @param string $column List table column name
879 1037 *
880 1038 * @return string setting name for that column
881 1039 */
882 - function get_column_excluded_setting_key( $column ) {
1040 + public function get_column_excluded_setting_key( $column ) {
883 1041 switch ( $column ) {
884 1042 case 'connector':
885 1043 $output = 'connectors';
886 1044 break;