PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 16.3-a.1
Jetpack – WP Security, Backup, Speed, & Growth v16.3-a.1
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 13.9.2 14.0.1 All 504 releases
jetpack / jetpack_vendor / automattic / jetpack-connection / src / class-plugin-storage.php

class-plugin-storage.php in Jetpack – WP Security, Backup, Speed, & Growth 16.3-a.1, at jetpack_vendor/automattic/jetpack-connection/src/class-plugin-storage.php

262 lines 7.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Storage for plugin connection information.
4 *
5 * @package automattic/jetpack-connection
6 */
7
8 namespace Automattic\Jetpack\Connection;
9
10 use Jetpack_Options;
11 use WP_Error;
12
13 /**
14 * The class serves a single purpose - to store the data which plugins use the connection, along with some auxiliary information.
15 */
16 class Plugin_Storage {
17
18 const ACTIVE_PLUGINS_OPTION_NAME = 'jetpack_connection_active_plugins';
19
20 /**
21 * Transient name used as flag to indicate that the active connected plugins list needs refreshing.
22 */
23 const ACTIVE_PLUGINS_REFRESH_FLAG = 'jetpack_connection_active_plugins_refresh';
24
25 /**
26 * Whether this class was configured for the first time or not.
27 *
28 * @var boolean
29 */
30 private static $configured = false;
31
32 /**
33 * Connected plugins.
34 *
35 * @var array
36 */
37 private static $plugins = array();
38
39 /**
40 * The blog ID the storage is setup for.
41 * The data will be refreshed if the blog ID changes.
42 * Used for the multisite networks.
43 *
44 * @var int
45 */
46 private static $current_blog_id = null;
47
48 /**
49 * Add or update the plugin information in the storage.
50 *
51 * @param string $slug Plugin slug.
52 * @param array $args Plugin arguments, optional.
53 *
54 * @return bool
55 */
56 public static function upsert( $slug, array $args = array() ) {
57 self::$plugins[ $slug ] = $args;
58
59 return true;
60 }
61
62 /**
63 * Retrieve the plugin information by slug.
64 * WARNING: the method cannot be called until Plugin_Storage::configure is called, which happens on plugins_loaded
65 * Even if you don't use Jetpack Config, it may be introduced later by other plugins,
66 * so please make sure not to run the method too early in the code.
67 *
68 * @param string $slug The plugin slug.
69 *
70 * @return array|null|WP_Error
71 */
72 public static function get_one( $slug ) {
73 $plugins = self::get_all();
74
75 if ( $plugins instanceof WP_Error ) {
76 return $plugins;
77 }
78
79 return empty( $plugins[ $slug ] ) ? null : $plugins[ $slug ];
80 }
81
82 /**
83 * Retrieve info for all plugins that use the connection.
84 * WARNING: the method cannot be called until Plugin_Storage::configure is called, which happens on plugins_loaded
85 * Even if you don't use Jetpack Config, it may be introduced later by other plugins,
86 * so please make sure not to run the method too early in the code.
87 *
88 * @return array|WP_Error
89 */
90 public static function get_all() {
91 $maybe_error = self::ensure_configured();
92
93 if ( $maybe_error instanceof WP_Error ) {
94 return $maybe_error;
95 }
96
97 return self::$plugins;
98 }
99
100 /**
101 * Remove the plugin connection info from Jetpack.
102 * WARNING: the method cannot be called until Plugin_Storage::configure is called, which happens on plugins_loaded
103 * Even if you don't use Jetpack Config, it may be introduced later by other plugins,
104 * so please make sure not to run the method too early in the code.
105 *
106 * @param string $slug The plugin slug.
107 *
108 * @return bool|WP_Error
109 */
110 public static function delete( $slug ) {
111 $maybe_error = self::ensure_configured();
112
113 if ( $maybe_error instanceof WP_Error ) {
114 return $maybe_error;
115 }
116
117 if ( array_key_exists( $slug, self::$plugins ) ) {
118 unset( self::$plugins[ $slug ] );
119 }
120
121 return true;
122 }
123
124 /**
125 * The method makes sure that `Jetpack\Config` has finished, and it's now safe to retrieve the list of plugins.
126 *
127 * @return bool|WP_Error
128 */
129 private static function ensure_configured() {
130 if ( ! self::$configured ) {
131 return new WP_Error( 'too_early', __( 'You cannot call this method until Jetpack Config is configured', 'jetpack-connection' ) );
132 }
133
134 if ( is_multisite() && get_current_blog_id() !== self::$current_blog_id ) {
135 if ( self::$current_blog_id ) {
136 // If blog ID got changed, pull the list of active plugins for that blog from the database.
137 self::$plugins = (array) get_option( self::ACTIVE_PLUGINS_OPTION_NAME, array() );
138 }
139 self::$current_blog_id = get_current_blog_id();
140 }
141
142 return true;
143 }
144
145 /**
146 * Called once to configure this class after plugins_loaded.
147 *
148 * @return void
149 */
150 public static function configure() {
151 if ( self::$configured ) {
152 return;
153 }
154
155 self::$configured = true;
156
157 add_action( 'update_option_active_plugins', array( __CLASS__, 'set_flag_to_refresh_active_connected_plugins' ) );
158
159 self::maybe_update_active_connected_plugins();
160 }
161
162 /**
163 * Set a flag to indicate that the active connected plugins list needs to be updated.
164 * This will happen when the `active_plugins` option is updated.
165 *
166 * @see configure
167 */
168 public static function set_flag_to_refresh_active_connected_plugins() {
169 set_transient( self::ACTIVE_PLUGINS_REFRESH_FLAG, time() );
170 }
171
172 /**
173 * Determine if we need to update the active connected plugins list.
174 */
175 public static function maybe_update_active_connected_plugins() {
176 $maybe_error = self::ensure_configured();
177
178 if ( $maybe_error instanceof WP_Error ) {
179 return;
180 }
181 // Only attempt to update the option if the corresponding flag is set.
182 if ( ! get_transient( self::ACTIVE_PLUGINS_REFRESH_FLAG ) ) {
183 return;
184 }
185 // Only attempt to update the option on POST requests.
186 // This will prevent the option from being updated multiple times due to concurrent requests.
187 if ( ! ( isset( $_SERVER['REQUEST_METHOD'] ) && 'POST' === $_SERVER['REQUEST_METHOD'] ) ) {
188 return;
189 }
190
191 delete_transient( self::ACTIVE_PLUGINS_REFRESH_FLAG );
192
193 if ( is_multisite() ) {
194 self::$current_blog_id = get_current_blog_id();
195 }
196
197 // If a plugin was activated or deactivated.
198 // self::$plugins is populated in Config::ensure_options_connection().
199 $configured_plugin_keys = array_keys( self::$plugins );
200 $stored_plugin_keys = array_keys( (array) get_option( self::ACTIVE_PLUGINS_OPTION_NAME, array() ) );
201 sort( $configured_plugin_keys );
202 sort( $stored_plugin_keys );
203
204 if ( $configured_plugin_keys !== $stored_plugin_keys ) {
205 self::update_active_plugins_option();
206 }
207 }
208
209 /**
210 * Updates the active plugins option with current list of active plugins.
211 *
212 * @return void
213 */
214 public static function update_active_plugins_option() {
215 // Note: Since this option is synced to wpcom, if you change its structure, you have to update the sanitizer at wpcom side.
216 update_option( self::ACTIVE_PLUGINS_OPTION_NAME, self::$plugins );
217 if ( ! class_exists( 'Automattic\Jetpack\Sync\Settings' ) || ! \Automattic\Jetpack\Sync\Settings::is_sync_enabled() ) {
218 self::update_active_plugins_wpcom_no_sync_fallback();
219 // Remove the checksum for active plugins, so it gets recalculated when sync gets activated.
220 $jetpack_callables_sync_checksum = Jetpack_Options::get_raw_option( 'jetpack_callables_sync_checksum' );
221 if ( isset( $jetpack_callables_sync_checksum['jetpack_connection_active_plugins'] ) ) {
222 unset( $jetpack_callables_sync_checksum['jetpack_connection_active_plugins'] );
223 Jetpack_Options::update_raw_option( 'jetpack_callables_sync_checksum', $jetpack_callables_sync_checksum );
224 }
225 }
226 }
227
228 /**
229 * Update active plugins option with current list of active plugins on WPCOM.
230 * This is a fallback to ensure this option is always up to date on WPCOM in case
231 * Sync is not present or disabled.
232 *
233 * @since 1.34.0
234 */
235 private static function update_active_plugins_wpcom_no_sync_fallback() {
236 $connection = new Manager();
237 if ( ! $connection->is_connected() ) {
238 return;
239 }
240
241 $site_id = \Jetpack_Options::get_option( 'id' );
242
243 $body = wp_json_encode(
244 array(
245 'active_connected_plugins' => self::$plugins,
246 ),
247 JSON_UNESCAPED_SLASHES
248 );
249
250 Client::wpcom_json_api_request_as_blog(
251 sprintf( '/sites/%d/jetpack-active-connected-plugins', $site_id ),
252 '2',
253 array(
254 'headers' => array( 'content-type' => 'application/json' ),
255 'method' => 'POST',
256 ),
257 $body,
258 'wpcom'
259 );
260 }
261 }
262