PluginProbe
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO / 2.10.0
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO v2.10.0
2.10.0 2.9.0 2.8.0 2.7.0 2.6.0 2.5.0 2.4.0 2.3.0 2.2.0 2.1.1 2.1.0 2.0.2 2.0.1 2.0.0 1.32.0 1.31.0 1.30.0 1.29.0 1.28.0 1.27.0 1.26.0 1.25.0 trunk 1.0.0 1.0.1 All 51 releases
thinkrank / includes / core / class-usage-tracker-manager.php

class-usage-tracker-manager.php in ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO 2.10.0, at includes/core/class-usage-tracker-manager.php

177 lines 5.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Usage Tracker Manager
5 *
6 * Bootstraps the opt-in Plugin_Usage_Tracker SDK: configures the opt-in
7 * notice copy and registers the tracker hooks on admin init.
8 *
9 * @package ThinkRank\Core
10 * @since 1.12.0
11 */
12
13 declare(strict_types=1);
14
15 namespace ThinkRank\Core;
16
17 // Prevent direct access
18 if (!defined('ABSPATH')) {
19 exit;
20 }
21
22 /**
23 * Usage Tracker Manager
24 *
25 * Single Responsibility: wire the usage tracker into WordPress.
26 *
27 * @since 1.12.0
28 */
29 class Usage_Tracker_Manager {
30
31 /**
32 * WP Insights item id for this product.
33 *
34 * Obtain the real id from the WP Insights dashboard and place it here
35 * (or filter `thinkrank_usage_tracker_item_id`). Without a valid id the
36 * tracker collects data but the initial site registration is skipped,
37 * so nothing is transmitted.
38 *
39 * @var string|false
40 */
41 private const ITEM_ID = '08649e95a94ecddfd027';
42
43 /**
44 * Days after install before the opt-in notice may be shown.
45 *
46 * Activation redirects into the Setup Wizard, which asks for consent
47 * itself. Asking again on the user's first admin page load is noise, so
48 * the card is held back for users who skipped the wizard and only appears
49 * once they have had a chance to use the plugin.
50 *
51 * @var int
52 */
53 private const NOTICE_DELAY_DAYS = 7;
54
55 /**
56 * Option holding the install timestamp the delay is measured from.
57 *
58 * @var string
59 */
60 private const INSTALL_TIME_OPTION = 'thinkrank_usage_notice_since';
61
62 /**
63 * Tracker instance.
64 *
65 * @var Plugin_Usage_Tracker|null
66 */
67 private ?Plugin_Usage_Tracker $tracker = null;
68
69 /**
70 * Register the bootstrap hook.
71 *
72 * Mirrors the reference integration: the tracker is built on `init`
73 * (admin context) so the opt-in notice and cron handlers are wired
74 * once per request. The activation/deactivation hooks are registered
75 * inside the tracker constructor.
76 *
77 * @return void
78 */
79 public function init(): void {
80 add_action('init', [$this, 'start_tracking']);
81 }
82
83 /**
84 * Build and configure the tracker.
85 *
86 * @return void
87 */
88 public function start_tracking(): void {
89 $item_id = apply_filters('thinkrank_usage_tracker_item_id', self::ITEM_ID);
90
91 $this->tracker = Plugin_Usage_Tracker::get_instance(THINKRANK_PLUGIN_FILE, [
92 'opt_in' => true,
93 'goodbye_form' => true,
94 'item_id' => $item_id,
95 ]);
96
97 // Only the admin ever renders the notice, and resolving the baseline
98 // can write an option — neither belongs on a front-end request.
99 if (is_admin()) {
100 $this->tracker->set_notice_after(
101 $this->get_notice_baseline() + (self::NOTICE_DELAY_DAYS * DAY_IN_SECONDS)
102 );
103 }
104
105 $this->tracker->set_notice_options([
106 'notice_title' => __('Want to help make ThinkRank even better?', 'thinkrank'),
107 'notice' => __('Allow us to collect non-sensitive diagnostic data and usage information.', 'thinkrank'),
108 'extra_notice' => __('We collect non-sensitive diagnostic data and plugin usage information — your site URL, WordPress &amp; PHP version, active plugins &amp; theme, and admin email. This lets us keep ThinkRank compatible with the most popular plugins and themes. No spam, we promise.', 'thinkrank'),
109 ]);
110
111 $this->tracker->init();
112 }
113
114 /**
115 * Timestamp the opt-in delay is measured from.
116 *
117 * Deliberately not `thinkrank_activation_time`: the activator rewrites
118 * that on every activation, so deactivating and reactivating would restart
119 * the grace period and a user who toggles the plugin could never be asked.
120 * This option is written once and then left alone.
121 *
122 * On upgrade the baseline is seeded from `thinkrank_activation_time`, so a
123 * site that has had ThinkRank for months is not made to wait another week
124 * before it can be asked — it has been seeing this card on every admin
125 * screen already, and the screen scoping is the change it needs. Only an
126 * install with no activation timestamp at all starts its week now.
127 *
128 * Autoloaded: it is read on every admin request, so the alternative is an
129 * extra query per page load.
130 *
131 * @since 2.8.1
132 * @return int Unix timestamp.
133 */
134 private function get_notice_baseline(): int {
135 $since = (int) get_option(self::INSTALL_TIME_OPTION, 0);
136
137 if ($since > 0) {
138 return $since;
139 }
140
141 $since = (int) get_option('thinkrank_activation_time', 0);
142 if ($since <= 0) {
143 $since = time();
144 }
145
146 // add_option() so a concurrent request cannot move a recorded baseline.
147 add_option(self::INSTALL_TIME_OPTION, $since);
148
149 return $since;
150 }
151
152 /**
153 * Record explicit user consent for usage tracking.
154 *
155 * Called by flows outside the opt-in notice (e.g. the Setup Wizard
156 * "Get Started" action). Builds the tracker if it has not been wired
157 * yet so consent works regardless of hook timing.
158 *
159 * @return void
160 */
161 public function grant_consent(): void {
162 if (null === $this->tracker) {
163 $this->start_tracking();
164 }
165 $this->tracker->opt_in();
166 }
167
168 /**
169 * Expose the tracker instance (mainly for tests / diagnostics).
170 *
171 * @return Plugin_Usage_Tracker|null
172 */
173 public function get_tracker(): ?Plugin_Usage_Tracker {
174 return $this->tracker;
175 }
176 }
177