PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 13.0.2
Jetpack – WP Security, Backup, Speed, & Growth v13.0.2
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 14.1.1 14.2.2 14.3.1 14.4.2 14.5.1 14.6.1 14.7.1 14.8.1 14.9.2 15.0.3 15.1.2 15.2.1 15.3.2 15.4.1 15.5.1 15.6.1 15.7.2 15.8.1 15.9.2 16.0.2 16.1.3 16.2-a.5 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 / vendor / automattic / jetpack-plans / src / class-current-plan.php
jetpack / vendor / automattic / jetpack-plans / src Last commit date
class-current-plan.php 2 years ago class-plans.php 4 years ago
class-current-plan.php
390 lines
1 <?php
2 /**
3 * Handles fetching of the site's plan and products from WordPress.com and caching values locally.
4 *
5 * @package automattic/jetpack-plans
6 */
7
8 namespace Automattic\Jetpack;
9
10 use Automattic\Jetpack\Connection\Client;
11 use Automattic\Jetpack\Connection\Manager;
12
13 /**
14 * Provides methods methods for fetching the site's plan and products from WordPress.com.
15 */
16 class Current_Plan {
17 /**
18 * A cache variable to hold the active plan for the current request.
19 *
20 * @var array
21 */
22 private static $active_plan_cache;
23
24 /**
25 * The name of the option that will store the site's plan.
26 *
27 * @var string
28 */
29 const PLAN_OPTION = 'jetpack_active_plan';
30
31 /**
32 * The name of the option that will store the site's products.
33 *
34 * @var string
35 */
36 const SITE_PRODUCTS_OPTION = 'jetpack_site_products';
37
38 const PLAN_DATA = array(
39 'free' => array(
40 'plans' => array(
41 'jetpack_free',
42 ),
43 'supports' => array(
44 'advanced-seo',
45 'opentable',
46 'calendly',
47 'send-a-message',
48 'whatsapp-button',
49 'social-previews',
50 'videopress',
51 'videopress/video',
52 'v6-video-frame-poster',
53
54 'core/video',
55 'core/cover',
56 'core/audio',
57 ),
58 ),
59 'personal' => array(
60 'plans' => array(
61 'jetpack_personal',
62 'jetpack_personal_monthly',
63 'personal-bundle',
64 'personal-bundle-monthly',
65 'personal-bundle-2y',
66 'personal-bundle-3y',
67 'starter-plan',
68 ),
69 'supports' => array(
70 'akismet',
71 'payments',
72 'videopress',
73 ),
74 ),
75 'premium' => array(
76 'plans' => array(
77 'jetpack_premium',
78 'jetpack_premium_monthly',
79 'value_bundle',
80 'value_bundle-monthly',
81 'value_bundle-2y',
82 'value_bundle-3y',
83 ),
84 'supports' => array(
85 'simple-payments',
86 'vaultpress',
87 'videopress',
88 'republicize',
89 ),
90 ),
91 'security' => array(
92 'plans' => array(
93 'jetpack_security_daily',
94 'jetpack_security_daily_monthly',
95 'jetpack_security_realtime',
96 'jetpack_security_realtime_monthly',
97 'jetpack_security_t1_yearly',
98 'jetpack_security_t1_monthly',
99 'jetpack_security_t2_yearly',
100 'jetpack_security_t2_monthly',
101 ),
102 'supports' => array(),
103 ),
104 'business' => array(
105 'plans' => array(
106 'jetpack_business',
107 'jetpack_business_monthly',
108 'business-bundle',
109 'business-bundle-monthly',
110 'business-bundle-2y',
111 'business-bundle-3y',
112 'ecommerce-bundle',
113 'ecommerce-bundle-monthly',
114 'ecommerce-bundle-2y',
115 'ecommerce-bundle-3y',
116 'pro-plan',
117 'wp_bundle_migration_trial_monthly',
118 'wp_bundle_hosting_trial_monthly',
119 'ecommerce-trial-bundle-monthly',
120 'wooexpress-small-bundle-yearly',
121 'wooexpress-small-bundle-monthly',
122 'wooexpress-medium-bundle-yearly',
123 'wooexpress-medium-bundle-monthly',
124 'wp_com_hundred_year_bundle_centennially',
125 ),
126 'supports' => array(),
127 ),
128
129 'complete' => array(
130 'plans' => array(
131 'jetpack_complete',
132 'jetpack_complete_monthly',
133 'vip',
134 ),
135 'supports' => array(),
136 ),
137 );
138
139 /**
140 * Given a response to the `/sites/%d` endpoint, will parse the response and attempt to set the
141 * site's plan and products from the response.
142 *
143 * @param array $response The response from `/sites/%d`.
144 * @return bool Was the plan successfully updated?
145 */
146 public static function update_from_sites_response( $response ) {
147 // Bail if there was an error or malformed response.
148 if ( is_wp_error( $response ) || ! is_array( $response ) || ! isset( $response['body'] ) ) {
149 return false;
150 }
151
152 $body = wp_remote_retrieve_body( $response );
153 if ( is_wp_error( $body ) ) {
154 return false;
155 }
156
157 // Decode the results.
158 $results = json_decode( $body, true );
159
160 if ( ! is_array( $results ) ) {
161 return false;
162 }
163
164 if ( isset( $results['products'] ) ) {
165 // Store the site's products in an option and return true if updated.
166 self::store_data_in_option( self::SITE_PRODUCTS_OPTION, $results['products'] );
167 }
168
169 if ( ! isset( $results['plan'] ) ) {
170 return false;
171 }
172
173 $current_plan = get_option( self::PLAN_OPTION, array() );
174
175 if ( ! empty( $current_plan ) && $current_plan === $results['plan'] ) {
176 // Bail if the plans array hasn't changed.
177 return false;
178 }
179
180 // Store the new plan in an option and return true if updated.
181 $result = self::store_data_in_option( self::PLAN_OPTION, $results['plan'] );
182
183 if ( $result ) {
184 // Reset the cache since we've just updated the plan.
185 self::$active_plan_cache = null;
186 }
187
188 return $result;
189 }
190
191 /**
192 * Store data in an option.
193 *
194 * @param string $option The name of the option that will store the data.
195 * @param array $data Data to be store in an option.
196 * @return bool Were the subscriptions successfully updated?
197 */
198 private static function store_data_in_option( $option, $data ) {
199 $result = update_option( $option, $data, true );
200
201 // If something goes wrong with the update, so delete the current option and then update it.
202 if ( ! $result ) {
203 delete_option( $option );
204 $result = update_option( $option, $data, true );
205 }
206
207 return $result;
208 }
209
210 /**
211 * Make an API call to WordPress.com for plan status
212 *
213 * @uses Jetpack_Options::get_option()
214 * @uses Client::wpcom_json_api_request_as_blog()
215 * @uses update_option()
216 *
217 * @access public
218 * @static
219 *
220 * @return bool True if plan is updated, false if no update
221 */
222 public static function refresh_from_wpcom() {
223 $site_id = Manager::get_site_id();
224 if ( is_wp_error( $site_id ) ) {
225 return false;
226 }
227
228 // Make the API request.
229
230 $response = Client::wpcom_json_api_request_as_blog(
231 sprintf( '/sites/%d?force=wpcom', $site_id ),
232 '1.1'
233 );
234
235 return self::update_from_sites_response( $response );
236 }
237
238 /**
239 * Get the plan that this Jetpack site is currently using.
240 *
241 * @uses get_option()
242 *
243 * @access public
244 * @static
245 *
246 * @return array Active Jetpack plan details
247 */
248 public static function get() {
249 // this can be expensive to compute so we cache for the duration of a request.
250 if ( is_array( self::$active_plan_cache ) && ! empty( self::$active_plan_cache ) ) {
251 return self::$active_plan_cache;
252 }
253
254 $plan = get_option( self::PLAN_OPTION, array() );
255
256 // Set the default options.
257 $plan = wp_parse_args(
258 $plan,
259 array(
260 'product_slug' => 'jetpack_free',
261 'class' => 'free',
262 'features' => array(
263 'active' => array(),
264 ),
265 )
266 );
267
268 list( $plan['class'], $supports ) = self::get_class_and_features( $plan['product_slug'] );
269
270 $modules = new Modules();
271 foreach ( $modules->get_available() as $module_slug ) {
272 $module = $modules->get( $module_slug );
273 if ( ! isset( $module ) || ! is_array( $module ) ) {
274 continue;
275 }
276 if ( in_array( 'free', $module['plan_classes'], true ) || in_array( $plan['class'], $module['plan_classes'], true ) ) {
277 $supports[] = $module_slug;
278 }
279 }
280
281 $plan['supports'] = $supports;
282
283 self::$active_plan_cache = $plan;
284
285 return $plan;
286 }
287
288 /**
289 * Get the site's products.
290 *
291 * @uses get_option()
292 *
293 * @access public
294 * @static
295 *
296 * @return array Active Jetpack products
297 */
298 public static function get_products() {
299 return get_option( self::SITE_PRODUCTS_OPTION, array() );
300 }
301
302 /**
303 * Get the class of plan and a list of features it supports
304 *
305 * @param string $plan_slug The plan that we're interested in.
306 * @return array Two item array, the plan class and the an array of features.
307 */
308 private static function get_class_and_features( $plan_slug ) {
309 $features = array();
310 foreach ( self::PLAN_DATA as $class => $details ) {
311 $features = array_merge( $features, $details['supports'] );
312 if ( in_array( $plan_slug, $details['plans'], true ) ) {
313 return array( $class, $features );
314 }
315 }
316 return array( 'free', self::PLAN_DATA['free']['supports'] );
317 }
318
319 /**
320 * Gets the minimum plan slug that supports the given feature
321 *
322 * @param string $feature The name of the feature.
323 * @return string|bool The slug for the minimum plan that supports.
324 * the feature or false if not found
325 */
326 public static function get_minimum_plan_for_feature( $feature ) {
327 foreach ( self::PLAN_DATA as $details ) {
328 if ( in_array( $feature, $details['supports'], true ) ) {
329 return $details['plans'][0];
330 }
331 }
332 return false;
333 }
334
335 /**
336 * Determine whether the active plan supports a particular feature
337 *
338 * @uses self::get()
339 *
340 * @access public
341 * @static
342 *
343 * @param string $feature The module or feature to check.
344 * @param bool $refresh_from_wpcom Refresh the local plan cache from wpcom.
345 *
346 * @return bool True if plan supports feature, false if not
347 */
348 public static function supports( $feature, $refresh_from_wpcom = false ) {
349 if ( $refresh_from_wpcom ) {
350 self::refresh_from_wpcom();
351 }
352
353 // Hijack the feature eligibility check on WordPress.com sites since they are gated differently.
354 $should_wpcom_gate_feature = (
355 function_exists( 'wpcom_site_has_feature' ) &&
356 function_exists( 'wpcom_feature_exists' ) &&
357 wpcom_feature_exists( $feature )
358 );
359 if ( $should_wpcom_gate_feature ) {
360 return wpcom_site_has_feature( $feature );
361 }
362
363 // Search product bypasses plan feature check.
364 if ( 'search' === $feature && (bool) get_option( 'has_jetpack_search_product' ) ) {
365 return true;
366 }
367
368 // As of Q3 2021 - a videopress free tier is available to all plans.
369 if ( 'videopress' === $feature ) {
370 return true;
371 }
372
373 // As of 05 2023 - all plans support Earn features (minus 'simple-payments')
374 if ( in_array( $feature, array( 'donations', 'recurring-payments', 'premium-content/container' ), true ) ) {
375 return true;
376 }
377
378 $plan = self::get();
379
380 if (
381 in_array( $feature, $plan['supports'], true )
382 || in_array( $feature, $plan['features']['active'], true )
383 ) {
384 return true;
385 }
386
387 return false;
388 }
389 }
390