PluginProbe
Stream – Activity Log & Audit Trail / 4.0.2
Stream – Activity Log & Audit Trail v4.0.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-settings.php +328 -187 3.14.0.2 View file →
@@ -1,14 +1,25 @@
1 1 <?php
2 +/**
3 + * Renders and manages the plugin Settings page.
4 + *
5 + * @package WP_Stream
6 + */
7 +
2 8 namespace WP_Stream;
3 9
4 -use \WP_Roles;
5 -use \WP_User;
6 -use \WP_User_Query;
10 +use WP_Roles;
11 +use WP_User;
12 +use WP_User_Query;
7 13
14 +/**
15 + * Class - Settings
16 + */
8 17 class Settings {
18 +
9 19 /**
10 - * Hold Plugin class
20 + * Holds instance of plugin object
21 + *
11 22 * @var Plugin
12 23 */
13 24 public $plugin;
14 25
@@ -42,9 +53,9 @@
42 53
43 54 /**
44 55 * Class constructor.
45 56 *
46 - * @param Plugin $plugin The main Plugin class.
57 + * @param Plugin $plugin Instance of plugin object.
47 58 */
48 59 public function __construct( $plugin ) {
49 60 $this->plugin = $plugin;
50 61
@@ -50,21 +61,35 @@
50 61
51 62 $this->option_key = $this->get_option_key();
52 63 $this->options = $this->get_options();
53 64
54 - // Register settings, and fields
65 + // Register settings, and fields.
55 66 add_action( 'admin_init', array( $this, 'register_settings' ) );
56 67
57 - // Remove records when records TTL is shortened
58 - add_action( 'update_option_' . $this->option_key, array( $this, 'updated_option_ttl_remove_records' ), 10, 2 );
68 + // Remove records when records TTL is shortened.
69 + add_action(
70 + 'update_option_' . $this->option_key,
71 + array(
72 + $this,
73 + 'updated_option_ttl_remove_records',
74 + ),
75 + 10,
76 + 2
77 + );
59 78
60 - // Apply label translations for settings
61 - add_filter( 'wp_stream_serialized_labels', array( $this, 'get_settings_translations' ) );
79 + // Apply label translations for settings.
80 + add_filter(
81 + 'wp_stream_serialized_labels',
82 + array(
83 + $this,
84 + 'get_settings_translations',
85 + )
86 + );
62 87
63 - // Ajax callback function to search users
88 + // Ajax callback function to search users.
64 89 add_action( 'wp_ajax_stream_get_users', array( $this, 'get_users' ) );
65 90
66 - // Ajax callback function to search IPs
91 + // Ajax callback function to search IPs.
67 92 add_action( 'wp_ajax_stream_get_ips', array( $this, 'get_ips' ) );
68 93 }
69 94
70 95 /**
@@ -83,19 +108,32 @@
83 108 'status' => false,
84 109 'message' => esc_html__( 'There was an error in the request', 'stream' ),
85 110 );
86 111
87 - $search = wp_unslash( trim( wp_stream_filter_input( INPUT_POST, 'find' ) ) );
112 + $search = '';
113 + $input = wp_stream_filter_input( INPUT_POST, 'find' );
88 114
115 + if ( ! isset( $input['term'] ) ) {
116 + $search = wp_unslash( trim( $input['term'] ) );
117 + }
118 +
89 119 $request = (object) array(
90 120 'find' => $search,
91 121 );
92 122
93 - add_filter( 'user_search_columns', array( $this, 'add_display_name_search_columns' ), 10, 3 );
123 + add_filter(
124 + 'user_search_columns',
125 + array(
126 + $this,
127 + 'add_display_name_search_columns',
128 + ),
129 + 10,
130 + 3
131 + );
94 132
95 133 $users = new WP_User_Query(
96 134 array(
97 - 'search' => "*{$request->find}*",
135 + 'search' => "*{$request->find}*",
98 136 'search_columns' => array(
99 137 'user_login',
100 138 'user_nicename',
101 139 'user_email',
@@ -100,14 +138,21 @@
100 138 'user_nicename',
101 139 'user_email',
102 140 'user_url',
103 141 ),
104 - 'orderby' => 'display_name',
105 - 'number' => $this->plugin->admin->preload_users_max,
142 + 'orderby' => 'display_name',
143 + 'number' => $this->plugin->admin->preload_users_max,
106 144 )
107 145 );
108 146
109 - remove_filter( 'user_search_columns', array( $this, 'add_display_name_search_columns' ), 10 );
147 + remove_filter(
148 + 'user_search_columns',
149 + array(
150 + $this,
151 + 'add_display_name_search_columns',
152 + ),
153 + 10
154 + );
110 155
111 156 if ( 0 === $users->get_total() ) {
112 157 wp_send_json_error( $response );
113 158 }
@@ -115,20 +160,21 @@
115 160
116 161 if ( is_multisite() && is_super_admin() ) {
117 162 $super_admins = get_super_admins();
118 163 foreach ( $super_admins as $admin ) {
119 - $user = get_user_by( 'login', $admin );
164 + $user = get_user_by( 'login', $admin );
120 165 $users_array[] = $user;
121 166 }
122 167 }
123 168
124 - $response->status = true;
125 - $response->message = '';
126 - $response->users = array();
169 + $response->status = true;
170 + $response->message = '';
171 + $response->roles = $this->get_roles();
172 + $response->users = array();
127 173 $users_added_to_response = array();
128 174
129 175 foreach ( $users_array as $key => $user ) {
130 - // exclude duplications:
176 + // exclude duplications.
131 177 if ( array_key_exists( $user->ID, $users_added_to_response ) ) {
132 178 continue;
133 179 } else {
134 180 $users_added_to_response[ $user->ID ] = true;
@@ -142,8 +188,9 @@
142 188 );
143 189
144 190 $args['tooltip'] = esc_attr(
145 191 sprintf(
192 + /* translators: %1$d: user ID, %2$s: username, %3$s: email, %4$s: user role (e.g. "42", "administrator", "foo@bar.com", "subscriber") */
146 193 __( 'ID: %1$d\nUser: %2$s\nEmail: %3$s\nRole: %4$s', 'stream' ),
147 194 $author->id,
148 195 $author->user_login,
149 196 $author->user_email,
@@ -157,15 +204,15 @@
157 204 }
158 205
159 206 usort(
160 207 $response->users,
161 - function( $a, $b ) {
208 + function ( $a, $b ) {
162 209 return strcmp( $a['text'], $b['text'] );
163 210 }
164 211 );
165 212
166 213 if ( empty( $search ) || preg_match( '/wp|cli|system|unknown/i', $search ) ) {
167 - $author = new Author( 0 );
214 + $author = new Author( 0 );
168 215 $response->users[] = array(
169 216 'id' => '0',
170 217 'text' => $author->get_display_name(),
171 218 'icon' => $author->get_avatar_src( 32 ),
@@ -176,10 +223,10 @@
176 223 wp_send_json_success( $response );
177 224 }
178 225
179 226 /**
180 - * Ajax callback function to search IP addresses, used on exclude setting page
181 - */
227 + * Ajax callback function to search IP addresses, used on exclude setting page
228 + */
182 229 public function get_ips() {
183 230 if ( ! defined( 'DOING_AJAX' ) || ! current_user_can( $this->plugin->admin->settings_cap ) ) {
184 231 return;
185 232 }
@@ -189,11 +236,14 @@
189 236 $ips = $this->plugin->db->existing_records( 'ip' );
190 237 $find = wp_stream_filter_input( INPUT_POST, 'find' );
191 238
192 239 if ( isset( $find['term'] ) && '' !== $find['term'] ) {
193 - $ips = array_filter( $ips, function ( $ip ) use ( $find ) {
194 - return 0 === strpos( $ip, $find['term'] );
195 - } );
240 + $ips = array_filter(
241 + $ips,
242 + function ( $ip ) use ( $find ) {
243 + return 0 === strpos( $ip, $find['term'] );
244 + }
245 + );
196 246 }
197 247
198 248 if ( $ips ) {
199 249 wp_send_json_success( $ips );
@@ -204,11 +254,11 @@
204 254
205 255 /**
206 256 * Filter the columns to search in a WP_User_Query search.
207 257 *
208 - * @param array $search_columns Array of column names to be searched.
209 - * @param string $search Text being searched.
210 - * @param \WP_User_Query $query current WP_User_Query instance.
258 + * @param array $search_columns Array of column names to be searched.
259 + * @param string $search Text being searched.
260 + * @param \WP_User_Query $query current WP_User_Query instance.
211 261 *
212 262 * @return array
213 263 */
214 264 public function add_display_name_search_columns( $search_columns, $search, $query ) {
@@ -247,18 +297,18 @@
247 297 * @return array
248 298 */
249 299 public function get_fields() {
250 300 $fields = array(
251 - 'general' => array(
301 + 'general' => array(
252 302 'title' => esc_html__( 'General', 'stream' ),
253 303 'fields' => array(
254 304 array(
255 - 'name' => 'role_access',
256 - 'title' => esc_html__( 'Role Access', 'stream' ),
257 - 'type' => 'multi_checkbox',
258 - 'desc' => esc_html__( 'Users from the selected roles above will have permission to view Stream Records. However, only site Administrators can access Stream Settings.', 'stream' ),
259 - 'choices' => $this->get_roles(),
260 - 'default' => array( 'administrator' ),
305 + 'name' => 'role_access',
306 + 'title' => esc_html__( 'Role Access', 'stream' ),
307 + 'type' => 'multi_checkbox',
308 + 'desc' => esc_html__( 'Users from the selected roles above will have permission to view Stream Records. However, only site Administrators can access Stream Settings.', 'stream' ),
309 + 'choices' => $this->get_roles(),
310 + 'default' => array( 'administrator' ),
261 311 ),
262 312 array(
263 313 'name' => 'records_ttl',
264 314 'title' => esc_html__( 'Keep Records for', 'stream' ),
@@ -280,18 +330,18 @@
280 330 'default' => 0,
281 331 ),
282 332 ),
283 333 ),
284 - 'exclude' => array(
334 + 'exclude' => array(
285 335 'title' => esc_html__( 'Exclude', 'stream' ),
286 336 'fields' => array(
287 337 array(
288 - 'name' => 'rules',
289 - 'title' => esc_html__( 'Exclude Rules', 'stream' ),
290 - 'type' => 'rule_list',
291 - 'desc' => esc_html__( 'Create rules to exclude certain kinds of activity from being recorded by Stream.', 'stream' ),
292 - 'default' => array(),
293 - 'nonce' => 'stream_get_ips',
338 + 'name' => 'rules',
339 + 'title' => esc_html__( 'Exclude Rules', 'stream' ),
340 + 'type' => 'rule_list',
341 + 'desc' => esc_html__( 'Create rules to exclude certain kinds of activity from being recorded by Stream.', 'stream' ),
342 + 'default' => array(),
343 + 'nonce' => 'stream_get_ips',
294 344 ),
295 345 ),
296 346 ),
297 347 'advanced' => array(
@@ -305,28 +355,28 @@
305 355 'after_field' => esc_html__( 'Enabled', 'stream' ),
306 356 'default' => 0,
307 357 ),
308 358 array(
309 - 'name' => 'delete_all_records',
310 - 'title' => esc_html__( 'Reset Stream Database', 'stream' ),
311 - 'type' => 'link',
312 - 'href' => add_query_arg(
359 + 'name' => 'delete_all_records',
360 + 'title' => esc_html__( 'Reset Stream Database', 'stream' ),
361 + 'type' => 'link',
362 + 'href' => add_query_arg(
313 363 array(
314 - 'action' => 'wp_stream_reset',
315 - 'wp_stream_nonce' => wp_create_nonce( 'stream_nonce' ),
364 + 'action' => 'wp_stream_reset',
365 + 'wp_stream_nonce_reset' => wp_create_nonce( 'stream_nonce_reset' ),
316 366 ),
317 367 admin_url( 'admin-ajax.php' )
318 368 ),
319 - 'class' => 'warning',
320 - 'desc' => esc_html__( 'Warning: This will delete all activity records from the database.', 'stream' ),
321 - 'default' => 0,
322 - 'sticky' => 'bottom',
369 + 'class' => 'warning',
370 + 'desc' => esc_html__( 'Warning: This will delete all activity records from the database.', 'stream' ),
371 + 'default' => 0,
372 + 'sticky' => 'bottom',
323 373 ),
324 374 ),
325 375 ),
326 376 );
327 377
328 - // If Akismet is active, allow Admins to opt-in to Akismet tracking
378 + // If Akismet is active, allow Admins to opt-in to Akismet tracking.
329 379 if ( class_exists( 'Akismet' ) ) {
330 380 $akismet_tracking = array(
331 381 'name' => 'akismet_tracking',
332 382 'title' => esc_html__( 'Akismet Tracking', 'stream' ),
@@ -338,21 +388,18 @@
338 388
339 389 array_push( $fields['advanced']['fields'], $akismet_tracking );
340 390 }
341 391
342 - // If WP Cron is enabled, allow Admins to opt-in to WP Cron tracking
343 - if ( wp_stream_is_cron_enabled() ) {
344 - $wp_cron_tracking = array(
345 - 'name' => 'wp_cron_tracking',
346 - 'title' => esc_html__( 'WP Cron Tracking', 'stream' ),
347 - 'type' => 'checkbox',
348 - 'desc' => esc_html__( 'By default, Stream does not track activity performed by WordPress cron events unless you opt-in here. Enabling this is not necessary or recommended for most sites.', 'stream' ),
349 - 'after_field' => esc_html__( 'Enabled', 'stream' ),
350 - 'default' => 0,
351 - );
392 + $wp_cron_tracking = array(
393 + 'name' => 'wp_cron_tracking',
394 + 'title' => esc_html__( 'WP Cron Tracking', 'stream' ),
395 + 'type' => 'checkbox',
396 + 'desc' => esc_html__( 'By default, Stream does not track activity performed by WordPress cron events unless you opt-in here. Enabling this is not necessary or recommended for most sites.', 'stream' ),
397 + 'after_field' => esc_html__( 'Enabled', 'stream' ),
398 + 'default' => 0,
399 + );
352 400
353 - array_push( $fields['advanced']['fields'], $wp_cron_tracking );
354 - }
401 + array_push( $fields['advanced']['fields'], $wp_cron_tracking );
355 402
356 403 /**
357 404 * Filter allows for modification of options fields
358 405 *
@@ -359,9 +406,9 @@
359 406 * @return array Array of option fields
360 407 */
361 408 $this->fields = apply_filters( 'wp_stream_settings_option_fields', $fields );
362 409
363 - // Sort option fields in each tab by title ASC
410 + // Sort option fields in each tab by title ASC.
364 411 foreach ( $this->fields as $tab => $options ) {
365 412 $titles = array();
366 413
367 414 foreach ( $options['fields'] as $field ) {
@@ -431,9 +478,16 @@
431 478 */
432 479 public function register_settings() {
433 480 $sections = $this->get_fields();
434 481
435 - register_setting( $this->option_key, $this->option_key, array( $this, 'sanitize_settings' ) );
482 + register_setting(
483 + $this->option_key,
484 + $this->option_key,
485 + array(
486 + $this,
487 + 'sanitize_settings',
488 + )
489 + );
436 490
437 491 foreach ( $sections as $section_name => $section ) {
438 492 add_settings_section(
439 493 $section_name,
@@ -442,9 +496,10 @@
442 496 $this->option_key
443 497 );
444 498
445 499 foreach ( $section['fields'] as $field_idx => $field ) {
446 - if ( ! isset( $field['type'] ) ) { // No field type associated, skip, no GUI
500 + // No field type associated, skip, no GUI.
501 + if ( ! isset( $field['type'] ) ) {
447 502 continue;
448 503 }
449 504
450 505 add_settings_field(
@@ -449,14 +504,17 @@
449 504
450 505 add_settings_field(
451 506 $field['name'],
452 507 $field['title'],
453 - ( isset( $field['callback'] ) ? $field['callback'] : array( $this, 'output_field' ) ),
508 + ( isset( $field['callback'] ) ? $field['callback'] : array(
509 + $this,
510 + 'output_field',
511 + ) ),
454 512 $this->option_key,
455 513 $section_name,
456 514 $field + array(
457 515 'section' => $section_name,
458 - 'label_for' => sprintf( '%s_%s_%s', $this->option_key, $section_name, $field['name'] ), // xss ok
516 + 'label_for' => sprintf( '%s_%s_%s', $this->option_key, $section_name, $field['name'] ),
459 517 )
460 518 );
461 519 }
462 520 }
@@ -464,9 +522,9 @@
464 522
465 523 /**
466 524 * Sanitization callback for settings field values before save
467 525 *
468 - * @param array $input
526 + * @param array $input Raw input.
469 527 *
470 528 * @return array
471 529 */
472 530 public function sanitize_settings( $input ) {
@@ -485,38 +543,56 @@
485 543 if ( empty( $type ) || ! isset( $input[ $name ] ) || '' === $input[ $name ] ) {
486 544 continue;
487 545 }
488 546
489 - // Sanitize depending on the type of field
490 - switch ( $type ) {
491 - case 'number':
492 - $output[ $name ] = is_numeric( $input[ $name ] ) ? intval( trim( $input[ $name ] ) ) : '';
493 - break;
494 - case 'checkbox':
495 - $output[ $name ] = is_numeric( $input[ $name ] ) ? absint( trim( $input[ $name ] ) ) : '';
496 - break;
497 - default:
498 - if ( is_array( $input[ $name ] ) ) {
499 - $output[ $name ] = $input[ $name ];
547 + $output[ $name ] = $this->sanitize_setting_by_field_type( $input[ $name ], $type );
548 + }
549 + }
500 550
501 - // Support all values in multidimentional arrays too
502 - array_walk_recursive( $output[ $name ], function( &$v, $k ) {
503 - $v = trim( $v );
504 - } );
505 - } else {
506 - $output[ $name ] = trim( $input[ $name ] );
551 + return $output;
552 + }
553 +
554 + /**
555 + * Sanitizes a setting value based on the field type.
556 + *
557 + * @param mixed $value The value to be sanitized.
558 + * @param string $field_type The type of field.
559 + *
560 + * @return mixed The sanitized value.
561 + */
562 + public function sanitize_setting_by_field_type( $value, $field_type ) {
563 +
564 + // Sanitize depending on the type of field.
565 + switch ( $field_type ) {
566 + case 'number':
567 + $sanitized_value = is_numeric( $value ) ? intval( trim( $value ) ) : '';
568 + break;
569 + case 'checkbox':
570 + $sanitized_value = is_numeric( $value ) ? absint( trim( $value ) ) : '';
571 + break;
572 + default:
573 + if ( is_array( $value ) ) {
574 + $sanitized_value = $value;
575 +
576 + // Support all values in multidimentional arrays too.
577 + array_walk_recursive(
578 + $sanitized_value,
579 + function ( &$v ) {
580 + $v = sanitize_text_field( trim( $v ) );
507 581 }
582 + );
583 + } else {
584 + $sanitized_value = sanitize_text_field( trim( $value ) );
508 585 }
509 - }
510 586 }
511 587
512 - return $output;
588 + return $sanitized_value;
513 589 }
514 590
515 591 /**
516 592 * Compile HTML needed for displaying the field
517 593 *
518 - * @param array $field Field settings
594 + * @param array $field Field settings.
519 595 *
520 596 * @return string HTML to be displayed
521 597 */
522 598 public function render_field( $field ) {
@@ -539,14 +615,12 @@
539 615 $nonce = isset( $field['nonce'] ) ? $field['nonce'] : null;
540 616
541 617 if ( isset( $field['value'] ) ) {
542 618 $current_value = $field['value'];
619 + } elseif ( isset( $this->options[ $section . '_' . $name ] ) ) {
620 + $current_value = $this->options[ $section . '_' . $name ];
543 621 } else {
544 - if ( isset( $this->options[ $section . '_' . $name ] ) ) {
545 - $current_value = $this->options[ $section . '_' . $name ];
546 - } else {
547 - $current_value = null;
548 - }
622 + $current_value = null;
549 623 }
550 624
551 625 $option_key = $this->option_key;
552 626
@@ -557,11 +631,9 @@
557 631 if ( ! $type || ! $section || ! $name ) {
558 632 return '';
559 633 }
560 634
561 - if ( 'multi_checkbox' === $type
562 - && ( empty( $field['choices'] ) || ! is_array( $field['choices'] ) )
563 - ) {
635 + if ( 'multi_checkbox' === $type && ( empty( $field['choices'] ) || ! is_array( $field['choices'] ) ) ) {
564 636 return '';
565 637 }
566 638
567 639 switch ( $type ) {
@@ -620,10 +692,10 @@
620 692 esc_attr( $option_key ),
621 693 esc_attr( $section ),
622 694 esc_attr( $name )
623 695 );
624 - // Fallback if nothing is selected
625 - $output .= sprintf(
696 + // Fallback if nothing is selected.
697 + $output .= sprintf(
626 698 '<input type="hidden" name="%1$s[%2$s_%3$s][]" value="__placeholder__" />',
627 699 esc_attr( $option_key ),
628 700 esc_attr( $section ),
629 701 esc_attr( $name )
@@ -628,9 +700,9 @@
628 700 esc_attr( $section ),
629 701 esc_attr( $name )
630 702 );
631 703 $current_value = (array) $current_value;
632 - $choices = $field['choices'];
704 + $choices = $field['choices'];
633 705 if ( is_callable( $choices ) ) {
634 706 $choices = call_user_func( $choices );
635 707 }
636 708 foreach ( $choices as $value => $label ) {
@@ -695,9 +767,9 @@
695 767 esc_attr( $href ),
696 768 esc_attr( $title )
697 769 );
698 770 break;
699 - case 'select2' :
771 + case 'select2':
700 772 if ( ! isset( $current_value ) ) {
701 773 $current_value = '';
702 774 }
703 775
@@ -714,16 +786,26 @@
714 786 $child_values = array();
715 787 if ( isset( $value['children'] ) ) {
716 788 $child_values = array();
717 789 foreach ( $value['children'] as $child_key => $child_value ) {
718 - $child_values[] = array( 'id' => $child_key, 'text' => $child_value );
790 + $child_values[] = array(
791 + 'id' => $child_key,
792 + 'text' => $child_value,
793 + );
719 794 }
720 795 }
721 796 if ( isset( $value['label'] ) ) {
722 - $data_values[] = array( 'id' => $key, 'text' => $value['label'], 'children' => $child_values );
797 + $data_values[] = array(
798 + 'id' => $key,
799 + 'text' => $value['label'],
800 + 'children' => $child_values,
801 + );
723 802 }
724 803 } else {
725 - $data_values[] = array( 'id' => $key, 'text' => $value );
804 + $data_values[] = array(
805 + 'id' => $key,
806 + 'text' => $value,
807 + );
726 808 }
727 809 }
728 810 $class .= ' with-source';
729 811 }
@@ -732,11 +814,12 @@
732 814 '<input type="hidden" name="%1$s[%2$s_%3$s]" data-values=\'%4$s\' value="%5$s" class="select2-select %6$s" data-placeholder="%7$s" />',
733 815 esc_attr( $option_key ),
734 816 esc_attr( $section ),
735 817 esc_attr( $name ),
736 - esc_attr( wp_stream_json_encode( $data_values ) ),
818 + esc_attr( wp_json_encode( $data_values ) ),
737 819 esc_attr( $current_value ),
738 820 esc_attr( $class ),
821 + /* translators: %s: the title of the dropdown menu (e.g. "users") */
739 822 sprintf( esc_html__( 'Any %s', 'stream' ), $title )
740 823 );
741 824
742 825 $output = sprintf(
@@ -747,14 +830,15 @@
747 830 $input_html
748 831 );
749 832
750 833 break;
751 - case 'rule_list' :
752 - $form = new Form_Generator;
834 + case 'rule_list':
835 + $users = count_users();
836 + $form = new Form_Generator();
753 837 $output = '<p class="description">' . esc_html( $description ) . '</p>';
754 838
755 - $actions_top = sprintf( '<input type="button" class="button" id="%1$s_new_rule" value="&#43; %2$s" />', esc_attr( $section . '_' . $name ), esc_html__( 'Add New Rule', 'stream' ) );
756 - $actions_bottom = sprintf( '<input type="button" class="button" id="%1$s_remove_rules" value="%2$s" />', esc_attr( $section . '_' . $name ), esc_html__( 'Delete Selected Rules', 'stream' ) );
839 + $actions_top = sprintf( '<input type="button" class="button" id="%1$s_new_rule" value="&#43; %2$s" />', esc_attr( $section . '_' . $name ), esc_html__( 'Add New Rule', 'stream' ) );
840 + $actions_bottom = sprintf( '<input type="button" class="button" id="%1$s_remove_rules" value="%2$s" />', esc_attr( $section . '_' . $name ), esc_html__( 'Delete Selected Rules', 'stream' ) );
757 841
758 842 $output .= sprintf( '<div class="tablenav top">%1$s</div>', $actions_top );
759 843 $output .= '<table class="wp-list-table widefat fixed stream-exclude-list">';
760 844
@@ -778,13 +862,18 @@
778 862 );
779 863
780 864 $exclude_rows = array();
781 865
782 - // Prepend an empty row
783 - $current_value['exclude_row'] = array( 'helper' => '' ) + ( isset( $current_value['exclude_row'] ) ? $current_value['exclude_row'] : array() );
866 + // Account for when no rules have been added yet.
867 + if ( ! is_array( $current_value ) ) {
868 + $current_value = array();
869 + }
784 870
871 + // Prepend an empty row.
872 + $current_value['exclude_row'] = ( isset( $current_value['exclude_row'] ) ? $current_value['exclude_row'] : array() ) + array( 'helper' => '' );
873 +
785 874 foreach ( $current_value['exclude_row'] as $key => $value ) {
786 - // Prepare values
875 + // Prepare values.
787 876 $author_or_role = isset( $current_value['author_or_role'][ $key ] ) ? $current_value['author_or_role'][ $key ] : '';
788 877 $connector = isset( $current_value['connector'][ $key ] ) ? $current_value['connector'][ $key ] : '';
789 878 $context = isset( $current_value['context'][ $key ] ) ? $current_value['context'][ $key ] : '';
790 879 $action = isset( $current_value['action'][ $key ] ) ? $current_value['action'][ $key ] : '';
@@ -789,18 +878,21 @@
789 878 $context = isset( $current_value['context'][ $key ] ) ? $current_value['context'][ $key ] : '';
790 879 $action = isset( $current_value['action'][ $key ] ) ? $current_value['action'][ $key ] : '';
791 880 $ip_address = isset( $current_value['ip_address'][ $key ] ) ? $current_value['ip_address'][ $key ] : '';
792 881
793 - // Author or Role dropdown menu
882 + // Author or Role dropdown menu.
794 883 $author_or_role_values = array();
795 884 $author_or_role_selected = array();
796 885
797 886 foreach ( $this->get_roles() as $role_id => $role ) {
798 - $args = array( 'value' => $role_id, 'text' => $role );
799 - $users = count_users();
887 + $args = array(
888 + 'value' => $role_id,
889 + 'text' => $role,
890 + );
800 891 $count = isset( $users['avail_roles'][ $role_id ] ) ? $users['avail_roles'][ $role_id ] : 0;
801 892
802 893 if ( ! empty( $count ) ) {
894 + /* translators: %d: a number of users (e.g. "42") */
803 895 $args['user_count'] = sprintf( _n( '%d user', '%d users', absint( $count ), 'stream' ), absint( $count ) );
804 896 }
805 897
806 898 if ( $role_id === $author_or_role ) {
@@ -813,25 +905,33 @@
813 905
814 906 if ( empty( $author_or_role_selected ) && is_numeric( $author_or_role ) ) {
815 907 $user = new WP_User( $author_or_role );
816 908 $display_name = ( 0 === $user->ID ) ? esc_html__( 'N/A', 'stream' ) : $user->display_name;
817 - $author_or_role_selected = array( 'value' => $user->ID, 'text' => $display_name );
909 + $author_or_role_selected = array(
910 + 'value' => $user->ID,
911 + 'text' => $display_name,
912 + );
818 913 $author_or_role_values[] = $author_or_role_selected;
819 914 }
820 915
821 - $author_or_role_input = $form->render_field( 'select2', array(
822 - 'name' => esc_attr( sprintf( '%1$s[%2$s_%3$s][%4$s][]' , $option_key, $section, $name, 'author_or_role' ) ),
823 - 'options' => $author_or_role_values,
824 - 'classes' => 'author_or_role',
825 - 'data' => array(
826 - 'placeholder' => esc_html__( 'Any Author or Role', 'stream' ),
827 - 'nonce' => esc_attr( wp_create_nonce( 'stream_get_users' ) ),
828 - 'selected-id' => isset( $author_or_role_selected['value'] ) ? esc_attr( $author_or_role_selected['value'] ) : '',
829 - 'selected-text' => isset( $author_or_role_selected['text'] ) ? esc_attr( $author_or_role_selected['text'] ) : '',
916 + $author_or_role_input = $form->render_field(
917 + 'select2',
918 + array(
919 + 'name' => esc_attr( sprintf( '%1$s[%2$s_%3$s][%4$s][]', $option_key, $section, $name, 'author_or_role' ) ),
920 + 'options' => $author_or_role_values,
921 + 'classes' => 'author_or_role',
922 + // Data attributes are escaped in Form_Generator::prepare_data_attributes_string().
923 + 'data' => array(
924 + 'placeholder' => __( 'Any Author or Role', 'stream' ),
925 + 'nonce' => wp_create_nonce( 'stream_get_users' ),
926 + 'selected-id' => isset( $author_or_role_selected['value'] ) ? $author_or_role_selected['value'] : '',
927 + 'selected-text' => isset( $author_or_role_selected['text'] ) ? $author_or_role_selected['text'] : '',
928 + ),
830 929 ),
831 - ) );
930 + false
931 + );
832 932
833 - // Context dropdown menu
933 + // Context dropdown menu.
834 934 $context_values = array();
835 935
836 936 foreach ( $this->get_terms_labels( 'context' ) as $context_id => $context_data ) {
837 937 if ( is_array( $context_data ) ) {
@@ -838,71 +938,108 @@
838 938 $child_values = array();
839 939 if ( isset( $context_data['children'] ) ) {
840 940 $child_values = array();
841 941 foreach ( $context_data['children'] as $child_id => $child_value ) {
842 - $child_values[] = array( 'value' => $context_id . '-' . $child_id, 'text' => $child_value, 'parent' => $context_id );
942 + $child_values[] = array(
943 + 'value' => $context_id . '-' . $child_id,
944 + 'text' => $child_value,
945 + 'parent' => $context_id,
946 + );
843 947 }
844 948 }
845 949 if ( isset( $context_data['label'] ) ) {
846 - $context_values[] = array( 'value' => $context_id, 'text' => $context_data['label'], 'children' => $child_values );
950 + $context_values[] = array(
951 + 'value' => $context_id,
952 + 'text' => $context_data['label'],
953 + 'children' => $child_values,
954 + );
847 955 }
848 956 } else {
849 - $context_values[] = array( 'value' => $context_id, 'text' => $context_data );
957 + $context_values[] = array(
958 + 'value' => $context_id,
959 + 'text' => $context_data,
960 + );
850 961 }
851 962 }
852 963
853 - $connector_or_context_input = $form->render_field( 'select2', array(
854 - 'name' => esc_attr( sprintf( '%1$s[%2$s_%3$s][%4$s][]' , $option_key, $section, $name, 'connector_or_context' ) ),
855 - 'options' => $context_values,
856 - 'classes' => 'connector_or_context',
857 - 'data' => array(
858 - 'group' => 'connector',
859 - 'placeholder' => __( 'Any Context', 'stream' ),
964 + $connector_or_context_input = $form->render_field(
965 + 'select2',
966 + array(
967 + 'name' => esc_attr( sprintf( '%1$s[%2$s_%3$s][%4$s][]', $option_key, $section, $name, 'connector_or_context' ) ),
968 + 'options' => $context_values,
969 + 'classes' => 'connector_or_context',
970 + // Data attributes are escaped in Form_Generator::prepare_data_attributes_string().
971 + 'data' => array(
972 + 'group' => 'connector',
973 + 'placeholder' => __( 'Any Context', 'stream' ),
974 + ),
860 975 ),
861 - ) );
976 + false
977 + );
862 978
863 - $connector_input = $form->render_field( 'hidden', array(
864 - 'name' => esc_attr( sprintf( '%1$s[%2$s_%3$s][%4$s][]' , $option_key, $section, $name, 'connector' ) ),
865 - 'value' => $connector,
866 - 'classes' => 'connector',
867 - ) );
979 + $connector_input = $form->render_field(
980 + 'hidden',
981 + array(
982 + 'name' => esc_attr( sprintf( '%1$s[%2$s_%3$s][%4$s][]', $option_key, $section, $name, 'connector' ) ),
983 + 'value' => $connector,
984 + 'classes' => 'connector',
985 + ),
986 + false
987 + );
868 988
869 - $context_input = $form->render_field( 'hidden', array(
870 - 'name' => esc_attr( sprintf( '%1$s[%2$s_%3$s][%4$s][]' , $option_key, $section, $name, 'context' ) ),
871 - 'value' => $context,
872 - 'classes' => 'context',
873 - ) );
989 + $context_input = $form->render_field(
990 + 'hidden',
991 + array(
992 + 'name' => esc_attr( sprintf( '%1$s[%2$s_%3$s][%4$s][]', $option_key, $section, $name, 'context' ) ),
993 + 'value' => $context,
994 + 'classes' => 'context',
995 + ),
996 + false
997 + );
874 998
875 - // Action dropdown menu
999 + // Action dropdown menu.
876 1000 $action_values = array();
877 1001
878 1002 foreach ( $this->get_terms_labels( 'action' ) as $action_id => $action_data ) {
879 - $action_values[] = array( 'value' => $action_id, 'text' => $action_data );
1003 + $action_values[] = array(
1004 + 'value' => $action_id,
1005 + 'text' => $action_data,
1006 + );
880 1007 }
881 1008
882 - $action_input = $form->render_field( 'select2', array(
883 - 'name' => esc_attr( sprintf( '%1$s[%2$s_%3$s][%4$s][]' , $option_key, $section, $name, 'action' ) ),
884 - 'value' => $action,
885 - 'options' => $action_values,
886 - 'classes' => 'action',
887 - 'data' => array(
888 - 'placeholder' => __( 'Any Action', 'stream' ),
1009 + $action_input = $form->render_field(
1010 + 'select2',
1011 + array(
1012 + 'name' => esc_attr( sprintf( '%1$s[%2$s_%3$s][%4$s][]', $option_key, $section, $name, 'action' ) ),
1013 + 'value' => $action,
1014 + 'options' => $action_values,
1015 + 'classes' => 'action',
1016 + // Data attributes are escaped in Form_Generator::prepare_data_attributes_string().
1017 + 'data' => array(
1018 + 'placeholder' => __( 'Any Action', 'stream' ),
1019 + ),
889 1020 ),
890 - ) );
1021 + false
1022 + );
891 1023
892 - // IP Address input
893 - $ip_address_input = $form->render_field( 'select2', array(
894 - 'name' => esc_attr( sprintf( '%1$s[%2$s_%3$s][%4$s][]' , $option_key, $section, $name, 'ip_address' ) ),
895 - 'value' => $ip_address,
896 - 'classes' => 'ip_address',
897 - 'data' => array(
898 - 'placeholder' => esc_attr__( 'Any IP Address', 'stream' ),
899 - 'nonce' => esc_attr( wp_create_nonce( 'stream_get_ips' ) ),
1024 + // IP Address input.
1025 + $ip_address_input = $form->render_field(
1026 + 'select2',
1027 + array(
1028 + 'name' => esc_attr( sprintf( '%1$s[%2$s_%3$s][%4$s][]', $option_key, $section, $name, 'ip_address' ) ),
1029 + 'value' => $ip_address,
1030 + 'classes' => 'ip_address',
1031 + // Data attributes are escaped in Form_Generator::prepare_data_attributes_string().
1032 + 'data' => array(
1033 + 'placeholder' => __( 'Any IP Address', 'stream' ),
1034 + 'nonce' => wp_create_nonce( 'stream_get_ips' ),
1035 + ),
1036 + 'multiple' => true,
900 1037 ),
901 - 'multiple' => true,
902 - ) );
1038 + false
1039 + );
903 1040
904 - // Hidden helper input
1041 + // Hidden helper input.
905 1042 $helper_input = sprintf(
906 1043 '<input type="hidden" name="%1$s[%2$s_%3$s][%4$s][]" value="" />',
907 1044 esc_attr( $option_key ),
908 1045 esc_attr( $section ),
@@ -916,12 +1053,14 @@
916 1053 <td>%5$s</td>
917 1054 <td>%6$s %7$s %8$s</td>
918 1055 <td>%9$s</td>
919 1056 <td>%10$s</td>
920 - <th scope="row" class="actions-column">%11$s</th>
1057 + <th scope="row" class="actions-column">
1058 + <a href="#" class="exclude_rules_remove_rule_row">%11$s</a>
1059 + </th>
921 1060 </tr>',
922 - ( 0 !== $key % 2 ) ? 'alternate' : '',
923 - ( 'helper' === $key ) ? 'hidden helper' : '',
1061 + ( 0 !== (int) $key % 2 ) ? 'alternate' : '',
1062 + ( 'helper' === (string) $key ) ? 'hidden helper' : '',
924 1063 '<input class="cb-select" type="checkbox" />',
925 1064 $helper_input,
926 1065 $author_or_role_input,
927 1066 $connector_or_context_input,
@@ -928,9 +1067,9 @@
928 1067 $connector_input,
929 1068 $context_input,
930 1069 $action_input,
931 1070 $ip_address_input,
932 - '<a href="#" class="exclude_rules_remove_rule_row">Delete</a>'
1071 + esc_html__( 'Delete', 'stream' )
933 1072 );
934 1073 }
935 1074
936 1075 $no_rules_found_row = sprintf(
@@ -955,9 +1094,9 @@
955 1094
956 1095 /**
957 1096 * Render Callback for post_types field
958 1097 *
959 - * @param array $field
1098 + * @param array $field Field to be rendered.
960 1099 *
961 1100 * @return string
962 1101 */
963 1102 public function output_field( $field ) {
@@ -968,9 +1107,9 @@
968 1107 }
969 1108
970 1109 $output = $this->render_field( $field );
971 1110
972 - echo $output; // xss ok
1111 + echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
973 1112 }
974 1113
975 1114 /**
976 1115 * Get an array of user roles
@@ -990,9 +1129,9 @@
990 1129
991 1130 /**
992 1131 * Function will return all terms labels of given column
993 1132 *
994 - * @param string $column string Name of the column
1133 + * @param string $column Name of the column.
995 1134 *
996 1135 * @return array
997 1136 */
998 1137 public function get_terms_labels( $column ) {
@@ -1025,14 +1164,14 @@
1025 1164 * Remove records when records TTL is shortened
1026 1165 *
1027 1166 * @action update_option_wp_stream
1028 1167 *
1029 - * @param array $old_value
1030 - * @param array $new_value
1168 + * @param array $old_value Old value.
1169 + * @param array $new_value New value.
1031 1170 */
1032 1171 public function updated_option_ttl_remove_records( $old_value, $new_value ) {
1033 - $ttl_before = isset( $old_value['general_records_ttl'] ) ? (int) $old_value['general_records_ttl'] : -1;
1034 - $ttl_after = isset( $new_value['general_records_ttl'] ) ? (int) $new_value['general_records_ttl'] : -1;
1172 + $ttl_before = isset( $old_value['general_records_ttl'] ) ? (int) $old_value['general_records_ttl'] : - 1;
1173 + $ttl_after = isset( $new_value['general_records_ttl'] ) ? (int) $new_value['general_records_ttl'] : - 1;
1035 1174
1036 1175 if ( $ttl_after < $ttl_before ) {
1037 1176 /**
1038 1177 * Action assists in purging when TTL is shortened
@@ -1044,8 +1183,10 @@
1044 1183 /**
1045 1184 * Get translations of serialized Stream settings
1046 1185 *
1047 1186 * @filter wp_stream_serialized_labels
1187 + *
1188 + * @param array $labels Setting labels.
1048 1189 *
1049 1190 * @return array Multidimensional array of fields
1050 1191 */
1051 1192 public function get_settings_translations( $labels ) {