PluginProbe
Yoast SEO – Advanced SEO with real-time guidance and built-in AI / 28.3
Yoast SEO – Advanced SEO with real-time guidance and built-in AI v28.3
28.4 28.3 28.2 28.1 28.0 27.9 27.8 27.7 27.6 27.5 trunk 18.0 18.1 18.2 18.3 18.4 18.4.1 18.5 18.5.1 18.6 18.7 18.8 18.9 19.0 19.1 All 128 releases
wordpress-seo / admin / tracking / class-tracking.php

class-tracking.php in Yoast SEO – Advanced SEO with real-time guidance and built-in AI 28.3, at admin/tracking/class-tracking.php

241 lines 6.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * WPSEO plugin file.
4 *
5 * @package WPSEO\Admin\Tracking
6 */
7
8 use Yoast\WP\SEO\Analytics\Application\Missing_Indexables_Collector;
9 use Yoast\WP\SEO\Analytics\Application\To_Be_Cleaned_Indexables_Collector;
10
11 /**
12 * This class handles the tracking routine.
13 */
14 class WPSEO_Tracking implements WPSEO_WordPress_Integration {
15
16 /**
17 * The tracking option name.
18 *
19 * @var string
20 */
21 protected $option_name = 'wpseo_tracking_last_request';
22
23 /**
24 * The limit for the option.
25 *
26 * @var int
27 */
28 protected $threshold = 0;
29
30 /**
31 * The endpoint to send the data to.
32 *
33 * @var string
34 */
35 protected $endpoint = '';
36
37 /**
38 * The current time.
39 *
40 * @var int
41 */
42 private $current_time;
43
44 /**
45 * WPSEO_Tracking constructor.
46 *
47 * @param string $endpoint The endpoint to send the data to.
48 * @param int $threshold The limit for the option.
49 */
50 public function __construct( $endpoint, $threshold ) {
51 if ( ! $this->tracking_enabled() ) {
52 return;
53 }
54
55 $this->endpoint = $endpoint;
56 $this->threshold = $threshold;
57 $this->current_time = time();
58 }
59
60 /**
61 * Registers all hooks to WordPress.
62 *
63 * @return void
64 */
65 public function register_hooks() {
66 if ( ! $this->tracking_enabled() ) {
67 return;
68 }
69
70 // Send tracking data on `admin_init`.
71 add_action( 'admin_init', [ $this, 'send' ], 1 );
72
73 // Add an action hook that will be triggered at the specified time by `wp_schedule_single_event()`.
74 add_action( 'wpseo_send_tracking_data_after_core_update', [ $this, 'send' ] );
75 // Call `wp_schedule_single_event()` after a WordPress core update.
76 add_action( 'upgrader_process_complete', [ $this, 'schedule_tracking_data_sending' ], 10, 2 );
77 }
78
79 /**
80 * Schedules a new sending of the tracking data after a WordPress core update.
81 *
82 * @param bool|WP_Upgrader $upgrader Optional. WP_Upgrader instance or false.
83 * Depending on context, it might be a Theme_Upgrader,
84 * Plugin_Upgrader, Core_Upgrade, or Language_Pack_Upgrader.
85 * instance. Default false.
86 * @param array $data Array of update data.
87 *
88 * @return void
89 */
90 public function schedule_tracking_data_sending( $upgrader = false, $data = [] ) {
91 // Return if it's not a WordPress core update.
92 if ( ! $upgrader || ! isset( $data['type'] ) || $data['type'] !== 'core' ) {
93 return;
94 }
95
96 /*
97 * To uniquely identify the scheduled cron event, `wp_next_scheduled()`
98 * needs to receive the same arguments as those used when originally
99 * scheduling the event otherwise it will always return false.
100 */
101 if ( ! wp_next_scheduled( 'wpseo_send_tracking_data_after_core_update', [ true ] ) ) {
102 /*
103 * Schedule sending of data tracking 6 hours after a WordPress core
104 * update. Pass a `true` parameter for the callback `$force` argument.
105 */
106 wp_schedule_single_event( ( time() + ( HOUR_IN_SECONDS * 6 ) ), 'wpseo_send_tracking_data_after_core_update', [ true ] );
107 }
108 }
109
110 /**
111 * Sends the tracking data.
112 *
113 * @param bool $force Whether to send the tracking data ignoring the two
114 * weeks time threshold. Default false.
115 *
116 * @return void
117 */
118 public function send( $force = false ) {
119 if ( ! $this->should_send_tracking( $force ) ) {
120 return;
121 }
122
123 // Set a 'content-type' header of 'application/json'.
124 $tracking_request_args = [
125 'headers' => [
126 'content-type:' => 'application/json',
127 ],
128 ];
129
130 $collector = $this->get_collector();
131
132 $request = new WPSEO_Remote_Request( $this->endpoint, $tracking_request_args );
133 $request->set_body( $collector->get_as_json() );
134 $request->send();
135
136 update_option( $this->option_name, $this->current_time, 'yes' );
137 }
138
139 /**
140 * Determines whether to send the tracking data.
141 *
142 * Returns false if tracking is disabled or the current page is one of the
143 * admin plugins pages. Returns true when there's no tracking data stored or
144 * the data was sent more than two weeks ago. The two weeks interval is set
145 * when instantiating the class.
146 *
147 * @param bool $ignore_time_treshhold Whether to send the tracking data ignoring
148 * the two weeks time treshhold. Default false.
149 *
150 * @return bool True when tracking data should be sent.
151 */
152 protected function should_send_tracking( $ignore_time_treshhold = false ) {
153 global $pagenow;
154
155 // Only send tracking on the main site of a multi-site instance. This returns true on non-multisite installs.
156 if ( is_network_admin() || ! is_main_site() ) {
157 return false;
158 }
159
160 // Because we don't want to possibly block plugin actions with our routines.
161 if ( in_array( $pagenow, [ 'plugins.php', 'plugin-install.php', 'plugin-editor.php' ], true ) ) {
162 return false;
163 }
164
165 $last_time = get_option( $this->option_name );
166
167 // When tracking data haven't been sent yet or when sending data is forced.
168 if ( ! $last_time || $ignore_time_treshhold ) {
169 return true;
170 }
171
172 return $this->exceeds_treshhold( $this->current_time - $last_time );
173 }
174
175 /**
176 * Checks if the given amount of seconds exceeds the set threshold.
177 *
178 * @param int $seconds The amount of seconds to check.
179 *
180 * @return bool True when seconds is bigger than threshold.
181 */
182 protected function exceeds_treshhold( $seconds ) {
183 return ( $seconds > $this->threshold );
184 }
185
186 /**
187 * Returns the collector for collecting the data.
188 *
189 * @return WPSEO_Collector The instance of the collector.
190 */
191 public function get_collector() {
192 $collector = new WPSEO_Collector();
193 $collector->add_collection( new WPSEO_Tracking_Default_Data() );
194 $collector->add_collection( new WPSEO_Tracking_Server_Data() );
195 $collector->add_collection( new WPSEO_Tracking_Theme_Data() );
196 $collector->add_collection( new WPSEO_Tracking_Plugin_Data() );
197 $collector->add_collection( new WPSEO_Tracking_Settings_Data() );
198 $collector->add_collection( new WPSEO_Tracking_Addon_Data() );
199 $collector->add_collection( YoastSEO()->classes->get( Missing_Indexables_Collector::class ) );
200 $collector->add_collection( YoastSEO()->classes->get( To_Be_Cleaned_Indexables_Collector::class ) );
201
202 return $collector;
203 }
204
205 /**
206 * See if we should run tracking at all.
207 *
208 * @return bool True when we can track, false when we can't.
209 */
210 private function tracking_enabled() {
211 // Check if we're allowing tracking.
212 $tracking = WPSEO_Options::get( 'tracking' );
213
214 if ( $tracking === false ) {
215 return false;
216 }
217
218 // Save this state.
219 if ( $tracking === null ) {
220 /**
221 * Filter: 'wpseo_enable_tracking' - Enables the data tracking of Yoast SEO Premium and add-ons.
222 *
223 * @param string|false $is_enabled The enabled state. Default is false.
224 */
225 $tracking = apply_filters( 'wpseo_enable_tracking', false );
226
227 WPSEO_Options::set( 'tracking', $tracking );
228 }
229
230 if ( $tracking === false ) {
231 return false;
232 }
233
234 if ( ! YoastSEO()->helpers->environment->is_production_mode() ) {
235 return false;
236 }
237
238 return true;
239 }
240 }
241