PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 16.3-a.7
Jetpack – WP Security, Backup, Speed, & Growth v16.3-a.7
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 13.7.2 13.8.3 All 506 releases
jetpack / jetpack_vendor / automattic / jetpack-premium-analytics / src / class-enablement-setting.php

class-enablement-setting.php in Jetpack – WP Security, Backup, Speed, & Growth 16.3-a.7, at jetpack_vendor/automattic/jetpack-premium-analytics/src/class-enablement-setting.php

141 lines 5.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Public entry point for hosts that expose the dashboard's opt-in setting.
4 *
5 * @package automattic/jetpack-premium-analytics
6 */
7
8 namespace Automattic\Jetpack\PremiumAnalytics;
9
10 /**
11 * Exposes the site's dashboard opt-in through core's `wp/v2/settings` route.
12 *
13 * This is the one thing the package has to serve while the dashboard is switched off, so hosts
14 * register it outside their enablement checks. Everything else lives behind
15 * {@see Dashboard_Support_Routes}, which only boots once the dashboard is already on.
16 *
17 * Reads and writes both address the stored opt-in, so this route reports the same value as any
18 * other reader of the option. An override such as our rollout sticker turns the dashboard on
19 * without touching the opt-in and deliberately does not surface here: whether the dashboard
20 * actually booted is `analytics.enabled` in script data.
21 *
22 * Writing cannot take effect in the request that writes it: Jetpack resolves the flag once, on
23 * `plugins_loaded`. Clients are expected to reload.
24 *
25 * @since 0.6.0
26 */
27 class Enablement_Setting {
28
29 /**
30 * Site option holding the customer's own opt-in to the dashboard.
31 *
32 * Lives here rather than on {@see Analytics} so that registering the setting does not pull the
33 * whole dashboard class in behind it: this runs on REST requests of every kind, including ones
34 * with the dashboard switched off. Jetpack::is_premium_analytics_enabled() spells the name a
35 * third time, since it has to answer before this package is known to be loadable at all.
36 *
37 * @since 0.6.0
38 */
39 const ENABLED_OPTION = 'jetpack_premium_analytics_enabled';
40
41 /**
42 * Preferences scope the dashboard stores its per-user state under. Mirrors
43 * `routes/dashboard/hooks/constants.ts`.
44 *
45 * @since 0.6.0
46 */
47 const PREFERENCES_SCOPE = 'jetpack-premium-analytics/dashboard';
48
49 /**
50 * Preferences key the dashboard sets once a reader has been through the onboarding. Mirrors
51 * `routes/dashboard/hooks/constants.ts`.
52 *
53 * @since 0.6.0
54 */
55 const ONBOARDING_KEY = 'onboardingCompletedAt';
56
57 /**
58 * Declare the setting so core's settings route exposes it.
59 *
60 * Call on `rest_api_init`: core builds the settings route from the registered settings at
61 * priority 99, so anything later would leave the option off the route's write schema. Both
62 * hosts may call this; a repeat call re-declares the same setting and is harmless.
63 *
64 * @since 0.6.0
65 *
66 * @return void
67 */
68 public static function register() {
69 register_setting(
70 'general',
71 self::ENABLED_OPTION,
72 array(
73 'type' => 'boolean',
74 'default' => false,
75 'show_in_rest' => true,
76 'sanitize_callback' => array( __CLASS__, 'sanitize_enabled' ),
77 'description' => __( 'Whether the Premium Analytics dashboard is enabled for this site.', 'jetpack-premium-analytics-pkg' ),
78 )
79 );
80 add_action( 'update_option_' . self::ENABLED_OPTION, array( __CLASS__, 'reset_onboarding_on_reactivation' ), 10, 2 );
81 }
82
83 /**
84 * Store the opt-in as 0 or 1.
85 *
86 * Without this, switching the dashboard off stores `''`: core's settings controller hands
87 * `update_option()` a bare `false`, which reaches the options table as an empty string. The
88 * REST schema does not accept that as a boolean, so the next read reports `null` rather than
89 * `false`, and a later `null` write answers 500 `rest_invalid_stored_value`.
90 *
91 * @since 0.6.0
92 *
93 * @param mixed $value Value being written.
94 * @return int
95 */
96 public static function sanitize_enabled( $value ) {
97 return (int) rest_sanitize_boolean( $value );
98 }
99
100 /**
101 * Forget that the reader switching the dashboard back on has seen the onboarding.
102 *
103 * Someone who switched off and came back gets the tour again; a first activation, a
104 * switch-off, and everyone else's preference are left alone. Riding on the option write means
105 * only writes made while the setting is registered count, which is every product path: the
106 * classic Stats banner and menu, and the dashboard's own switch-off, all go through REST.
107 *
108 * The preference lives in core's persisted preferences user meta, whose client-side layer
109 * keeps a localStorage copy and takes whichever is newer, so `_modified` moves with the change.
110 *
111 * @since 0.6.0
112 *
113 * @param mixed $old_value Previous option value.
114 * @param mixed $value New option value.
115 * @return void
116 */
117 public static function reset_onboarding_on_reactivation( $old_value, $value ) {
118 if ( (bool) $old_value || ! (bool) $value ) {
119 return;
120 }
121
122 $user_id = get_current_user_id();
123 if ( ! $user_id ) {
124 return;
125 }
126
127 global $wpdb;
128 $meta_key = $wpdb->get_blog_prefix() . 'persisted_preferences';
129 $preferences = get_user_meta( $user_id, $meta_key, true );
130
131 if ( ! is_array( $preferences ) || ! isset( $preferences[ self::PREFERENCES_SCOPE ][ self::ONBOARDING_KEY ] ) ) {
132 return;
133 }
134
135 unset( $preferences[ self::PREFERENCES_SCOPE ][ self::ONBOARDING_KEY ] );
136 $preferences['_modified'] = gmdate( 'Y-m-d\TH:i:s\Z' );
137
138 update_user_meta( $user_id, $meta_key, $preferences );
139 }
140 }
141