PluginProbe ʕ •ᴥ•ʔ
Starter Templates – AI-Powered Templates for Elementor & Gutenberg / 4.0.7
Starter Templates – AI-Powered Templates for Elementor & Gutenberg v4.0.7
4.6.1 4.6.0 4.5.4 4.5.3 2.3.6 2.3.7 2.3.8 2.3.9 2.4.0 2.5.0 2.5.1 2.6.0 2.6.1 2.6.10 2.6.11 2.6.12 2.6.13 2.6.14 2.6.15 2.6.16 2.6.17 2.6.18 2.6.19 2.6.2 2.6.20 2.6.21 2.6.22 2.6.3 2.6.4 2.6.5 2.6.6 2.6.7 2.6.8 2.6.9 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 3.0.0 3.0.1 3.0.10 3.0.11 3.0.12 3.0.13 3.0.14 3.0.15 3.0.16 3.0.17 3.0.18 3.0.19 3.0.2 3.0.20 3.0.21 3.0.22 3.0.23 3.0.24 3.0.25 3.0.3 3.0.4 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.1 3.1.10 3.1.11 3.1.12 3.1.13 3.1.14 3.1.15 3.1.16 3.1.17 3.1.18 3.1.19 3.1.2 3.1.20 3.1.21 3.1.22 3.1.23 3.1.24 3.1.25 3.1.26 3.1.27 3.1.3 3.1.4 3.1.5 3.1.6 3.1.7 3.1.8 3.1.9 3.2.0 3.2.1 3.2.2 3.2.3 3.2.4 3.2.5 3.2.6 3.3.0 3.4.0 3.4.1 3.4.2 3.4.3 3.4.4 3.4.5 3.4.6 3.5.0 3.5.1 3.5.2 3.5.3 3.5.4 3.5.5 3.5.6 3.5.7 4.0.0 4.0.1 4.0.10 4.0.11 4.0.12 4.0.13 4.0.2 4.0.3 4.0.4 4.0.5 4.0.6 4.0.7 4.0.8 4.0.9 4.1.0 4.1.1 4.1.2 4.1.3 4.1.4 4.1.5 4.1.6 4.1.7 4.2.0 4.2.1 4.2.2 4.2.3 4.2.4 4.2.5 4.2.6 4.3.0 4.3.1 4.3.2 4.3.3 4.3.4 4.3.5 4.3.6 4.3.7 4.3.8 4.3.9 4.4.0 4.4.1 4.4.10 4.4.11 4.4.12 4.4.13 4.4.14 4.4.16 4.4.17 4.4.18 4.4.19 4.4.2 4.4.20 4.4.21 4.4.22 4.4.23 4.4.24 trunk 4.4.25 0.4.4.0 4.4.26 0.4.4.15 4.4.27 1.0.0 4.4.28 1.0.1 4.4.29 1.0.10 4.4.3 1.0.11 4.4.30 1.0.12 4.4.31 1.0.13 4.4.32 1.0.14 4.4.33 1.0.2 4.4.34 1.0.3 4.4.35 1.0.4 4.4.36 1.0.5 4.4.37 1.0.6 4.4.38 1.0.7 4.4.39 1.0.8 4.4.4 1.0.9 4.4.40 1.1.0 4.4.41 1.1.1 4.4.42 1.1.2 4.4.43 1.1.3 4.4.44 1.1.4 4.4.45 1.1.5 4.4.46 1.1.6 4.4.47 1.1.7 4.4.48 1.1.8 4.4.49 1.1.9 4.4.5 1.2.0 4.4.50 1.2.1 4.4.51 1.2.10 4.4.52 1.2.11 4.4.6 1.2.12 4.4.7 1.2.13 4.4.8 1.2.14 4.4.9 1.2.15 4.5.0 1.2.2 4.5.1 1.2.3 4.5.2 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 1.3.0 1.3.1 1.3.10 1.3.11 1.3.13 1.3.14 1.3.15 1.3.16 1.3.17 1.3.18 1.3.19 1.3.2 1.3.20 1.3.21 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 2.0.0 2.0.1 2.0.2 2.1.0 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.3.0 2.3.1 2.3.2 2.3.3 2.3.4 2.3.5
astra-sites / admin / bsf-analytics / class-bsf-analytics.php
astra-sites / admin / bsf-analytics Last commit date
assets 4 years ago class-bsf-analytics-loader.php 5 years ago class-bsf-analytics-stats.php 4 years ago class-bsf-analytics.php 3 years ago version.json 3 years ago
class-bsf-analytics.php
515 lines
1 <?php
2 /**
3 * BSF analytics class file.
4 *
5 * @version 1.0.0
6 *
7 * @package bsf-analytics
8 */
9
10 if ( ! defined( 'ABSPATH' ) ) {
11 exit; // Exit if accessed directly.
12 }
13
14 if ( ! class_exists( 'BSF_Analytics' ) ) {
15
16 /**
17 * BSF analytics
18 */
19 class BSF_Analytics {
20
21 /**
22 * Member Variable
23 *
24 * @var array Entities data.
25 */
26 private $entities;
27
28 /**
29 * Member Variable
30 *
31 * @var string Usage tracking document URL
32 */
33 public $usage_doc_link = 'https://store.brainstormforce.com/usage-tracking/?utm_source=wp_dashboard&utm_medium=general_settings&utm_campaign=usage_tracking';
34
35 /**
36 * Setup actions, load files.
37 *
38 * @param array $args entity data for analytics.
39 * @param string $analytics_path directory path to analytics library.
40 * @param float $analytics_version analytics library version.
41 * @since 1.0.0
42 */
43 public function __construct( $args, $analytics_path, $analytics_version ) {
44
45 // Bail when no analytics entities are registered.
46 if ( empty( $args ) ) {
47 return;
48 }
49
50 $this->entities = $args;
51
52 define( 'BSF_ANALYTICS_VERSION', $analytics_version );
53 define( 'BSF_ANALYTICS_URI', $this->get_analytics_url( $analytics_path ) );
54
55 add_action( 'admin_init', array( $this, 'handle_optin_optout' ) );
56 add_action( 'admin_init', array( $this, 'option_notice' ) );
57 add_action( 'init', array( $this, 'maybe_track_analytics' ), 99 );
58
59 $this->set_actions();
60
61 add_action( 'admin_init', array( $this, 'register_usage_tracking_setting' ) );
62
63 $this->includes();
64 }
65
66 /**
67 * Setup actions for admin notice style and analytics cron event.
68 *
69 * @since 1.0.4
70 */
71 public function set_actions() {
72
73 foreach ( $this->entities as $key => $data ) {
74 add_action( 'astra_notice_before_markup_' . $key . '-optin-notice', array( $this, 'enqueue_assets' ) );
75 add_action( 'update_option_' . $key . '_analytics_optin', array( $this, 'update_analytics_option_callback' ), 10, 3 );
76 add_action( 'add_option_' . $key . '_analytics_optin', array( $this, 'add_analytics_option_callback' ), 10, 2 );
77 }
78 }
79
80 /**
81 * BSF Analytics URL
82 *
83 * @param string $analytics_path directory path to analytics library.
84 * @return String URL of bsf-analytics directory.
85 * @since 1.0.0
86 */
87 public function get_analytics_url( $analytics_path ) {
88
89 $content_dir_path = wp_normalize_path( WP_CONTENT_DIR );
90
91 $analytics_path = wp_normalize_path( $analytics_path );
92
93 return str_replace( $content_dir_path, content_url(), $analytics_path );
94 }
95
96 /**
97 * Get API URL for sending analytics.
98 *
99 * @return string API URL.
100 * @since 1.0.0
101 */
102 private function get_api_url() {
103 return defined( 'BSF_API_URL' ) ? BSF_API_URL : 'https://support.brainstormforce.com/';
104 }
105
106 /**
107 * Enqueue Scripts.
108 *
109 * @since 1.0.0
110 * @return void
111 */
112 public function enqueue_assets() {
113
114 /**
115 * Load unminified if SCRIPT_DEBUG is true.
116 *
117 * Directory and Extensions.
118 */
119 $dir_name = ( SCRIPT_DEBUG ) ? 'unminified' : 'minified';
120 $file_rtl = ( is_rtl() ) ? '-rtl' : '';
121 $css_ext = ( SCRIPT_DEBUG ) ? '.css' : '.min.css';
122
123 $css_uri = BSF_ANALYTICS_URI . '/assets/css/' . $dir_name . '/style' . $file_rtl . $css_ext;
124
125 wp_enqueue_style( 'bsf-analytics-admin-style', $css_uri, false, BSF_ANALYTICS_VERSION, 'all' );
126 }
127
128 /**
129 * Send analytics API call.
130 *
131 * @since 1.0.0
132 */
133 public function send() {
134 wp_remote_post(
135 $this->get_api_url() . 'wp-json/bsf-core/v1/analytics/',
136 array(
137 'body' => BSF_Analytics_Stats::instance()->get_stats(),
138 'timeout' => 5,
139 'blocking' => false,
140 )
141 );
142 }
143
144 /**
145 * Check if usage tracking is enabled.
146 *
147 * @return bool
148 * @since 1.0.0
149 */
150 public function is_tracking_enabled() {
151
152 foreach ( $this->entities as $key => $data ) {
153
154 $is_enabled = get_site_option( $key . '_analytics_optin' ) === 'yes' ? true : false;
155 $is_enabled = $this->is_white_label_enabled( $key ) ? false : $is_enabled;
156
157 if ( apply_filters( $key . '_tracking_enabled', $is_enabled ) ) {
158 return true;
159 }
160 }
161
162 return false;
163 }
164
165 /**
166 * Check if WHITE label is enabled for BSF products.
167 *
168 * @param string $source source of analytics.
169 * @return bool
170 * @since 1.0.0
171 */
172 public function is_white_label_enabled( $source ) {
173
174 $options = apply_filters( $source . '_white_label_options', array() );
175 $is_enabled = false;
176
177 if ( is_array( $options ) ) {
178 foreach ( $options as $option ) {
179 if ( true === $option ) {
180 $is_enabled = true;
181 break;
182 }
183 }
184 }
185
186 return $is_enabled;
187 }
188
189 /**
190 * Display admin notice for usage tracking.
191 *
192 * @since 1.0.0
193 */
194 public function option_notice() {
195
196 if ( ! current_user_can( 'manage_options' ) ) {
197 return;
198 }
199
200 foreach ( $this->entities as $key => $data ) {
201
202 $time_to_display = isset( $data['time_to_display'] ) ? $data['time_to_display'] : '+24 hours';
203 $usage_doc_link = isset( $data['usage_doc_link'] ) ? $data['usage_doc_link'] : $this->usage_doc_link;
204
205 // Don't display the notice if tracking is disabled or White Label is enabled for any of our plugins.
206 if ( false !== get_site_option( $key . '_analytics_optin', false ) || $this->is_white_label_enabled( $key ) ) {
207 continue;
208 }
209
210 // Show tracker consent notice after 24 hours from installed time.
211 if ( strtotime( $time_to_display, $this->get_analytics_install_time( $key ) ) > time() ) {
212 continue;
213 }
214
215 /* translators: %s product name */
216 $notice_string = __( 'Want to help make <strong>%1s</strong> even more awesome? Allow us to collect non-sensitive diagnostic data and usage information. ', 'astra-sites' );
217
218 if ( is_multisite() ) {
219 $notice_string .= __( 'This will be applicable for all sites from the network.', 'astra-sites' );
220 }
221
222 $language_dir = is_rtl() ? 'rtl' : 'ltr';
223
224 Astra_Notices::add_notice(
225 array(
226 'id' => $key . '-optin-notice',
227 'type' => '',
228 'message' => sprintf(
229 '<div class="notice-content">
230 <div class="notice-heading">
231 %1$s
232 </div>
233 <div class="astra-notices-container">
234 <a href="%2$s" class="astra-notices button-primary">
235 %3$s
236 </a>
237 <a href="%4$s" data-repeat-notice-after="%5$s" class="astra-notices button-secondary">
238 %6$s
239 </a>
240 </div>
241 </div>',
242 /* translators: %s usage doc link */
243 sprintf( $notice_string . '<span dir="%2s"><a href="%3s" target="_blank" rel="noreferrer noopener">%4s</a><span>', esc_html( $data['product_name'] ), $language_dir, esc_url( $usage_doc_link ), __( ' Know More.', 'astra-sites' ) ),
244 esc_url(
245 add_query_arg(
246 array(
247 $key . '_analytics_optin' => 'yes',
248 $key . '_analytics_nonce' => wp_create_nonce( $key . '_analytics_optin' ),
249 'bsf_analytics_source' => $key,
250 )
251 )
252 ),
253 __( 'Yes! Allow it', 'astra-sites' ),
254 esc_url(
255 add_query_arg(
256 array(
257 $key . '_analytics_optin' => 'no',
258 $key . '_analytics_nonce' => wp_create_nonce( $key . '_analytics_optin' ),
259 'bsf_analytics_source' => $key,
260 )
261 )
262 ),
263 MONTH_IN_SECONDS,
264 __( 'No Thanks', 'astra-sites' )
265 ),
266 'show_if' => true,
267 'repeat-notice-after' => false,
268 'priority' => 18,
269 'display-with-other-notices' => true,
270 )
271 );
272 }
273 }
274
275 /**
276 * Process usage tracking opt out.
277 *
278 * @since 1.0.0
279 */
280 public function handle_optin_optout() {
281
282 if ( ! current_user_can( 'manage_options' ) ) {
283 return;
284 }
285
286 $source = isset( $_GET['bsf_analytics_source'] ) ? sanitize_text_field( wp_unslash( $_GET['bsf_analytics_source'] ) ) : '';
287
288 if ( ! isset( $_GET[ $source . '_analytics_nonce' ] ) ) {
289 return;
290 }
291
292 if ( ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET[ $source . '_analytics_nonce' ] ) ), $source . '_analytics_optin' ) ) {
293 return;
294 }
295
296 $optin_status = isset( $_GET[ $source . '_analytics_optin' ] ) ? sanitize_text_field( wp_unslash( $_GET[ $source . '_analytics_optin' ] ) ) : '';
297
298 if ( 'yes' === $optin_status ) {
299 $this->optin( $source );
300 } elseif ( 'no' === $optin_status ) {
301 $this->optout( $source );
302 }
303
304 wp_safe_redirect(
305 esc_url_raw(
306 remove_query_arg(
307 array(
308 $source . '_analytics_optin',
309 $source . '_analytics_nonce',
310 'bsf_analytics_source',
311 )
312 )
313 )
314 );
315 }
316
317 /**
318 * Opt in to usage tracking.
319 *
320 * @param string $source source of analytics.
321 * @since 1.0.0
322 */
323 private function optin( $source ) {
324 update_site_option( $source . '_analytics_optin', 'yes' );
325 }
326
327 /**
328 * Opt out to usage tracking.
329 *
330 * @param string $source source of analytics.
331 * @since 1.0.0
332 */
333 private function optout( $source ) {
334 update_site_option( $source . '_analytics_optin', 'no' );
335 }
336
337 /**
338 * Load analytics stat class.
339 *
340 * @since 1.0.0
341 */
342 private function includes() {
343 require_once __DIR__ . '/class-bsf-analytics-stats.php';
344 }
345
346 /**
347 * Register usage tracking option in General settings page.
348 *
349 * @since 1.0.0
350 */
351 public function register_usage_tracking_setting() {
352
353 foreach ( $this->entities as $key => $data ) {
354
355 if ( ! apply_filters( $key . '_tracking_enabled', true ) || $this->is_white_label_enabled( $key ) ) {
356 return;
357 }
358
359 $usage_doc_link = isset( $data['usage_doc_link'] ) ? $data['usage_doc_link'] : $this->usage_doc_link;
360 $author = isset( $data['author'] ) ? $data['author'] : 'Brainstorm Force';
361
362 register_setting(
363 'general', // Options group.
364 $key . '_analytics_optin', // Option name/database.
365 array( 'sanitize_callback' => array( $this, 'sanitize_option' ) ) // sanitize callback function.
366 );
367
368 add_settings_field(
369 $key . '-analytics-optin', // Field ID.
370 __( 'Usage Tracking', 'astra-sites' ), // Field title.
371 array( $this, 'render_settings_field_html' ), // Field callback function.
372 'general',
373 'default', // Settings page slug.
374 array(
375 'type' => 'checkbox',
376 'title' => $author,
377 'name' => $key . '_analytics_optin',
378 'label_for' => $key . '-analytics-optin',
379 'id' => $key . '-analytics-optin',
380 'usage_doc_link' => $usage_doc_link,
381 )
382 );
383 }
384 }
385
386 /**
387 * Sanitize Callback Function
388 *
389 * @param bool $input Option value.
390 * @since 1.0.0
391 */
392 public function sanitize_option( $input ) {
393
394 if ( ! $input || 'no' === $input ) {
395 return 'no';
396 }
397
398 return 'yes';
399 }
400
401 /**
402 * Print settings field HTML.
403 *
404 * @param array $args arguments to field.
405 * @since 1.0.0
406 */
407 public function render_settings_field_html( $args ) {
408 ?>
409 <fieldset>
410 <label for="<?php echo esc_attr( $args['label_for'] ); ?>">
411 <input id="<?php echo esc_attr( $args['id'] ); ?>" type="checkbox" value="1" name="<?php echo esc_attr( $args['name'] ); ?>" <?php checked( get_site_option( $args['name'], 'no' ), 'yes' ); ?>>
412 <?php
413 /* translators: %s Product title */
414 echo esc_html( sprintf( __( 'Allow %s products to track non-sensitive usage tracking data.', 'astra-sites' ), $args['title'] ) );// phpcs:ignore WordPress.WP.I18n.NonSingularStringLiteralText
415
416 if ( is_multisite() ) {
417 esc_html_e( ' This will be applicable for all sites from the network.', 'astra-sites' );
418 }
419 ?>
420 </label>
421 <?php
422 echo wp_kses_post( sprintf( '<a href="%1s" target="_blank" rel="noreferrer noopener">%2s</a>', esc_url( $args['usage_doc_link'] ), __( 'Learn More.', 'astra-sites' ) ) );
423 ?>
424 </fieldset>
425 <?php
426 }
427
428 /**
429 * Set analytics installed time in option.
430 *
431 * @param string $source source of analytics.
432 * @return string $time analytics installed time.
433 * @since 1.0.0
434 */
435 private function get_analytics_install_time( $source ) {
436
437 $time = get_site_option( $source . '_analytics_installed_time' );
438
439 if ( ! $time ) {
440 $time = time();
441 update_site_option( $source . '_analytics_installed_time', time() );
442 }
443
444 return $time;
445 }
446
447 /**
448 * Schedule/unschedule cron event on updation of option.
449 *
450 * @param string $old_value old value of option.
451 * @param string $value value of option.
452 * @param string $option Option name.
453 * @since 1.0.0
454 */
455 public function update_analytics_option_callback( $old_value, $value, $option ) {
456 if ( is_multisite() ) {
457 $this->add_option_to_network( $option, $value );
458 }
459 }
460
461 /**
462 * Analytics option add callback.
463 *
464 * @param string $option Option name.
465 * @param string $value value of option.
466 * @since 1.0.0
467 */
468 public function add_analytics_option_callback( $option, $value ) {
469 if ( is_multisite() ) {
470 $this->add_option_to_network( $option, $value );
471 }
472 }
473
474 /**
475 * Send analaytics track event if tracking is enabled.
476 *
477 * @since 1.0.0
478 */
479 public function maybe_track_analytics() {
480
481 if ( ! $this->is_tracking_enabled() ) {
482 return;
483 }
484
485 $analytics_track = get_site_transient( 'bsf_analytics_track' );
486
487 // If the last data sent is 2 days old i.e. transient is expired.
488 if ( ! $analytics_track ) {
489 $this->send();
490 set_site_transient( 'bsf_analytics_track', true, 2 * DAY_IN_SECONDS );
491 }
492 }
493
494 /**
495 * Save analytics option to network.
496 *
497 * @param string $option name of option.
498 * @param string $value value of option.
499 * @since 1.0.0
500 */
501 public function add_option_to_network( $option, $value ) {
502
503 // If action coming from general settings page.
504 if ( isset( $_POST['option_page'] ) && 'general' === $_POST['option_page'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
505
506 if ( get_site_option( $option ) ) {
507 update_site_option( $option, $value );
508 } else {
509 add_site_option( $option, $value );
510 }
511 }
512 }
513 }
514 }
515