PluginProbe
Stream – Activity Log & Audit Trail / 3.7.0
Stream – Activity Log & Audit Trail v3.7.0
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 +326 -171 3.0.13.7.0 View file →
@@ -1,5 +1,11 @@
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 10 use \WP_Roles;
5 11 use \WP_User;
@@ -4,11 +10,16 @@
4 10 use \WP_Roles;
5 11 use \WP_User;
6 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 /**
@@ -84,21 +109,31 @@
84 109 'message' => esc_html__( 'There was an error in the request', 'stream' ),
85 110 );
86 111
87 112 $search = '';
88 - if ( isset( $_POST['find'] ) ) {
89 - // @TODO: Make this pass phpcs
90 - $search = esc_html( wp_unslash( trim( $_POST['find'] ) ) ); // input var okay
113 + $input = wp_stream_filter_input( INPUT_POST, 'find' );
114 +
115 + if ( ! isset( $input['term'] ) ) {
116 + $search = wp_unslash( trim( $input['term'] ) );
91 117 }
118 +
92 119 $request = (object) array(
93 120 'find' => $search,
94 121 );
95 122
96 - 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 + );
97 132
98 133 $users = new WP_User_Query(
99 134 array(
100 - 'search' => "*{$request->find}*",
135 + 'search' => "*{$request->find}*",
101 136 'search_columns' => array(
102 137 'user_login',
103 138 'user_nicename',
104 139 'user_email',
@@ -103,24 +138,49 @@
103 138 'user_nicename',
104 139 'user_email',
105 140 'user_url',
106 141 ),
107 - 'orderby' => 'display_name',
108 - 'number' => $this->plugin->admin->preload_users_max,
142 + 'orderby' => 'display_name',
143 + 'number' => $this->plugin->admin->preload_users_max,
109 144 )
110 145 );
111 146
112 - 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 + );
113 155
114 156 if ( 0 === $users->get_total() ) {
115 157 wp_send_json_error( $response );
116 158 }
159 + $users_array = $users->results;
117 160
118 - $response->status = true;
119 - $response->message = '';
120 - $response->users = array();
161 + if ( is_multisite() && is_super_admin() ) {
162 + $super_admins = get_super_admins();
163 + foreach ( $super_admins as $admin ) {
164 + $user = get_user_by( 'login', $admin );
165 + $users_array[] = $user;
166 + }
167 + }
121 168
122 - foreach ( $users->results as $key => $user ) {
169 + $response->status = true;
170 + $response->message = '';
171 + $response->roles = $this->get_roles();
172 + $response->users = array();
173 + $users_added_to_response = array();
174 +
175 + foreach ( $users_array as $key => $user ) {
176 + // exclude duplications.
177 + if ( array_key_exists( $user->ID, $users_added_to_response ) ) {
178 + continue;
179 + } else {
180 + $users_added_to_response[ $user->ID ] = true;
181 + }
182 +
123 183 $author = new Author( $user->ID );
124 184
125 185 $args = array(
126 186 'id' => $author->ID,
@@ -128,9 +188,10 @@
128 188 );
129 189
130 190 $args['tooltip'] = esc_attr(
131 191 sprintf(
132 - __( "ID: %d\nUser: %s\nEmail: %s\nRole: %s", 'stream' ),
192 + /* translators: %1$d: user ID, %2$s: username, %3$s: email, %4$s: user role (e.g. "42", "administrator", "foo@bar.com", "subscriber") */
193 + __( 'ID: %1$d\nUser: %2$s\nEmail: %3$s\nRole: %4$s', 'stream' ),
133 194 $author->id,
134 195 $author->user_login,
135 196 $author->user_email,
136 197 ucwords( $author->get_role() )
@@ -141,12 +202,19 @@
141 202
142 203 $response->users[] = $args;
143 204 }
144 205
206 + usort(
207 + $response->users,
208 + function ( $a, $b ) {
209 + return strcmp( $a['text'], $b['text'] );
210 + }
211 + );
212 +
145 213 if ( empty( $search ) || preg_match( '/wp|cli|system|unknown/i', $search ) ) {
146 - $author = new Author( 0 );
214 + $author = new Author( 0 );
147 215 $response->users[] = array(
148 - 'id' => $author->id,
216 + 'id' => '0',
149 217 'text' => $author->get_display_name(),
150 218 'icon' => $author->get_avatar_src( 32 ),
151 219 'tooltip' => esc_html__( 'Actions performed by the system when a user is not logged in (e.g. auto site upgrader, or invoking WP-CLI without --user)', 'stream' ),
152 220 );
@@ -155,10 +223,10 @@
155 223 wp_send_json_success( $response );
156 224 }
157 225
158 226 /**
159 - * Ajax callback function to search IP addresses, used on exclude setting page
160 - */
227 + * Ajax callback function to search IP addresses, used on exclude setting page
228 + */
161 229 public function get_ips() {
162 230 if ( ! defined( 'DOING_AJAX' ) || ! current_user_can( $this->plugin->admin->settings_cap ) ) {
163 231 return;
164 232 }
@@ -164,10 +232,20 @@
164 232 }
165 233
166 234 check_ajax_referer( 'stream_get_ips', 'nonce' );
167 235
168 - $ips = $this->plugin->db->existing_records( 'ip' );
236 + $ips = $this->plugin->db->existing_records( 'ip' );
237 + $find = wp_stream_filter_input( INPUT_POST, 'find' );
169 238
239 + if ( isset( $find['term'] ) && '' !== $find['term'] ) {
240 + $ips = array_filter(
241 + $ips,
242 + function ( $ip ) use ( $find ) {
243 + return 0 === strpos( $ip, $find['term'] );
244 + }
245 + );
246 + }
247 +
170 248 if ( $ips ) {
171 249 wp_send_json_success( $ips );
172 250 } else {
173 251 wp_send_json_error();
@@ -176,11 +254,11 @@
176 254
177 255 /**
178 256 * Filter the columns to search in a WP_User_Query search.
179 257 *
180 - * @param array $search_columns Array of column names to be searched.
181 - * @param string $search Text being searched.
182 - * @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.
183 261 *
184 262 * @return array
185 263 */
186 264 public function add_display_name_search_columns( $search_columns, $search, $query ) {
@@ -219,18 +297,18 @@
219 297 * @return array
220 298 */
221 299 public function get_fields() {
222 300 $fields = array(
223 - 'general' => array(
301 + 'general' => array(
224 302 'title' => esc_html__( 'General', 'stream' ),
225 303 'fields' => array(
226 304 array(
227 - 'name' => 'role_access',
228 - 'title' => esc_html__( 'Role Access', 'stream' ),
229 - 'type' => 'multi_checkbox',
230 - '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' ),
231 - 'choices' => $this->get_roles(),
232 - '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' ),
233 311 ),
234 312 array(
235 313 'name' => 'records_ttl',
236 314 'title' => esc_html__( 'Keep Records for', 'stream' ),
@@ -252,18 +330,18 @@
252 330 'default' => 0,
253 331 ),
254 332 ),
255 333 ),
256 - 'exclude' => array(
334 + 'exclude' => array(
257 335 'title' => esc_html__( 'Exclude', 'stream' ),
258 336 'fields' => array(
259 337 array(
260 - 'name' => 'rules',
261 - 'title' => esc_html__( 'Exclude Rules', 'stream' ),
262 - 'type' => 'rule_list',
263 - 'desc' => esc_html__( 'Create rules to exclude certain kinds of activity from being recorded by Stream.', 'stream' ),
264 - 'default' => array(),
265 - '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',
266 344 ),
267 345 ),
268 346 ),
269 347 'advanced' => array(
@@ -277,28 +355,28 @@
277 355 'after_field' => esc_html__( 'Enabled', 'stream' ),
278 356 'default' => 0,
279 357 ),
280 358 array(
281 - 'name' => 'delete_all_records',
282 - 'title' => esc_html__( 'Reset Stream Database', 'stream' ),
283 - 'type' => 'link',
284 - '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(
285 363 array(
286 - 'action' => 'wp_stream_reset',
287 - 'wp_stream_nonce' => wp_create_nonce( 'stream_nonce' ),
364 + 'action' => 'wp_stream_reset',
365 + 'wp_stream_nonce_reset' => wp_create_nonce( 'stream_nonce_reset' ),
288 366 ),
289 367 admin_url( 'admin-ajax.php' )
290 368 ),
291 - 'class' => 'warning',
292 - 'desc' => esc_html__( 'Warning: This will delete all activity records from the database.', 'stream' ),
293 - 'default' => 0,
294 - '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',
295 373 ),
296 374 ),
297 375 ),
298 376 );
299 377
300 - // 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.
301 379 if ( class_exists( 'Akismet' ) ) {
302 380 $akismet_tracking = array(
303 381 'name' => 'akismet_tracking',
304 382 'title' => esc_html__( 'Akismet Tracking', 'stream' ),
@@ -310,21 +388,18 @@
310 388
311 389 array_push( $fields['advanced']['fields'], $akismet_tracking );
312 390 }
313 391
314 - // If WP Cron is enabled, allow Admins to opt-in to WP Cron tracking
315 - if ( wp_stream_is_cron_enabled() ) {
316 - $wp_cron_tracking = array(
317 - 'name' => 'wp_cron_tracking',
318 - 'title' => esc_html__( 'WP Cron Tracking', 'stream' ),
319 - 'type' => 'checkbox',
320 - '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' ),
321 - 'after_field' => esc_html__( 'Enabled', 'stream' ),
322 - 'default' => 0,
323 - );
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 + );
324 400
325 - array_push( $fields['advanced']['fields'], $wp_cron_tracking );
326 - }
401 + array_push( $fields['advanced']['fields'], $wp_cron_tracking );
327 402
328 403 /**
329 404 * Filter allows for modification of options fields
330 405 *
@@ -331,9 +406,9 @@
331 406 * @return array Array of option fields
332 407 */
333 408 $this->fields = apply_filters( 'wp_stream_settings_option_fields', $fields );
334 409
335 - // Sort option fields in each tab by title ASC
410 + // Sort option fields in each tab by title ASC.
336 411 foreach ( $this->fields as $tab => $options ) {
337 412 $titles = array();
338 413
339 414 foreach ( $options['fields'] as $field ) {
@@ -403,9 +478,16 @@
403 478 */
404 479 public function register_settings() {
405 480 $sections = $this->get_fields();
406 481
407 - 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 + );
408 490
409 491 foreach ( $sections as $section_name => $section ) {
410 492 add_settings_section(
411 493 $section_name,
@@ -414,9 +496,10 @@
414 496 $this->option_key
415 497 );
416 498
417 499 foreach ( $section['fields'] as $field_idx => $field ) {
418 - if ( ! isset( $field['type'] ) ) { // No field type associated, skip, no GUI
500 + // No field type associated, skip, no GUI.
501 + if ( ! isset( $field['type'] ) ) {
419 502 continue;
420 503 }
421 504
422 505 add_settings_field(
@@ -421,14 +504,18 @@
421 504
422 505 add_settings_field(
423 506 $field['name'],
424 507 $field['title'],
425 - ( isset( $field['callback'] ) ? $field['callback'] : array( $this, 'output_field' ) ),
508 + ( isset( $field['callback'] ) ? $field['callback'] : array(
509 + $this,
510 + 'output_field',
511 + ) ),
426 512 $this->option_key,
427 513 $section_name,
428 514 $field + array(
429 515 'section' => $section_name,
430 - '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'] ),
517 + // xss ok.
431 518 )
432 519 );
433 520 }
434 521 }
@@ -436,9 +523,9 @@
436 523
437 524 /**
438 525 * Sanitization callback for settings field values before save
439 526 *
440 - * @param array $input
527 + * @param array $input Raw input.
441 528 *
442 529 * @return array
443 530 */
444 531 public function sanitize_settings( $input ) {
@@ -457,9 +544,9 @@
457 544 if ( empty( $type ) || ! isset( $input[ $name ] ) || '' === $input[ $name ] ) {
458 545 continue;
459 546 }
460 547
461 - // Sanitize depending on the type of field
548 + // Sanitize depending on the type of field.
462 549 switch ( $type ) {
463 550 case 'number':
464 551 $output[ $name ] = is_numeric( $input[ $name ] ) ? intval( trim( $input[ $name ] ) ) : '';
465 552 break;
@@ -469,14 +556,17 @@
469 556 default:
470 557 if ( is_array( $input[ $name ] ) ) {
471 558 $output[ $name ] = $input[ $name ];
472 559
473 - // Support all values in multidimentional arrays too
474 - array_walk_recursive( $output[ $name ], function( &$v, $k ) {
475 - $v = trim( $v );
476 - } );
560 + // Support all values in multidimentional arrays too.
561 + array_walk_recursive(
562 + $output[ $name ],
563 + function ( &$v ) {
564 + $v = sanitize_text_field( trim( $v ) );
565 + }
566 + );
477 567 } else {
478 - $output[ $name ] = trim( $input[ $name ] );
568 + $output[ $name ] = sanitize_text_field( trim( $input[ $name ] ) );
479 569 }
480 570 }
481 571 }
482 572 }
@@ -486,9 +576,9 @@
486 576
487 577 /**
488 578 * Compile HTML needed for displaying the field
489 579 *
490 - * @param array $field Field settings
580 + * @param array $field Field settings.
491 581 *
492 582 * @return string HTML to be displayed
493 583 */
494 584 public function render_field( $field ) {
@@ -529,11 +619,9 @@
529 619 if ( ! $type || ! $section || ! $name ) {
530 620 return '';
531 621 }
532 622
533 - if ( 'multi_checkbox' === $type
534 - && ( empty( $field['choices'] ) || ! is_array( $field['choices'] ) )
535 - ) {
623 + if ( 'multi_checkbox' === $type && ( empty( $field['choices'] ) || ! is_array( $field['choices'] ) ) ) {
536 624 return '';
537 625 }
538 626
539 627 switch ( $type ) {
@@ -568,14 +656,22 @@
568 656 wp_kses_post( $after_field )
569 657 );
570 658 break;
571 659 case 'checkbox':
660 + if ( isset( $current_value ) ) {
661 + $value = $current_value;
662 + } elseif ( isset( $default ) ) {
663 + $value = $default;
664 + } else {
665 + $value = 0;
666 + }
667 +
572 668 $output = sprintf(
573 669 '<label><input type="checkbox" name="%1$s[%2$s_%3$s]" id="%1$s[%2$s_%3$s]" value="1" %4$s /> %5$s</label>',
574 670 esc_attr( $option_key ),
575 671 esc_attr( $section ),
576 672 esc_attr( $name ),
577 - checked( $current_value, 1, false ),
673 + checked( $value, 1, false ),
578 674 wp_kses_post( $after_field )
579 675 );
580 676 break;
581 677 case 'multi_checkbox':
@@ -584,10 +680,10 @@
584 680 esc_attr( $option_key ),
585 681 esc_attr( $section ),
586 682 esc_attr( $name )
587 683 );
588 - // Fallback if nothing is selected
589 - $output .= sprintf(
684 + // Fallback if nothing is selected.
685 + $output .= sprintf(
590 686 '<input type="hidden" name="%1$s[%2$s_%3$s][]" value="__placeholder__" />',
591 687 esc_attr( $option_key ),
592 688 esc_attr( $section ),
593 689 esc_attr( $name )
@@ -592,9 +688,9 @@
592 688 esc_attr( $section ),
593 689 esc_attr( $name )
594 690 );
595 691 $current_value = (array) $current_value;
596 - $choices = $field['choices'];
692 + $choices = $field['choices'];
597 693 if ( is_callable( $choices ) ) {
598 694 $choices = call_user_func( $choices );
599 695 }
600 696 foreach ( $choices as $value => $label ) {
@@ -605,9 +701,9 @@
605 701 esc_attr( $option_key ),
606 702 esc_attr( $section ),
607 703 esc_attr( $name ),
608 704 esc_attr( $value ),
609 - checked( in_array( $value, $current_value ), true, false )
705 + checked( in_array( $value, $current_value, true ), true, false )
610 706 ),
611 707 esc_html( $label )
612 708 );
613 709 }
@@ -659,9 +755,9 @@
659 755 esc_attr( $href ),
660 756 esc_attr( $title )
661 757 );
662 758 break;
663 - case 'select2' :
759 + case 'select2':
664 760 if ( ! isset( $current_value ) ) {
665 761 $current_value = '';
666 762 }
667 763
@@ -678,16 +774,26 @@
678 774 $child_values = array();
679 775 if ( isset( $value['children'] ) ) {
680 776 $child_values = array();
681 777 foreach ( $value['children'] as $child_key => $child_value ) {
682 - $child_values[] = array( 'id' => $child_key, 'text' => $child_value );
778 + $child_values[] = array(
779 + 'id' => $child_key,
780 + 'text' => $child_value,
781 + );
683 782 }
684 783 }
685 784 if ( isset( $value['label'] ) ) {
686 - $data_values[] = array( 'id' => $key, 'text' => $value['label'], 'children' => $child_values );
785 + $data_values[] = array(
786 + 'id' => $key,
787 + 'text' => $value['label'],
788 + 'children' => $child_values,
789 + );
687 790 }
688 791 } else {
689 - $data_values[] = array( 'id' => $key, 'text' => $value );
792 + $data_values[] = array(
793 + 'id' => $key,
794 + 'text' => $value,
795 + );
690 796 }
691 797 }
692 798 $class .= ' with-source';
693 799 }
@@ -699,8 +805,9 @@
699 805 esc_attr( $name ),
700 806 esc_attr( wp_stream_json_encode( $data_values ) ),
701 807 esc_attr( $current_value ),
702 808 esc_attr( $class ),
809 + /* translators: %s: the title of the dropdown menu (e.g. "users") */
703 810 sprintf( esc_html__( 'Any %s', 'stream' ), $title )
704 811 );
705 812
706 813 $output = sprintf(
@@ -711,13 +818,15 @@
711 818 $input_html
712 819 );
713 820
714 821 break;
715 - case 'rule_list' :
822 + case 'rule_list':
823 + $users = count_users();
824 + $form = new Form_Generator();
716 825 $output = '<p class="description">' . esc_html( $description ) . '</p>';
717 826
718 - $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' ) );
719 - $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' ) );
827 + $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' ) );
828 + $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' ) );
720 829
721 830 $output .= sprintf( '<div class="tablenav top">%1$s</div>', $actions_top );
722 831 $output .= '<table class="wp-list-table widefat fixed stream-exclude-list">';
723 832
@@ -741,13 +850,18 @@
741 850 );
742 851
743 852 $exclude_rows = array();
744 853
745 - // Prepend an empty row
746 - $current_value['exclude_row'] = array( 'helper' => '' ) + ( isset( $current_value['exclude_row'] ) ? $current_value['exclude_row'] : array() );
854 + // Account for when no rules have been added yet.
855 + if ( ! is_array( $current_value ) ) {
856 + $current_value = array();
857 + }
747 858
859 + // Prepend an empty row.
860 + $current_value['exclude_row'] = ( isset( $current_value['exclude_row'] ) ? $current_value['exclude_row'] : array() ) + array( 'helper' => '' );
861 +
748 862 foreach ( $current_value['exclude_row'] as $key => $value ) {
749 - // Prepare values
863 + // Prepare values.
750 864 $author_or_role = isset( $current_value['author_or_role'][ $key ] ) ? $current_value['author_or_role'][ $key ] : '';
751 865 $connector = isset( $current_value['connector'][ $key ] ) ? $current_value['connector'][ $key ] : '';
752 866 $context = isset( $current_value['context'][ $key ] ) ? $current_value['context'][ $key ] : '';
753 867 $action = isset( $current_value['action'][ $key ] ) ? $current_value['action'][ $key ] : '';
@@ -752,24 +866,27 @@
752 866 $context = isset( $current_value['context'][ $key ] ) ? $current_value['context'][ $key ] : '';
753 867 $action = isset( $current_value['action'][ $key ] ) ? $current_value['action'][ $key ] : '';
754 868 $ip_address = isset( $current_value['ip_address'][ $key ] ) ? $current_value['ip_address'][ $key ] : '';
755 869
756 - // Author or Role dropdown menu
870 + // Author or Role dropdown menu.
757 871 $author_or_role_values = array();
758 872 $author_or_role_selected = array();
759 873
760 874 foreach ( $this->get_roles() as $role_id => $role ) {
761 - $args = array( 'id' => $role_id, 'text' => $role );
762 - $users = count_users();
875 + $args = array(
876 + 'value' => $role_id,
877 + 'text' => $role,
878 + );
763 879 $count = isset( $users['avail_roles'][ $role_id ] ) ? $users['avail_roles'][ $role_id ] : 0;
764 880
765 881 if ( ! empty( $count ) ) {
766 - $args['user_count'] = sprintf( _n( '1 user', '%s users', absint( $count ), 'stream' ), absint( $count ) );
882 + /* translators: %d: a number of users (e.g. "42") */
883 + $args['user_count'] = sprintf( _n( '%d user', '%d users', absint( $count ), 'stream' ), absint( $count ) );
767 884 }
768 885
769 886 if ( $role_id === $author_or_role ) {
770 - $author_or_role_selected['id'] = $role_id;
771 - $author_or_role_selected['text'] = $role;
887 + $author_or_role_selected['value'] = $role_id;
888 + $author_or_role_selected['text'] = $role;
772 889 }
773 890
774 891 $author_or_role_values[] = $args;
775 892 }
@@ -776,25 +893,31 @@
776 893
777 894 if ( empty( $author_or_role_selected ) && is_numeric( $author_or_role ) ) {
778 895 $user = new WP_User( $author_or_role );
779 896 $display_name = ( 0 === $user->ID ) ? esc_html__( 'N/A', 'stream' ) : $user->display_name;
780 - $author_or_role_selected = array( 'id' => $user->ID, 'text' => $display_name );
897 + $author_or_role_selected = array(
898 + 'value' => $user->ID,
899 + 'text' => $display_name,
900 + );
901 + $author_or_role_values[] = $author_or_role_selected;
781 902 }
782 903
783 - $author_or_role_input = sprintf(
784 - '<input type="hidden" name="%1$s[%2$s_%3$s][%4$s][]" data-values=\'%5$s\' data-selected-id=\'%6$s\' data-selected-text=\'%7$s\' value="%6$s" class="select2-select %4$s" data-placeholder="%8$s" data-nonce="%9$s" />',
785 - esc_attr( $option_key ),
786 - esc_attr( $section ),
787 - esc_attr( $name ),
788 - 'author_or_role',
789 - esc_attr( wp_stream_json_encode( $author_or_role_values ) ),
790 - isset( $author_or_role_selected['id'] ) ? esc_attr( $author_or_role_selected['id'] ) : '',
791 - isset( $author_or_role_selected['text'] ) ? esc_attr( $author_or_role_selected['text'] ) : '',
792 - esc_html__( 'Any Author or Role', 'stream' ),
793 - esc_attr( wp_create_nonce( 'stream_get_users' ) )
904 + $author_or_role_input = $form->render_field(
905 + 'select2',
906 + array(
907 + 'name' => esc_attr( sprintf( '%1$s[%2$s_%3$s][%4$s][]', $option_key, $section, $name, 'author_or_role' ) ),
908 + 'options' => $author_or_role_values,
909 + 'classes' => 'author_or_role',
910 + 'data' => array(
911 + 'placeholder' => esc_html__( 'Any Author or Role', 'stream' ),
912 + 'nonce' => esc_attr( wp_create_nonce( 'stream_get_users' ) ),
913 + 'selected-id' => isset( $author_or_role_selected['value'] ) ? esc_attr( $author_or_role_selected['value'] ) : '',
914 + 'selected-text' => isset( $author_or_role_selected['text'] ) ? esc_attr( $author_or_role_selected['text'] ) : '',
915 + ),
916 + )
794 917 );
795 918
796 - // Context dropdown menu
919 + // Context dropdown menu.
797 920 $context_values = array();
798 921
799 922 foreach ( $this->get_terms_labels( 'context' ) as $context_id => $context_data ) {
800 923 if ( is_array( $context_data ) ) {
@@ -801,71 +924,100 @@
801 924 $child_values = array();
802 925 if ( isset( $context_data['children'] ) ) {
803 926 $child_values = array();
804 927 foreach ( $context_data['children'] as $child_id => $child_value ) {
805 - $child_values[] = array( 'id' => $child_id, 'text' => $child_value, 'parent' => $context_id );
928 + $child_values[] = array(
929 + 'value' => $context_id . '-' . $child_id,
930 + 'text' => $child_value,
931 + 'parent' => $context_id,
932 + );
806 933 }
807 934 }
808 935 if ( isset( $context_data['label'] ) ) {
809 - $context_values[] = array( 'id' => $context_id, 'text' => $context_data['label'], 'children' => $child_values );
936 + $context_values[] = array(
937 + 'value' => $context_id,
938 + 'text' => $context_data['label'],
939 + 'children' => $child_values,
940 + );
810 941 }
811 942 } else {
812 - $context_values[] = array( 'id' => $context_id, 'text' => $context_data );
943 + $context_values[] = array(
944 + 'value' => $context_id,
945 + 'text' => $context_data,
946 + );
813 947 }
814 948 }
815 949
816 - $connector_input = sprintf(
817 - '<input type="hidden" name="%1$s[%2$s_%3$s][%4$s][]" class="%4$s" value="%5$s">',
818 - esc_attr( $option_key ),
819 - esc_attr( $section ),
820 - esc_attr( $name ),
821 - esc_attr( 'connector' ),
822 - esc_attr( $connector )
950 + $connector_or_context_input = $form->render_field(
951 + 'select2',
952 + array(
953 + 'name' => esc_attr( sprintf( '%1$s[%2$s_%3$s][%4$s][]', $option_key, $section, $name, 'connector_or_context' ) ),
954 + 'options' => $context_values,
955 + 'classes' => 'connector_or_context',
956 + 'data' => array(
957 + 'group' => 'connector',
958 + 'placeholder' => __( 'Any Context', 'stream' ),
959 + ),
960 + )
823 961 );
824 962
825 - $context_input = sprintf(
826 - '<input type="hidden" name="%1$s[%2$s_%3$s][%4$s][]" data-values=\'%5$s\' value="%6$s" class="select2-select with-source %4$s" data-placeholder="%7$s" data-group="%8$s" />',
827 - esc_attr( $option_key ),
828 - esc_attr( $section ),
829 - esc_attr( $name ),
830 - 'context',
831 - esc_attr( wp_stream_json_encode( $context_values ) ),
832 - esc_attr( $context ),
833 - esc_html__( 'Any Context', 'stream' ),
834 - 'connector'
963 + $connector_input = $form->render_field(
964 + 'hidden',
965 + array(
966 + 'name' => esc_attr( sprintf( '%1$s[%2$s_%3$s][%4$s][]', $option_key, $section, $name, 'connector' ) ),
967 + 'value' => $connector,
968 + 'classes' => 'connector',
969 + )
835 970 );
836 971
837 - // Action dropdown menu
972 + $context_input = $form->render_field(
973 + 'hidden',
974 + array(
975 + 'name' => esc_attr( sprintf( '%1$s[%2$s_%3$s][%4$s][]', $option_key, $section, $name, 'context' ) ),
976 + 'value' => $context,
977 + 'classes' => 'context',
978 + )
979 + );
980 +
981 + // Action dropdown menu.
838 982 $action_values = array();
839 983
840 984 foreach ( $this->get_terms_labels( 'action' ) as $action_id => $action_data ) {
841 - $action_values[] = array( 'id' => $action_id, 'text' => $action_data );
985 + $action_values[] = array(
986 + 'value' => $action_id,
987 + 'text' => $action_data,
988 + );
842 989 }
843 990
844 - $action_input = sprintf(
845 - '<input type="hidden" name="%1$s[%2$s_%3$s][%4$s][]" data-values=\'%5$s\' value="%6$s" class="select2-select with-source %4$s" data-placeholder="%7$s" />',
846 - esc_attr( $option_key ),
847 - esc_attr( $section ),
848 - esc_attr( $name ),
849 - 'action',
850 - esc_attr( wp_stream_json_encode( $action_values ) ),
851 - esc_attr( $action ),
852 - esc_html__( 'Any Action', 'stream' )
991 + $action_input = $form->render_field(
992 + 'select2',
993 + array(
994 + 'name' => esc_attr( sprintf( '%1$s[%2$s_%3$s][%4$s][]', $option_key, $section, $name, 'action' ) ),
995 + 'value' => $action,
996 + 'options' => $action_values,
997 + 'classes' => 'action',
998 + 'data' => array(
999 + 'placeholder' => __( 'Any Action', 'stream' ),
1000 + ),
1001 + )
853 1002 );
854 1003
855 - // IP Address input
856 - $ip_address_input = sprintf(
857 - '<input type="hidden" name="%1$s[%2$s_%3$s][%4$s][]" value="%5$s" class="select2-select %4$s" data-placeholder="%6$s" data-nonce="%7$s" />',
858 - esc_attr( $option_key ),
859 - esc_attr( $section ),
860 - esc_attr( $name ),
861 - 'ip_address',
862 - esc_attr( $ip_address ),
863 - esc_html__( 'Any IP Address', 'stream' ),
864 - esc_attr( wp_create_nonce( 'stream_get_ips' ) )
1004 + // IP Address input.
1005 + $ip_address_input = $form->render_field(
1006 + 'select2',
1007 + array(
1008 + 'name' => esc_attr( sprintf( '%1$s[%2$s_%3$s][%4$s][]', $option_key, $section, $name, 'ip_address' ) ),
1009 + 'value' => $ip_address,
1010 + 'classes' => 'ip_address',
1011 + 'data' => array(
1012 + 'placeholder' => esc_attr__( 'Any IP Address', 'stream' ),
1013 + 'nonce' => esc_attr( wp_create_nonce( 'stream_get_ips' ) ),
1014 + ),
1015 + 'multiple' => true,
1016 + )
865 1017 );
866 1018
867 - // Hidden helper input
1019 + // Hidden helper input.
868 1020 $helper_input = sprintf(
869 1021 '<input type="hidden" name="%1$s[%2$s_%3$s][%4$s][]" value="" />',
870 1022 esc_attr( $option_key ),
871 1023 esc_attr( $section ),
@@ -876,18 +1028,19 @@
876 1028 $exclude_rows[] = sprintf(
877 1029 '<tr class="%1$s %2$s">
878 1030 <th scope="row" class="check-column">%3$s %4$s</th>
879 1031 <td>%5$s</td>
880 - <td>%6$s %7$s</td>
881 - <td>%8$s</td>
1032 + <td>%6$s %7$s %8$s</td>
882 1033 <td>%9$s</td>
883 - <th scope="row" class="actions-column">%10$s</th>
1034 + <td>%10$s</td>
1035 + <th scope="row" class="actions-column">%11$s</th>
884 1036 </tr>',
885 - ( 0 !== $key % 2 ) ? 'alternate' : '',
886 - ( 'helper' === $key ) ? 'hidden helper' : '',
1037 + ( 0 !== (int) $key % 2 ) ? 'alternate' : '',
1038 + ( 'helper' === (string) $key ) ? 'hidden helper' : '',
887 1039 '<input class="cb-select" type="checkbox" />',
888 1040 $helper_input,
889 1041 $author_or_role_input,
1042 + $connector_or_context_input,
890 1043 $connector_input,
891 1044 $context_input,
892 1045 $action_input,
893 1046 $ip_address_input,
@@ -917,9 +1070,9 @@
917 1070
918 1071 /**
919 1072 * Render Callback for post_types field
920 1073 *
921 - * @param array $field
1074 + * @param array $field Field to be rendered.
922 1075 *
923 1076 * @return string
924 1077 */
925 1078 public function output_field( $field ) {
@@ -930,9 +1083,9 @@
930 1083 }
931 1084
932 1085 $output = $this->render_field( $field );
933 1086
934 - echo $output; // xss ok
1087 + echo $output; // xss ok.
935 1088 }
936 1089
937 1090 /**
938 1091 * Get an array of user roles
@@ -952,9 +1105,9 @@
952 1105
953 1106 /**
954 1107 * Function will return all terms labels of given column
955 1108 *
956 - * @param string $column string Name of the column
1109 + * @param string $column Name of the column.
957 1110 *
958 1111 * @return array
959 1112 */
960 1113 public function get_terms_labels( $column ) {
@@ -987,14 +1140,14 @@
987 1140 * Remove records when records TTL is shortened
988 1141 *
989 1142 * @action update_option_wp_stream
990 1143 *
991 - * @param array $old_value
992 - * @param array $new_value
1144 + * @param array $old_value Old value.
1145 + * @param array $new_value New value.
993 1146 */
994 1147 public function updated_option_ttl_remove_records( $old_value, $new_value ) {
995 - $ttl_before = isset( $old_value['general_records_ttl'] ) ? (int) $old_value['general_records_ttl'] : -1;
996 - $ttl_after = isset( $new_value['general_records_ttl'] ) ? (int) $new_value['general_records_ttl'] : -1;
1148 + $ttl_before = isset( $old_value['general_records_ttl'] ) ? (int) $old_value['general_records_ttl'] : - 1;
1149 + $ttl_after = isset( $new_value['general_records_ttl'] ) ? (int) $new_value['general_records_ttl'] : - 1;
997 1150
998 1151 if ( $ttl_after < $ttl_before ) {
999 1152 /**
1000 1153 * Action assists in purging when TTL is shortened
@@ -1006,8 +1159,10 @@
1006 1159 /**
1007 1160 * Get translations of serialized Stream settings
1008 1161 *
1009 1162 * @filter wp_stream_serialized_labels
1163 + *
1164 + * @param array $labels Setting labels.
1010 1165 *
1011 1166 * @return array Multidimensional array of fields
1012 1167 */
1013 1168 public function get_settings_translations( $labels ) {