PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 16.3-a.7
Jetpack – WP Security, Backup, Speed, & Growth v16.3-a.7
16.3-a.5 16.3-a.7 16.3-a.3 16.3-a.1 16.2 16.2-beta 12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 13.7.2 13.8.3 All 506 releases
jetpack / jetpack_vendor / automattic / jetpack-stats / src / class-settings.php

class-settings.php in Jetpack – WP Security, Backup, Speed, & Growth 16.3-a.7, at jetpack_vendor/automattic/jetpack-stats/src/class-settings.php

177 lines 5.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * The Stats settings a site owner can change.
4 *
5 * @package automattic/jetpack-stats
6 */
7
8 namespace Automattic\Jetpack\Stats;
9
10 use WP_Error;
11
12 /**
13 * Reads and validates changes to the owner-facing keys of `stats_options`.
14 */
15 class Settings {
16 const ERROR_PREFIX = 'jetpack_stats_';
17
18 /**
19 * The `stats_options` keys a site owner can change. Each key's type comes from `Options::get_defaults()`.
20 *
21 * @var string[]
22 */
23 const KEYS = array( 'admin_bar', 'roles', 'count_roles', 'do_not_track' );
24
25 /**
26 * Get the current values of some `stats_options` keys.
27 *
28 * @param string[] $keys The keys to read.
29 * @return array
30 */
31 public static function get( array $keys ): array {
32 $options = Options::get_options();
33 $defaults = Options::get_defaults();
34 $out = array();
35 foreach ( $keys as $key ) {
36 $raw = $options[ $key ] ?? null;
37 $default = $defaults[ $key ] ?? null;
38 if ( is_bool( $default ) ) {
39 $out[ $key ] = (bool) $raw;
40 } elseif ( is_array( $default ) ) {
41 $out[ $key ] = is_array( $raw ) ? array_values( $raw ) : array();
42 } else {
43 $out[ $key ] = $raw;
44 }
45 }
46 return $out;
47 }
48
49 /**
50 * Validate new values and save the ones that change.
51 *
52 * @param array $values New values, keyed by `stats_options` key.
53 * @param string[] $keys The keys the caller may change.
54 * @return array|WP_Error `changed` and the `settings` after the save, or why the values were refused.
55 */
56 public static function update( array $values, array $keys ) {
57 $unknown = array_diff( $keys, self::KEYS );
58 if ( ! empty( $unknown ) ) {
59 return new WP_Error(
60 self::ERROR_PREFIX . 'unknown_setting',
61 sprintf(
62 /* translators: %s: comma-separated list of setting names. */
63 __( 'Unknown Stats settings: %s.', 'jetpack-stats-pkg' ),
64 implode( ', ', $unknown )
65 )
66 );
67 }
68
69 $provided = array_intersect_key( $values, array_flip( $keys ) );
70 if ( empty( $provided ) ) {
71 return new WP_Error(
72 self::ERROR_PREFIX . 'missing_setting_field',
73 sprintf(
74 /* translators: %s: comma-separated list of writable field names. */
75 __( 'Provide at least one of: %s.', 'jetpack-stats-pkg' ),
76 implode( ', ', $keys )
77 )
78 );
79 }
80
81 $defaults = Options::get_defaults();
82 $before = self::get( $keys );
83 $known_roles = null;
84 foreach ( $keys as $role_field ) {
85 if ( ! array_key_exists( $role_field, $provided ) ) {
86 continue;
87 }
88 if ( ! is_array( $defaults[ $role_field ] ?? null ) ) {
89 continue;
90 }
91 if ( null === $known_roles ) {
92 $known_roles = array_keys( wp_roles()->roles );
93 }
94 if ( ! is_array( $provided[ $role_field ] ) ) {
95 return new WP_Error(
96 self::ERROR_PREFIX . 'invalid_' . $role_field,
97 sprintf(
98 /* translators: %s: the offending field name. */
99 __( 'Field `%s` must be an array of role slugs.', 'jetpack-stats-pkg' ),
100 $role_field
101 )
102 );
103 }
104 // Direct PHP callers skip the REST schema's `minItems` check.
105 if ( 'roles' === $role_field && empty( $provided[ $role_field ] ) ) {
106 return new WP_Error(
107 self::ERROR_PREFIX . 'invalid_roles',
108 __( 'Field `roles` must be a non-empty array of role slugs.', 'jetpack-stats-pkg' )
109 );
110 }
111 $sanitized = array();
112 foreach ( $provided[ $role_field ] as $role ) {
113 if ( ! is_string( $role ) || '' === $role ) {
114 return new WP_Error(
115 self::ERROR_PREFIX . 'invalid_role',
116 sprintf(
117 /* translators: 1: field name, 2: comma-separated list of valid role slugs. */
118 __( 'Role slugs in `%1$s` must be non-empty strings. Known roles: %2$s.', 'jetpack-stats-pkg' ),
119 $role_field,
120 implode( ', ', $known_roles )
121 )
122 );
123 }
124 if ( ! in_array( $role, $known_roles, true ) && ! in_array( $role, $before[ $role_field ], true ) ) {
125 return new WP_Error(
126 self::ERROR_PREFIX . 'invalid_role',
127 sprintf(
128 /* translators: 1: unknown role slug, 2: field name, 3: comma-separated list of valid role slugs. */
129 __( 'Unknown role `%1$s` in `%2$s`. Known roles: %3$s.', 'jetpack-stats-pkg' ),
130 $role,
131 $role_field,
132 implode( ', ', $known_roles )
133 )
134 );
135 }
136 $sanitized[] = $role;
137 }
138 // Administrators keep `view_stats`, because the screen that changes this list needs it.
139 if ( 'roles' === $role_field && ! in_array( 'administrator', $sanitized, true ) ) {
140 array_unshift( $sanitized, 'administrator' );
141 }
142 $provided[ $role_field ] = array_values( array_unique( $sanitized ) );
143 }
144
145 $changes = array();
146 foreach ( $provided as $key => $value ) {
147 if ( is_bool( $defaults[ $key ] ?? null ) ) {
148 $value = (bool) $value;
149 }
150 $current = $before[ $key ] ?? null;
151 if ( $current === $value ) {
152 continue;
153 }
154 $changes[ $key ] = $value;
155 }
156
157 if ( ! empty( $changes ) ) {
158 Options::set_options( $changes );
159 }
160
161 $after = self::get( $keys );
162 foreach ( $changes as $key => $value ) {
163 if ( $after[ $key ] !== $value ) {
164 return new WP_Error(
165 self::ERROR_PREFIX . 'save_failed',
166 __( 'The Stats settings could not be saved.', 'jetpack-stats-pkg' )
167 );
168 }
169 }
170
171 return array(
172 'changed' => $after !== $before,
173 'settings' => $after,
174 );
175 }
176 }
177