PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 16.3
Jetpack – WP Security, Backup, Speed, & Growth v16.3
16.3 16.3-beta 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 All 508 releases
← All changes | jetpack_vendor/automattic/jetpack-connection/src/class-plugin-storage.php +261 -0 16.2-beta → 16.3 View file →
@@ -1,0 +1,261 @@
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 +}