PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 16.0-beta
Jetpack – WP Security, Backup, Speed, & Growth v16.0-beta
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 / _inc / lib / class-jetpack-recommendations.php
jetpack / _inc / lib Last commit date
admin-pages 2 weeks ago core-api 3 days ago debugger 1 month ago markdown 7 months ago class-jetpack-ai-helper.php 4 months ago class-jetpack-application-password-extras.php 3 months ago class-jetpack-blog-stats-helper.php 7 months ago class-jetpack-currencies.php 1 year ago class-jetpack-instagram-gallery-helper.php 1 month ago class-jetpack-mapbox-helper.php 3 years ago class-jetpack-newsletter-category-helper.php 7 months ago class-jetpack-podcast-feed-locator.php 1 month ago class-jetpack-podcast-helper.php 5 months ago class-jetpack-recommendations.php 1 month ago class-jetpack-spinner.php 2 months ago class-jetpack-top-posts-helper.php 2 weeks ago class.color.php 1 year ago class.core-rest-api-endpoints.php 2 weeks ago class.jetpack-automatic-install-skin.php 2 years ago class.jetpack-iframe-embed.php 3 years ago class.jetpack-password-checker.php 7 months ago class.jetpack-search-performance-logger.php 4 years ago class.media-extractor.php 1 month ago class.media-summary.php 2 weeks ago class.media.php 7 months ago components.php 7 months ago debugger.php 1 month ago icalendar-reader.php 1 month ago markdown.php 7 months ago plans.php 4 years ago plugins.php 4 years ago tonesque.php 7 months ago widgets.php 3 months ago
class-jetpack-recommendations.php
451 lines
1 <?php
2 /**
3 * Utilities related to the Jetpack Recommendations
4 *
5 * @package automattic/jetpack
6 */
7
8 use Automattic\Jetpack\Current_Plan as Jetpack_Plan;
9 use Automattic\Jetpack\Plugins_Installer;
10 use Automattic\Jetpack\Status;
11 use Automattic\Jetpack\Status\Host;
12
13 /**
14 * Contains utilities related to the Jetpack Recommendations.
15 *
16 * @package automattic/jetpack
17 */
18
19 /**
20 * Jetpack_Recommendations class
21 */
22 class Jetpack_Recommendations {
23 const PUBLICIZE_RECOMMENDATION = 'publicize';
24 const PROTECT_RECOMMENDATION = 'protect';
25 const ANTI_SPAM_RECOMMENDATION = 'anti-spam';
26 const VIDEOPRESS_RECOMMENDATION = 'videopress';
27 const BACKUP_PLAN_RECOMMENDATION = 'backup-plan';
28 const BOOST_RECOMMENDATION = 'boost';
29
30 const CONDITIONAL_RECOMMENDATIONS_OPTION = 'recommendations_conditional';
31 const CONDITIONAL_RECOMMENDATIONS = array(
32 self::PUBLICIZE_RECOMMENDATION,
33 self::PROTECT_RECOMMENDATION,
34 self::ANTI_SPAM_RECOMMENDATION,
35 self::VIDEOPRESS_RECOMMENDATION,
36 self::BACKUP_PLAN_RECOMMENDATION,
37 self::BOOST_RECOMMENDATION,
38 );
39
40 const VIDEOPRESS_TIMED_ACTION = 'jetpack_recommend_videopress';
41
42 /**
43 * Returns a boolean indicating if the Jetpack Recommendations are enabled.
44 *
45 * @since 9.3.0
46 *
47 * @return bool
48 */
49 public static function is_enabled() {
50 // Shortcircuit early if Jetpack is not active or we are in offline mode.
51 if ( ! Jetpack::is_connection_ready() || ( new Status() )->is_offline_mode() ) {
52 return false;
53 }
54
55 // No recommendations for Atomic sites, they already get onboarded in Calypso.
56 if ( ( new Host() )->is_woa_site() ) {
57 return false;
58 }
59
60 self::initialize_jetpack_recommendations();
61
62 return true;
63 }
64
65 /**
66 * Returns a boolean indicating if the Jetpack Banner is enabled.
67 *
68 * @since 9.3.0
69 *
70 * @deprecated 13.2
71 *
72 * @return bool
73 */
74 public static function is_banner_enabled() {
75 _deprecated_function( __METHOD__, 'jetpack-13.2' );
76 return false;
77 }
78
79 /**
80 * Set up actions to monitor for things that trigger a recommendation.
81 *
82 * @return false|void
83 */
84 public static function init_conditional_recommendation_actions() {
85 // Check to make sure that recommendations are enabled.
86 if ( ! self::is_enabled() ) {
87 return false;
88 }
89
90 // Monitor for the publishing of a new post.
91 add_action( 'transition_post_status', array( static::class, 'post_transition' ), 10, 3 );
92 add_action( 'jetpack_activate_module', array( static::class, 'jetpack_module_activated' ), 10, 2 );
93
94 // Monitor for activating a new plugin.
95 add_action( 'activated_plugin', array( static::class, 'plugin_activated' ), 10 );
96
97 // Monitor for the addition of a new comment.
98 add_action( 'comment_post', array( static::class, 'comment_added' ), 10, 3 );
99
100 // Monitor for Jetpack connection success.
101 add_action( 'jetpack_authorize_ending_authorized', array( static::class, 'jetpack_connected' ) );
102 add_action( self::VIDEOPRESS_TIMED_ACTION, array( static::class, 'recommend_videopress' ) );
103
104 // Monitor for changes in plugins that have auto-updates enabled
105 add_action( 'update_site_option_auto_update_plugins', array( static::class, 'plugin_auto_update_settings_changed' ), 10, 3 );
106 }
107
108 /**
109 * Check when Jetpack modules are activated if some recommendations should be skipped.
110 *
111 * @param string $module Name of the module activated.
112 * @param bool $success Whether the module activation was successful.
113 */
114 public static function jetpack_module_activated( $module, $success ) {
115 if ( 'publicize' === $module && $success ) {
116 self::disable_conditional_recommendation( self::PUBLICIZE_RECOMMENDATION );
117 } elseif ( 'videopress' === $module && $success ) {
118 // If VideoPress is enabled and a recommendation for it is scheduled, cancel that recommendation.
119 $recommendation_timestamp = wp_next_scheduled( self::VIDEOPRESS_TIMED_ACTION );
120 if ( false !== $recommendation_timestamp ) {
121 wp_unschedule_event( $recommendation_timestamp, self::VIDEOPRESS_TIMED_ACTION );
122 }
123 }
124 }
125
126 /**
127 * Hook for transition_post_status that checks for the publishing of a new post or page.
128 * Used to enable the publicize and boost recommendations.
129 *
130 * @param string $new_status new status of post.
131 * @param string $old_status old status of post.
132 * @param WP_Post $post the post object being updated.
133 */
134 public static function post_transition( $new_status, $old_status, $post ) {
135 // Check for condition when post has been published.
136 if ( 'post' === $post->post_type && 'publish' === $new_status && 'publish' !== $old_status && ! Jetpack::is_module_active( 'publicize' ) ) {
137 // Set the publicize recommendation to have met criteria to be shown.
138 self::enable_conditional_recommendation( self::PUBLICIZE_RECOMMENDATION );
139 return;
140 }
141 // A new page has been published
142 // Check to see if the boost plugin is active
143 if (
144 'page' === $post->post_type &&
145 'publish' === $new_status &&
146 'publish' !== $old_status &&
147 ! Plugins_Installer::is_plugin_active( 'boost/jetpack-boost.php' ) &&
148 ! Plugins_Installer::is_plugin_active( 'jetpack-boost/jetpack-boost.php' )
149 ) {
150 self::enable_conditional_recommendation( self::BOOST_RECOMMENDATION );
151 }
152 }
153
154 /**
155 * Runs when a plugin gets activated
156 *
157 * @param string $plugin Path to the plugins file relative to the plugins directory.
158 */
159 public static function plugin_activated( $plugin ) {
160 // If the plugin is in this list, don't enable the recommendation.
161 $plugin_whitelist = array(
162 'jetpack.php',
163 'akismet.php',
164 'creative-mail.php',
165 'jetpack-backup.php',
166 'jetpack-boost.php',
167 'jetpack-protect.php',
168 'crowdsignal.php',
169 'vaultpress.php',
170 'woocommerce.php',
171 );
172
173 $path_parts = explode( '/', $plugin );
174 $plugin_file = array_pop( $path_parts );
175
176 if ( ! in_array( $plugin_file, $plugin_whitelist, true ) ) {
177 $products = array_column( Jetpack_Plan::get_products(), 'product_slug' );
178
179 // Check for a plan or product that enables scan.
180 $plan_supports_scan = Jetpack_Plan::supports( 'scan' );
181 $has_scan_product = count( array_intersect( array( 'jetpack_scan', 'jetpack_scan_monthly' ), $products ) ) > 0;
182 $has_scan = $plan_supports_scan || $has_scan_product;
183
184 // Check if Jetpack Protect plugin is already active.
185 $has_protect = Plugins_Installer::is_plugin_active( 'jetpack-protect/jetpack-protect.php' ) || Plugins_Installer::is_plugin_active( 'protect/jetpack-protect.php' );
186
187 if ( ! $has_scan && ! $has_protect ) {
188 self::enable_conditional_recommendation( self::PROTECT_RECOMMENDATION );
189 }
190 }
191 }
192
193 /**
194 * Runs when the auto_update_plugins option has been changed
195 *
196 * @param string $option_name - the name of the option updated ( always auto_update_plugins ).
197 * @param array $new_auto_update_plugins - plugins that have auto update enabled following the change.
198 * @param array $old_auto_update_plugins - plugins that had auto update enabled before the most recent change.
199 * @return void
200 */
201 public static function plugin_auto_update_settings_changed( $option_name, $new_auto_update_plugins, $old_auto_update_plugins ) {
202 if (
203 is_multisite() ||
204 self::is_conditional_recommendation_enabled( self::BACKUP_PLAN_RECOMMENDATION )
205 ) {
206 return;
207 }
208
209 // Look for plugins that have had auto-update enabled in this most recent update.
210 $enabled_auto_updates = array_diff( $new_auto_update_plugins, $old_auto_update_plugins );
211 if ( ! empty( $enabled_auto_updates ) ) {
212 // Check the backup state.
213 $rewind_state = get_transient( 'jetpack_rewind_state' );
214 $has_backup = $rewind_state && in_array( $rewind_state->state, array( 'awaiting_credentials', 'provisioning', 'active' ), true );
215
216 if ( ! $has_backup ) {
217 self::enable_conditional_recommendation( self::BACKUP_PLAN_RECOMMENDATION );
218 }
219 }
220 }
221
222 /**
223 * Runs when a new comment is added.
224 *
225 * @param integer $comment_id The ID of the comment that was added.
226 * @param bool $comment_approved Whether or not the comment is approved.
227 * @param array $commentdata Comment data.
228 */
229 public static function comment_added( $comment_id, $comment_approved, $commentdata ) {
230 if ( self::is_conditional_recommendation_enabled( self::ANTI_SPAM_RECOMMENDATION ) ) {
231 return;
232 }
233
234 if ( Plugins_Installer::is_plugin_active( 'akismet/akismet.php' ) ) {
235 return;
236 }
237
238 // The site has anti-spam features already.
239 $site_products = array_column( Jetpack_Plan::get_products(), 'product_slug' );
240 $has_anti_spam_product = count( array_intersect( array( 'jetpack_anti_spam', 'jetpack_anti_spam_monthly' ), $site_products ) ) > 0;
241
242 if ( Jetpack_Plan::supports( 'akismet' ) || Jetpack_Plan::supports( 'antispam' ) || $has_anti_spam_product ) {
243 return;
244 }
245
246 if ( isset( $commentdata['comment_post_ID'] ) ) {
247 $post_id = $commentdata['comment_post_ID'];
248 } else {
249 $comment = get_comment( $comment_id );
250 $post_id = $comment->comment_post_ID;
251 }
252 $comment_count = get_comments_number( $post_id );
253
254 if ( intval( $comment_count ) >= 5 ) {
255 self::enable_conditional_recommendation( self::ANTI_SPAM_RECOMMENDATION );
256 }
257 }
258
259 /**
260 * Runs after a successful connection is made.
261 */
262 public static function jetpack_connected() {
263 // Schedule a recommendation for VideoPress in 2 weeks.
264 if ( false === wp_next_scheduled( self::VIDEOPRESS_TIMED_ACTION ) ) {
265 $date = new DateTime();
266 $date->add( new DateInterval( 'P14D' ) );
267 wp_schedule_single_event( $date->getTimestamp(), self::VIDEOPRESS_TIMED_ACTION );
268 }
269 }
270
271 /**
272 * Enable a recommendation for VideoPress.
273 */
274 public static function recommend_videopress() {
275 // Check to see if the VideoPress recommendation is already enabled.
276 if ( self::is_conditional_recommendation_enabled( self::VIDEOPRESS_RECOMMENDATION ) ) {
277 return;
278 }
279
280 $site_plan = Jetpack_Plan::get();
281 $site_products = array_column( Jetpack_Plan::get_products(), 'product_slug' );
282
283 if ( self::should_recommend_videopress( $site_plan, $site_products ) ) {
284 self::enable_conditional_recommendation( self::VIDEOPRESS_RECOMMENDATION );
285 }
286 }
287
288 /**
289 * Should we provide a recommendation for videopress?
290 * This method exists to facilitate unit testing
291 *
292 * @param array $site_plan A representation of the site's plan.
293 * @param array $site_products An array of product slugs.
294 * @return boolean
295 */
296 public static function should_recommend_videopress( $site_plan, $site_products ) {
297 // Does the site have the VideoPress module enabled?
298 if ( Jetpack::is_module_active( 'videopress' ) ) {
299 return false;
300 }
301
302 // Does the site plan have upgraded videopress features?
303 // For now, this just checks to see if the site has a free plan.
304 // Jetpack_Plan::supports('videopress') returns true for all plans, since there is a free tier.
305 $is_free_plan = 'free' === $site_plan['class'];
306 if ( ! $is_free_plan ) {
307 return false;
308 }
309
310 // Does this site already have a VideoPress product?
311 $has_videopress_product = count( array_intersect( array( 'jetpack_videopress', 'jetpack_videopress_monthly' ), $site_products ) ) > 0;
312 if ( $has_videopress_product ) {
313 return false;
314 }
315
316 return true;
317 }
318
319 /**
320 * Enable a recommendation.
321 *
322 * @param string $recommendation_name The name of the recommendation to enable.
323 * @return false|void
324 */
325 public static function enable_conditional_recommendation( $recommendation_name ) {
326 if ( ! in_array( $recommendation_name, self::CONDITIONAL_RECOMMENDATIONS, true ) ) {
327 return false;
328 }
329
330 $conditional_recommendations = Jetpack_Options::get_option( self::CONDITIONAL_RECOMMENDATIONS_OPTION, array() );
331 if ( ! in_array( $recommendation_name, $conditional_recommendations, true ) ) {
332 $conditional_recommendations[] = $recommendation_name;
333 Jetpack_Options::update_option( self::CONDITIONAL_RECOMMENDATIONS_OPTION, $conditional_recommendations );
334 }
335 }
336
337 /**
338 * Disable a recommendation.
339 *
340 * @param string $recommendation_name The name of the recommendation to disable.
341 * @return false|void
342 */
343 public static function disable_conditional_recommendation( $recommendation_name ) {
344 if ( ! in_array( $recommendation_name, self::CONDITIONAL_RECOMMENDATIONS, true ) ) {
345 return false;
346 }
347
348 $conditional_recommendations = Jetpack_Options::get_option( self::CONDITIONAL_RECOMMENDATIONS_OPTION, array() );
349 $recommendation_index = array_search( $recommendation_name, $conditional_recommendations, true );
350
351 if ( false !== $recommendation_index ) {
352 array_splice( $conditional_recommendations, $recommendation_index, 1 );
353 Jetpack_Options::update_option( self::CONDITIONAL_RECOMMENDATIONS_OPTION, $conditional_recommendations );
354 }
355 }
356
357 /**
358 * Check to see if a recommendation is enabled or not.
359 *
360 * @param string $recommendation_name The name of the recommendation to check for.
361 * @return bool
362 */
363 public static function is_conditional_recommendation_enabled( $recommendation_name ) {
364 $conditional_recommendations = Jetpack_Options::get_option( self::CONDITIONAL_RECOMMENDATIONS_OPTION, array() );
365 return in_array( $recommendation_name, $conditional_recommendations, true );
366 }
367
368 /**
369 * Gets data for all conditional recommendations.
370 *
371 * @return mixed
372 */
373 public static function get_conditional_recommendations() {
374 return Jetpack_Options::get_option( self::CONDITIONAL_RECOMMENDATIONS_OPTION, array() );
375 }
376
377 /**
378 * Get an array of new conditional recommendations that have not been viewed.
379 *
380 * @return array
381 */
382 public static function get_new_conditional_recommendations() {
383 $conditional_recommendations = self::get_conditional_recommendations();
384 $recommendations_data = Jetpack_Options::get_option( 'recommendations_data', array() );
385 $viewed_recommendations = $recommendations_data['viewedRecommendations'] ?? array();
386
387 // array_diff returns a keyed array - reduce to unique values.
388 return array_unique( array_values( array_diff( $conditional_recommendations, $viewed_recommendations ) ) );
389 }
390
391 /**
392 * Initializes the Recommendations step according to the Setup Wizard state.
393 */
394 private static function initialize_jetpack_recommendations() {
395 if ( Jetpack_Options::get_option( 'recommendations_step' ) ) {
396 return;
397 }
398
399 $setup_wizard_status = Jetpack_Options::get_option( 'setup_wizard_status' );
400 if ( 'completed' === $setup_wizard_status ) {
401 Jetpack_Options::update_option( 'recommendations_step', 'setup-wizard-completed' );
402 }
403 }
404
405 /**
406 * Get the data for the recommendations
407 *
408 * @return array Recommendations data
409 */
410 public static function get_recommendations_data() {
411 self::initialize_jetpack_recommendations();
412
413 return Jetpack_Options::get_option( 'recommendations_data', array() );
414 }
415
416 /**
417 * Update the data for the recommendations
418 *
419 * @param WP_REST_Request $data The data.
420 */
421 public static function update_recommendations_data( $data ) {
422 if ( ! empty( $data ) ) {
423 Jetpack_Options::update_option( 'recommendations_data', $data );
424 }
425 }
426
427 /**
428 * Get the data for the recommendations
429 *
430 * @return array Recommendations data
431 */
432 public static function get_recommendations_step() {
433 self::initialize_jetpack_recommendations();
434
435 return array(
436 'step' => Jetpack_Options::get_option( 'recommendations_step', 'not-started' ),
437 );
438 }
439
440 /**
441 * Update the step for the recommendations
442 *
443 * @param WP_REST_Request $step The step.
444 */
445 public static function update_recommendations_step( $step ) {
446 if ( ! empty( $step ) ) {
447 Jetpack_Options::update_option( 'recommendations_step', $step );
448 }
449 }
450 }
451