PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 16.1-beta.2
Jetpack – WP Security, Backup, Speed, & Growth v16.1-beta.2
16.2-a.3 16.1.2 16.2-a.1 16.1.1 16.1 16.1-beta 16.1-beta.2 16.1-beta.3 16.1-a.5 16.1-a.3 16.0.1 16.1-a.1 16.0 16.0-beta 16.0-a.7 16.0-a.5 15.9.1 16.0-a.3 16.0-a.1 15.9 15.9-beta 15.9-a.7 15.9-a.5 15.9-a.3 15.9-a.1 15.8 15.8-beta 15.8-a.7 15.8-a.5 5.2.5 5.3.4 5.4.4 5.5.5 5.6.5 5.7.5 5.8.4 5.9.4 6.0.4 6.1 6.1.1 6.1.2 6.1.3 6.1.4 6.1.5 6.2 6.2.1 6.2.2 6.2.3 6.2.4 6.2.5 6.3 6.3.1 6.3.2 6.3.3 6.3.4 6.3.5 6.3.6 6.3.7 6.4 6.4.1 6.4.2 6.4.3 6.4.4 6.4.5 6.4.6 6.5 6.5.1 6.5.2 6.5.3 6.5.4 6.6 6.6.1 6.6.2 6.6.3 6.6.4 6.6.5 6.7 6.7.1 6.7.2 6.7.3 6.7.4 6.8 6.8.1 6.8.2 6.8.3 6.8.4 6.8.5 6.9 6.9.1 6.9.2 6.9.3 6.9.4 7.0 7.0.1 7.0.2 7.0.3 7.0.4 7.0.5 7.1 7.1.1 7.1.2 7.1.3 7.1.4 7.1.5 7.2 7.2.1 7.2.1.1 7.2.2 7.2.3 7.2.4 7.2.5 7.3 7.3.0.1 7.3.1 7.3.1.1 7.3.2 7.3.3 7.3.4 7.3.5 7.4 7.4.1 7.4.2 7.4.3 7.4.4 7.4.5 7.5 7.5.0.1 7.5.1 7.5.2 7.5.3 7.5.4 7.5.5 7.5.6 7.5.7 7.6 7.6.1 7.6.2 7.6.3 7.6.4 7.7 7.7.1 7.7.2 7.7.3 7.7.4 7.7.5 7.7.6 7.8 7.8.1 7.8.2 7.8.3 7.8.4 7.9 7.9.1 7.9.2 7.9.3 7.9.4 8.0 8.0.1 8.0.2 8.0.3 8.1 8.1.1 8.1.2 8.1.3 8.1.4 8.2 8.2.0.1 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.2.6 8.3 8.3.1 8.3.2 8.3.3 8.4 8.4.1 8.4.2 8.4.3 8.4.4 8.4.5 8.5 8.5.1 8.5.2 8.5.3 8.6 8.6.1 8.6.2 8.6.3 8.6.4 8.7 8.7.0.1 8.7.1 8.7.2 8.7.3 8.7.4 8.8 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.9 8.9.1 8.9.2 8.9.3 8.9.4 9.0 9.0.1 9.0.2 9.0.3 9.0.4 9.0.5 9.1 9.1.1 9.1.2 9.1.3 9.2 9.2.1 9.2.2 9.2.3 9.2.4 9.3 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.4 9.4.1 9.4.2 9.4.3 9.4.4 9.5 9.5.1 9.5.2 9.5.3 9.5.4 9.5.5 9.6 9.6.1 9.6.2 9.6.3 9.6.4 9.7 9.7.1 9.7.2 15.7-beta.2 9.7.3 15.7.1 9.8 15.8-a.1 9.8.1 15.8-a.3 9.8.2 2.0.9 9.8.3 2.1.7 9.9 2.2.10 9.9.1 2.3.10 9.9.2 2.4.7 9.9.3 2.5.5 2.6.6 2.7.5 2.8.5 2.9.6 3.0.6 3.1.5 3.2.5 3.3.6 3.4.6 3.5.6 3.6.4 3.7.5 3.8.5 3.9.10 4.0.7 4.1.4 4.2.5 4.3.5 4.4.5 4.5.3 4.6.3 4.7.4 4.8.5 4.9.3 5.0.3 5.1.4 trunk 10.0 10.0.1 10.0.2 10.1 10.1.1 10.1.2 10.2 10.2.1 10.2.2 10.2.3 10.3 10.3.1 10.3.2 10.4 10.4.1 10.4.2 10.5 10.5.1 10.5.2 10.5.3 10.6 10.6.1 10.6.2 10.7 10.7.1 10.7.2 10.8 10.8.1 10.8.2 10.9 10.9.1 10.9.2 10.9.3 11.0 11.0.1 11.0.2 11.1 11.1.1 11.1.2 11.1.3 11.1.4 11.2 11.2.1 11.2.2 11.3 11.3.1 11.3.2 11.3.3 11.3.4 11.4 11.4.1 11.4.2 11.5 11.5.1 11.5.2 11.5.3 11.6 11.6.1 11.6.2 11.7 11.7.1 11.7.2 11.7.3 11.8 11.8.3 11.8.4 11.8.5 11.8.6 11.9 11.9.1 11.9.2 11.9.3 12.0 12.0.1 12.0.2 12.1 12.1.1 12.1.2 12.2 12.2.1 12.2.2 12.3 12.3.1 12.4 12.4.1 12.5 12.5.1 12.6 12.6.1 12.6.2 12.6.3 12.7 12.7.1 12.7.2 12.8 12.8.1 12.8.2 12.9 12.9.1 12.9.2 12.9.3 12.9.4 13.0 13.0.1 13.1 13.1.1 13.1.2 13.1.3 13.1.4 13.2 13.2.1 13.2.2 13.2.3 13.3 13.3.1 13.3.2 13.4 13.4.1 13.4.2 13.4.3 13.4.4 13.5 13.5.1 13.6 13.6.1 13.7 13.7.1 13.8 13.8.1 13.8.2 13.9 13.9.1 14.0 14.1 14.2 14.2.1 14.3 14.4 14.4.1 14.5 14.6 14.7 14.8 14.9 14.9.1 15.0 15.0.1 15.0.2 15.1 15.1.1 15.2 15.3 15.3.1 15.4 15.5 15.6 15.7 15.7-a.1 15.7-a.3 15.7-a.5 15.7-a.7 15.7-beta
jetpack / jetpack_vendor / automattic / jetpack-agents-manager / src / class-open-state-store.php
jetpack / jetpack_vendor / automattic / jetpack-agents-manager / src Last commit date
js 3 weeks ago class-agents-manager.php 3 weeks ago class-open-state-store.php 2 months ago class-sidebar-open-preservation.php 3 weeks ago class-wp-rest-agents-manager-persisted-open-state.php 2 months ago class-wp-rest-jetpack-ai-jwt.php 2 months ago
class-open-state-store.php
205 lines
1 <?php
2 /**
3 * Open_State_Store file.
4 *
5 * @package automattic/jetpack-agents-manager
6 */
7
8 namespace Automattic\Jetpack\Agents_Manager;
9
10 use Automattic\Jetpack\Connection\Client;
11 use Automattic\Jetpack\Status\Host;
12
13 /**
14 * Reads and writes the Agents Manager open state.
15 *
16 * The state is a global, per-user wpcom preference behind the
17 * `/agents-manager/state` endpoint. How the server reads it depends on the site:
18 *
19 * - wpcom Simple: the preference is local, so read `calypso_preferences` directly.
20 * - WoA / self-hosted: the preference is remote, so reads/writes go through this
21 * store's local REST route, which calls wpcom over the Jetpack Connection and
22 * caches the result in a per-user transient. Latency-sensitive readers (the
23 * server-side pre-render) use that transient to skip the round-trip.
24 */
25 class Open_State_Store {
26
27 /**
28 * Transient key prefix for the cached per-user open state.
29 *
30 * @var string
31 */
32 private const TRANSIENT_PREFIX = 'agents_manager_open_state_';
33
34 /**
35 * Default state values.
36 *
37 * @var array
38 */
39 public const DEFAULTS = array(
40 'agents_manager_open' => false,
41 'agents_manager_docked' => false,
42 'agents_manager_minimized' => false,
43 'agents_manager_floating_position' => 'right',
44 'agents_manager_router_history' => null,
45 'agents_manager_last_activity' => null,
46 );
47
48 /**
49 * Fetch the open state from wpcom and refresh the cache.
50 *
51 * @return array|\WP_Error Normalized state, or WP_Error when the request fails.
52 */
53 public static function fetch() {
54 $body = Client::wpcom_json_api_request_as_user(
55 '/agents-manager/state',
56 '2',
57 array( 'method' => 'GET' )
58 );
59
60 if ( is_wp_error( $body ) ) {
61 return $body;
62 }
63
64 $response = json_decode( wp_remote_retrieve_body( $body ), true );
65 $state = self::normalize( is_array( $response ) ? $response : array() );
66
67 self::cache( $state );
68
69 return $state;
70 }
71
72 /**
73 * Persist the open state to wpcom and refresh the cache.
74 *
75 * @param array $state Partial state to update (subset of DEFAULTS keys).
76 * @return array|\WP_Error Normalized state, or WP_Error when the request fails.
77 */
78 public static function update( array $state ) {
79 $body = Client::wpcom_json_api_request_as_user(
80 '/agents-manager/state',
81 '2',
82 array( 'method' => 'POST' ),
83 array( 'state' => $state )
84 );
85
86 if ( is_wp_error( $body ) ) {
87 return $body;
88 }
89
90 $response = json_decode( wp_remote_retrieve_body( $body ), true );
91
92 if ( ! is_array( $response ) ) {
93 return new \WP_Error(
94 'invalid_response',
95 'Invalid response from WPCOM endpoint',
96 array( 'status' => 500 )
97 );
98 }
99
100 $normalized = self::normalize( $response );
101
102 self::cache( $normalized );
103
104 return $normalized;
105 }
106
107 /**
108 * Read the current user's open state from the fastest local source.
109 *
110 * For latency-sensitive callers like the server-side pre-render: Simple sites
111 * read `calypso_preferences` directly, everywhere else uses the cached
112 * transient (see the class docblock). Returns null when nothing is known yet,
113 * so callers can skip pre-rendering until the frontend sets the real state.
114 *
115 * @return array|null `{ agents_manager_open, agents_manager_docked }` or null.
116 */
117 public static function get_cached() {
118 $user_id = get_current_user_id();
119 if ( ! $user_id ) {
120 return null;
121 }
122
123 // Simple sites have the preference locally, so read it directly (the
124 // transient is never primed there).
125 if ( ( new Host() )->is_wpcom_simple() && function_exists( '\get_user_attribute' ) ) {
126 $calypso_prefs = \get_user_attribute( $user_id, 'calypso_preferences' );
127 if ( ! is_array( $calypso_prefs ) ) {
128 return null;
129 }
130
131 return array(
132 'agents_manager_open' => (bool) ( $calypso_prefs['agents_manager_open'] ?? false ),
133 'agents_manager_docked' => (bool) ( $calypso_prefs['agents_manager_docked'] ?? false ),
134 );
135 }
136
137 $cached = get_transient( self::cache_key( $user_id ) );
138
139 return is_array( $cached ) ? $cached : null;
140 }
141
142 /**
143 * Normalize a raw endpoint response into the full state shape.
144 *
145 * @param array $response Raw decoded response.
146 * @return array Normalized state with all DEFAULTS keys present.
147 */
148 private static function normalize( array $response ): array {
149 return array(
150 'agents_manager_open' => (bool) ( $response['agents_manager_open'] ?? self::DEFAULTS['agents_manager_open'] ),
151 'agents_manager_docked' => (bool) ( $response['agents_manager_docked'] ?? self::DEFAULTS['agents_manager_docked'] ),
152 'agents_manager_minimized' => (bool) ( $response['agents_manager_minimized'] ?? self::DEFAULTS['agents_manager_minimized'] ),
153 'agents_manager_floating_position' => $response['agents_manager_floating_position'] ?? self::DEFAULTS['agents_manager_floating_position'],
154 'agents_manager_router_history' => $response['agents_manager_router_history'] ?? self::DEFAULTS['agents_manager_router_history'],
155 'agents_manager_last_activity' => $response['agents_manager_last_activity'] ?? self::DEFAULTS['agents_manager_last_activity'],
156 );
157 }
158
159 /**
160 * Cache the open/docked bits in a per-user transient.
161 *
162 * Only used on the remote (WoA / self-hosted) path — it's what get_cached()
163 * reads there. Simple sites read `calypso_preferences` directly and skip this.
164 *
165 * @param array $state Normalized state.
166 */
167 private static function cache( array $state ): void {
168 $user_id = get_current_user_id();
169 if ( ! $user_id ) {
170 return;
171 }
172
173 /**
174 * Filter how long the cached open state lives.
175 *
176 * It's refreshed on every read/write through this store, so the TTL mainly
177 * caps how long a value changed elsewhere (e.g. in Calypso) stays stale.
178 *
179 * @since 0.4.0
180 *
181 * @param int $ttl Cache lifetime in seconds.
182 */
183 $ttl = (int) apply_filters( 'agents_manager_open_state_cache_ttl', WEEK_IN_SECONDS );
184
185 set_transient(
186 self::cache_key( $user_id ),
187 array(
188 'agents_manager_open' => (bool) ( $state['agents_manager_open'] ?? false ),
189 'agents_manager_docked' => (bool) ( $state['agents_manager_docked'] ?? false ),
190 ),
191 $ttl
192 );
193 }
194
195 /**
196 * Build the per-user transient key.
197 *
198 * @param int $user_id User ID.
199 * @return string
200 */
201 private static function cache_key( int $user_id ): string {
202 return self::TRANSIENT_PREFIX . $user_id;
203 }
204 }
205