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-premium-analytics/src/class-enablement-setting.php +140 -0 16.2-beta → 16.3 View file →
@@ -1,0 +1,140 @@
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 +}