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 +154 -98 3.2.34.0.2 View file →
@@ -1,16 +1,25 @@
1 1 <?php
2 +/**
3 + * Renders and manages the plugin Settings page.
4 + *
5 + * @package WP_Stream
6 + */
2 7
3 8 namespace WP_Stream;
4 9
5 -use \WP_Roles;
6 -use \WP_User;
7 -use \WP_User_Query;
10 +use WP_Roles;
11 +use WP_User;
12 +use WP_User_Query;
8 13
14 +/**
15 + * Class - Settings
16 + */
9 17 class Settings {
10 18
11 19 /**
12 - * Hold Plugin class
20 + * Holds instance of plugin object
21 + *
13 22 * @var Plugin
14 23 */
15 24 public $plugin;
16 25
@@ -44,9 +53,9 @@
44 53
45 54 /**
46 55 * Class constructor.
47 56 *
48 - * @param Plugin $plugin The main Plugin class.
57 + * @param Plugin $plugin Instance of plugin object.
49 58 */
50 59 public function __construct( $plugin ) {
51 60 $this->plugin = $plugin;
52 61
@@ -52,31 +61,35 @@
52 61
53 62 $this->option_key = $this->get_option_key();
54 63 $this->options = $this->get_options();
55 64
56 - // Register settings, and fields
65 + // Register settings, and fields.
57 66 add_action( 'admin_init', array( $this, 'register_settings' ) );
58 67
59 - // Remove records when records TTL is shortened
68 + // Remove records when records TTL is shortened.
60 69 add_action(
61 - 'update_option_' . $this->option_key, array(
70 + 'update_option_' . $this->option_key,
71 + array(
62 72 $this,
63 73 'updated_option_ttl_remove_records',
64 - ), 10, 2
74 + ),
75 + 10,
76 + 2
65 77 );
66 78
67 - // Apply label translations for settings
79 + // Apply label translations for settings.
68 80 add_filter(
69 - 'wp_stream_serialized_labels', array(
81 + 'wp_stream_serialized_labels',
82 + array(
70 83 $this,
71 84 'get_settings_translations',
72 85 )
73 86 );
74 87
75 - // Ajax callback function to search users
88 + // Ajax callback function to search users.
76 89 add_action( 'wp_ajax_stream_get_users', array( $this, 'get_users' ) );
77 90
78 - // Ajax callback function to search IPs
91 + // Ajax callback function to search IPs.
79 92 add_action( 'wp_ajax_stream_get_ips', array( $this, 'get_ips' ) );
80 93 }
81 94
82 95 /**
@@ -107,12 +120,15 @@
107 120 'find' => $search,
108 121 );
109 122
110 123 add_filter(
111 - 'user_search_columns', array(
124 + 'user_search_columns',
125 + array(
112 126 $this,
113 127 'add_display_name_search_columns',
114 - ), 10, 3
128 + ),
129 + 10,
130 + 3
115 131 );
116 132
117 133 $users = new WP_User_Query(
118 134 array(
@@ -128,12 +144,14 @@
128 144 )
129 145 );
130 146
131 147 remove_filter(
132 - 'user_search_columns', array(
148 + 'user_search_columns',
149 + array(
133 150 $this,
134 151 'add_display_name_search_columns',
135 - ), 10
152 + ),
153 + 10
136 154 );
137 155
138 156 if ( 0 === $users->get_total() ) {
139 157 wp_send_json_error( $response );
@@ -154,9 +172,9 @@
154 172 $response->users = array();
155 173 $users_added_to_response = array();
156 174
157 175 foreach ( $users_array as $key => $user ) {
158 - // exclude duplications:
176 + // exclude duplications.
159 177 if ( array_key_exists( $user->ID, $users_added_to_response ) ) {
160 178 continue;
161 179 } else {
162 180 $users_added_to_response[ $user->ID ] = true;
@@ -170,9 +188,9 @@
170 188 );
171 189
172 190 $args['tooltip'] = esc_attr(
173 191 sprintf(
174 - // translators: Placeholders refers to a user ID, a username, an email address, and a user role (e.g. "42", "administrator", "foo@bar.com", "subscriber").
192 + /* translators: %1$d: user ID, %2$s: username, %3$s: email, %4$s: user role (e.g. "42", "administrator", "foo@bar.com", "subscriber") */
175 193 __( 'ID: %1$d\nUser: %2$s\nEmail: %3$s\nRole: %4$s', 'stream' ),
176 194 $author->id,
177 195 $author->user_login,
178 196 $author->user_email,
@@ -356,9 +374,9 @@
356 374 ),
357 375 ),
358 376 );
359 377
360 - // 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.
361 379 if ( class_exists( 'Akismet' ) ) {
362 380 $akismet_tracking = array(
363 381 'name' => 'akismet_tracking',
364 382 'title' => esc_html__( 'Akismet Tracking', 'stream' ),
@@ -370,21 +388,18 @@
370 388
371 389 array_push( $fields['advanced']['fields'], $akismet_tracking );
372 390 }
373 391
374 - // If WP Cron is enabled, allow Admins to opt-in to WP Cron tracking
375 - if ( wp_stream_is_cron_enabled() ) {
376 - $wp_cron_tracking = array(
377 - 'name' => 'wp_cron_tracking',
378 - 'title' => esc_html__( 'WP Cron Tracking', 'stream' ),
379 - 'type' => 'checkbox',
380 - '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' ),
381 - 'after_field' => esc_html__( 'Enabled', 'stream' ),
382 - 'default' => 0,
383 - );
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 + );
384 400
385 - array_push( $fields['advanced']['fields'], $wp_cron_tracking );
386 - }
401 + array_push( $fields['advanced']['fields'], $wp_cron_tracking );
387 402
388 403 /**
389 404 * Filter allows for modification of options fields
390 405 *
@@ -391,9 +406,9 @@
391 406 * @return array Array of option fields
392 407 */
393 408 $this->fields = apply_filters( 'wp_stream_settings_option_fields', $fields );
394 409
395 - // Sort option fields in each tab by title ASC
410 + // Sort option fields in each tab by title ASC.
396 411 foreach ( $this->fields as $tab => $options ) {
397 412 $titles = array();
398 413
399 414 foreach ( $options['fields'] as $field ) {
@@ -464,9 +479,11 @@
464 479 public function register_settings() {
465 480 $sections = $this->get_fields();
466 481
467 482 register_setting(
468 - $this->option_key, $this->option_key, array(
483 + $this->option_key,
484 + $this->option_key,
485 + array(
469 486 $this,
470 487 'sanitize_settings',
471 488 )
472 489 );
@@ -479,9 +496,10 @@
479 496 $this->option_key
480 497 );
481 498
482 499 foreach ( $section['fields'] as $field_idx => $field ) {
483 - if ( ! isset( $field['type'] ) ) { // No field type associated, skip, no GUI
500 + // No field type associated, skip, no GUI.
501 + if ( ! isset( $field['type'] ) ) {
484 502 continue;
485 503 }
486 504
487 505 add_settings_field(
@@ -495,9 +513,8 @@
495 513 $section_name,
496 514 $field + array(
497 515 'section' => $section_name,
498 516 'label_for' => sprintf( '%s_%s_%s', $this->option_key, $section_name, $field['name'] ),
499 - // xss ok
500 517 )
501 518 );
502 519 }
503 520 }
@@ -505,9 +522,9 @@
505 522
506 523 /**
507 524 * Sanitization callback for settings field values before save
508 525 *
509 - * @param array $input
526 + * @param array $input Raw input.
510 527 *
511 528 * @return array
512 529 */
513 530 public function sanitize_settings( $input ) {
@@ -526,40 +543,56 @@
526 543 if ( empty( $type ) || ! isset( $input[ $name ] ) || '' === $input[ $name ] ) {
527 544 continue;
528 545 }
529 546
530 - // Sanitize depending on the type of field.
531 - switch ( $type ) {
532 - case 'number':
533 - $output[ $name ] = is_numeric( $input[ $name ] ) ? intval( trim( $input[ $name ] ) ) : '';
534 - break;
535 - case 'checkbox':
536 - $output[ $name ] = is_numeric( $input[ $name ] ) ? absint( trim( $input[ $name ] ) ) : '';
537 - break;
538 - default:
539 - if ( is_array( $input[ $name ] ) ) {
540 - $output[ $name ] = $input[ $name ];
547 + $output[ $name ] = $this->sanitize_setting_by_field_type( $input[ $name ], $type );
548 + }
549 + }
541 550
542 - // Support all values in multidimentional arrays too.
543 - array_walk_recursive(
544 - $output[ $name ], function ( &$v, $k ) {
545 - $v = trim( $v );
546 - }
547 - );
548 - } else {
549 - $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 ) );
550 581 }
582 + );
583 + } else {
584 + $sanitized_value = sanitize_text_field( trim( $value ) );
551 585 }
552 - }
553 586 }
554 587
555 - return $output;
588 + return $sanitized_value;
556 589 }
557 590
558 591 /**
559 592 * Compile HTML needed for displaying the field
560 593 *
561 - * @param array $field Field settings
594 + * @param array $field Field settings.
562 595 *
563 596 * @return string HTML to be displayed
564 597 */
565 598 public function render_field( $field ) {
@@ -582,14 +615,12 @@
582 615 $nonce = isset( $field['nonce'] ) ? $field['nonce'] : null;
583 616
584 617 if ( isset( $field['value'] ) ) {
585 618 $current_value = $field['value'];
619 + } elseif ( isset( $this->options[ $section . '_' . $name ] ) ) {
620 + $current_value = $this->options[ $section . '_' . $name ];
586 621 } else {
587 - if ( isset( $this->options[ $section . '_' . $name ] ) ) {
588 - $current_value = $this->options[ $section . '_' . $name ];
589 - } else {
590 - $current_value = null;
591 - }
622 + $current_value = null;
592 623 }
593 624
594 625 $option_key = $this->option_key;
595 626
@@ -783,12 +814,12 @@
783 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" />',
784 815 esc_attr( $option_key ),
785 816 esc_attr( $section ),
786 817 esc_attr( $name ),
787 - esc_attr( wp_stream_json_encode( $data_values ) ),
818 + esc_attr( wp_json_encode( $data_values ) ),
788 819 esc_attr( $current_value ),
789 820 esc_attr( $class ),
790 - // translators: Placeholder refers to the title of the dropdown menu (e.g. "users")
821 + /* translators: %s: the title of the dropdown menu (e.g. "users") */
791 822 sprintf( esc_html__( 'Any %s', 'stream' ), $title )
792 823 );
793 824
794 825 $output = sprintf(
@@ -831,10 +862,15 @@
831 862 );
832 863
833 864 $exclude_rows = array();
834 865
866 + // Account for when no rules have been added yet.
867 + if ( ! is_array( $current_value ) ) {
868 + $current_value = array();
869 + }
870 +
835 871 // Prepend an empty row.
836 - $current_value['exclude_row'] = array( 'helper' => '' ) + ( isset( $current_value['exclude_row'] ) ? $current_value['exclude_row'] : array() );
872 + $current_value['exclude_row'] = ( isset( $current_value['exclude_row'] ) ? $current_value['exclude_row'] : array() ) + array( 'helper' => '' );
837 873
838 874 foreach ( $current_value['exclude_row'] as $key => $value ) {
839 875 // Prepare values.
840 876 $author_or_role = isset( $current_value['author_or_role'][ $key ] ) ? $current_value['author_or_role'][ $key ] : '';
@@ -842,9 +878,9 @@
842 878 $context = isset( $current_value['context'][ $key ] ) ? $current_value['context'][ $key ] : '';
843 879 $action = isset( $current_value['action'][ $key ] ) ? $current_value['action'][ $key ] : '';
844 880 $ip_address = isset( $current_value['ip_address'][ $key ] ) ? $current_value['ip_address'][ $key ] : '';
845 881
846 - // Author or Role dropdown menu
882 + // Author or Role dropdown menu.
847 883 $author_or_role_values = array();
848 884 $author_or_role_selected = array();
849 885
850 886 foreach ( $this->get_roles() as $role_id => $role ) {
@@ -854,9 +890,9 @@
854 890 );
855 891 $count = isset( $users['avail_roles'][ $role_id ] ) ? $users['avail_roles'][ $role_id ] : 0;
856 892
857 893 if ( ! empty( $count ) ) {
858 - // translators: Placeholder refers to a number of users (e.g. "42")
894 + /* translators: %d: a number of users (e.g. "42") */
859 895 $args['user_count'] = sprintf( _n( '%d user', '%d users', absint( $count ), 'stream' ), absint( $count ) );
860 896 }
861 897
862 898 if ( $role_id === $author_or_role ) {
@@ -877,22 +913,25 @@
877 913 $author_or_role_values[] = $author_or_role_selected;
878 914 }
879 915
880 916 $author_or_role_input = $form->render_field(
881 - 'select2', array(
917 + 'select2',
918 + array(
882 919 'name' => esc_attr( sprintf( '%1$s[%2$s_%3$s][%4$s][]', $option_key, $section, $name, 'author_or_role' ) ),
883 920 'options' => $author_or_role_values,
884 921 'classes' => 'author_or_role',
922 + // Data attributes are escaped in Form_Generator::prepare_data_attributes_string().
885 923 'data' => array(
886 - 'placeholder' => esc_html__( 'Any Author or Role', 'stream' ),
887 - 'nonce' => esc_attr( wp_create_nonce( 'stream_get_users' ) ),
888 - 'selected-id' => isset( $author_or_role_selected['value'] ) ? esc_attr( $author_or_role_selected['value'] ) : '',
889 - 'selected-text' => isset( $author_or_role_selected['text'] ) ? esc_attr( $author_or_role_selected['text'] ) : '',
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'] : '',
890 928 ),
891 - )
929 + ),
930 + false
892 931 );
893 932
894 - // Context dropdown menu
933 + // Context dropdown menu.
895 934 $context_values = array();
896 935
897 936 foreach ( $this->get_terms_labels( 'context' ) as $context_id => $context_data ) {
898 937 if ( is_array( $context_data ) ) {
@@ -922,36 +961,43 @@
922 961 }
923 962 }
924 963
925 964 $connector_or_context_input = $form->render_field(
926 - 'select2', array(
965 + 'select2',
966 + array(
927 967 'name' => esc_attr( sprintf( '%1$s[%2$s_%3$s][%4$s][]', $option_key, $section, $name, 'connector_or_context' ) ),
928 968 'options' => $context_values,
929 969 'classes' => 'connector_or_context',
970 + // Data attributes are escaped in Form_Generator::prepare_data_attributes_string().
930 971 'data' => array(
931 972 'group' => 'connector',
932 973 'placeholder' => __( 'Any Context', 'stream' ),
933 974 ),
934 - )
975 + ),
976 + false
935 977 );
936 978
937 979 $connector_input = $form->render_field(
938 - 'hidden', array(
980 + 'hidden',
981 + array(
939 982 'name' => esc_attr( sprintf( '%1$s[%2$s_%3$s][%4$s][]', $option_key, $section, $name, 'connector' ) ),
940 983 'value' => $connector,
941 984 'classes' => 'connector',
942 - )
985 + ),
986 + false
943 987 );
944 988
945 989 $context_input = $form->render_field(
946 - 'hidden', array(
990 + 'hidden',
991 + array(
947 992 'name' => esc_attr( sprintf( '%1$s[%2$s_%3$s][%4$s][]', $option_key, $section, $name, 'context' ) ),
948 993 'value' => $context,
949 994 'classes' => 'context',
950 - )
995 + ),
996 + false
951 997 );
952 998
953 - // Action dropdown menu
999 + // Action dropdown menu.
954 1000 $action_values = array();
955 1001
956 1002 foreach ( $this->get_terms_labels( 'action' ) as $action_id => $action_data ) {
957 1003 $action_values[] = array(
@@ -960,34 +1006,40 @@
960 1006 );
961 1007 }
962 1008
963 1009 $action_input = $form->render_field(
964 - 'select2', array(
1010 + 'select2',
1011 + array(
965 1012 'name' => esc_attr( sprintf( '%1$s[%2$s_%3$s][%4$s][]', $option_key, $section, $name, 'action' ) ),
966 1013 'value' => $action,
967 1014 'options' => $action_values,
968 1015 'classes' => 'action',
1016 + // Data attributes are escaped in Form_Generator::prepare_data_attributes_string().
969 1017 'data' => array(
970 1018 'placeholder' => __( 'Any Action', 'stream' ),
971 1019 ),
972 - )
1020 + ),
1021 + false
973 1022 );
974 1023
975 - // IP Address input
1024 + // IP Address input.
976 1025 $ip_address_input = $form->render_field(
977 - 'select2', array(
1026 + 'select2',
1027 + array(
978 1028 'name' => esc_attr( sprintf( '%1$s[%2$s_%3$s][%4$s][]', $option_key, $section, $name, 'ip_address' ) ),
979 1029 'value' => $ip_address,
980 1030 'classes' => 'ip_address',
1031 + // Data attributes are escaped in Form_Generator::prepare_data_attributes_string().
981 1032 'data' => array(
982 - 'placeholder' => esc_attr__( 'Any IP Address', 'stream' ),
983 - 'nonce' => esc_attr( wp_create_nonce( 'stream_get_ips' ) ),
1033 + 'placeholder' => __( 'Any IP Address', 'stream' ),
1034 + 'nonce' => wp_create_nonce( 'stream_get_ips' ),
984 1035 ),
985 1036 'multiple' => true,
986 - )
1037 + ),
1038 + false
987 1039 );
988 1040
989 - // Hidden helper input
1041 + // Hidden helper input.
990 1042 $helper_input = sprintf(
991 1043 '<input type="hidden" name="%1$s[%2$s_%3$s][%4$s][]" value="" />',
992 1044 esc_attr( $option_key ),
993 1045 esc_attr( $section ),
@@ -1001,9 +1053,11 @@
1001 1053 <td>%5$s</td>
1002 1054 <td>%6$s %7$s %8$s</td>
1003 1055 <td>%9$s</td>
1004 1056 <td>%10$s</td>
1005 - <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>
1006 1060 </tr>',
1007 1061 ( 0 !== (int) $key % 2 ) ? 'alternate' : '',
1008 1062 ( 'helper' === (string) $key ) ? 'hidden helper' : '',
1009 1063 '<input class="cb-select" type="checkbox" />',
@@ -1013,9 +1067,9 @@
1013 1067 $connector_input,
1014 1068 $context_input,
1015 1069 $action_input,
1016 1070 $ip_address_input,
1017 - '<a href="#" class="exclude_rules_remove_rule_row">Delete</a>'
1071 + esc_html__( 'Delete', 'stream' )
1018 1072 );
1019 1073 }
1020 1074
1021 1075 $no_rules_found_row = sprintf(
@@ -1040,9 +1094,9 @@
1040 1094
1041 1095 /**
1042 1096 * Render Callback for post_types field
1043 1097 *
1044 - * @param array $field
1098 + * @param array $field Field to be rendered.
1045 1099 *
1046 1100 * @return string
1047 1101 */
1048 1102 public function output_field( $field ) {
@@ -1053,9 +1107,9 @@
1053 1107 }
1054 1108
1055 1109 $output = $this->render_field( $field );
1056 1110
1057 - echo $output; // xss ok
1111 + echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1058 1112 }
1059 1113
1060 1114 /**
1061 1115 * Get an array of user roles
@@ -1075,9 +1129,9 @@
1075 1129
1076 1130 /**
1077 1131 * Function will return all terms labels of given column
1078 1132 *
1079 - * @param string $column string Name of the column
1133 + * @param string $column Name of the column.
1080 1134 *
1081 1135 * @return array
1082 1136 */
1083 1137 public function get_terms_labels( $column ) {
@@ -1110,10 +1164,10 @@
1110 1164 * Remove records when records TTL is shortened
1111 1165 *
1112 1166 * @action update_option_wp_stream
1113 1167 *
1114 - * @param array $old_value
1115 - * @param array $new_value
1168 + * @param array $old_value Old value.
1169 + * @param array $new_value New value.
1116 1170 */
1117 1171 public function updated_option_ttl_remove_records( $old_value, $new_value ) {
1118 1172 $ttl_before = isset( $old_value['general_records_ttl'] ) ? (int) $old_value['general_records_ttl'] : - 1;
1119 1173 $ttl_after = isset( $new_value['general_records_ttl'] ) ? (int) $new_value['general_records_ttl'] : - 1;
@@ -1129,8 +1183,10 @@
1129 1183 /**
1130 1184 * Get translations of serialized Stream settings
1131 1185 *
1132 1186 * @filter wp_stream_serialized_labels
1187 + *
1188 + * @param array $labels Setting labels.
1133 1189 *
1134 1190 * @return array Multidimensional array of fields
1135 1191 */
1136 1192 public function get_settings_translations( $labels ) {