• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Yoast / wordpress-seo / d6112f48a78380ef0e30c3424c33b8a053eaa052

14 Apr 2025 01:30PM UTC coverage: 52.454% (-2.1%) from 54.594%
d6112f48a78380ef0e30c3424c33b8a053eaa052

Pull #22077

github

web-flow
Merge 68bb84799 into b621a6397
Pull Request #22077: Drop compatibility with PHP 7.2 and 7.3

7827 of 13877 branches covered (56.4%)

Branch coverage included in aggregate %.

29025 of 56379 relevant lines covered (51.48%)

42277.18 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

26.15
/admin/tracking/class-tracking.php
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 ) {
4✔
51
                if ( ! $this->tracking_enabled() ) {
4✔
52
                        return;
2✔
53
                }
54

55
                $this->endpoint     = $endpoint;
2✔
56
                $this->threshold    = $threshold;
2✔
57
                $this->current_time = time();
2✔
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() {
2✔
192
                $collector = new WPSEO_Collector();
2✔
193
                $collector->add_collection( new WPSEO_Tracking_Default_Data() );
2✔
194
                $collector->add_collection( new WPSEO_Tracking_Server_Data() );
2✔
195
                $collector->add_collection( new WPSEO_Tracking_Theme_Data() );
2✔
196
                $collector->add_collection( new WPSEO_Tracking_Plugin_Data() );
2✔
197
                $collector->add_collection( new WPSEO_Tracking_Settings_Data() );
2✔
198
                $collector->add_collection( new WPSEO_Tracking_Addon_Data() );
2✔
199
                $collector->add_collection( YoastSEO()->classes->get( Missing_Indexables_Collector::class ) );
2✔
200
                $collector->add_collection( YoastSEO()->classes->get( To_Be_Cleaned_Indexables_Collector::class ) );
2✔
201

202
                return $collector;
2✔
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
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc