Fullwidth Templates for Any Theme & Page Builder - Version 1.1.1

Version Description

  • Fix: Fixed compatibility with other plugins with respect to the admin notice.
Download this release

Release Info

Developer brainstormworg
Plugin Icon 128x128 Fullwidth Templates for Any Theme & Page Builder
Version 1.1.1
Comparing to
See all releases

Code changes from version 1.1.0 to 1.1.1

admin/bsf-analytics/assets/css/minified/style-rtl.min.css ADDED
@@ -0,0 +1 @@
 
1
+ [ID*="-optin-notice"]{padding:1px 12px;border-right-color:#007cba}[ID*="-optin-notice"] .notice-container{padding-top:10px;padding-bottom:12px}[ID*="-optin-notice"] .notice-content{margin:0}[ID*="-optin-notice"] .notice-heading{padding:0 0 12px 20px}[ID*="-optin-notice"] .button-primary{margin-left:5px}
admin/bsf-analytics/assets/css/minified/style.min-rtl.css DELETED
@@ -1 +0,0 @@
1
- #bsf-optin-notice{padding:1px 12px;border-right-color:#007cba}#bsf-optin-notice .notice-container{padding-top:10px;padding-bottom:12px}#bsf-optin-notice .notice-content{margin:0}#bsf-optin-notice .notice-heading{padding:0 0 12px 20px}#bsf-optin-notice .button-primary{margin-left:5px}
 
admin/bsf-analytics/assets/css/minified/style.min.css CHANGED
@@ -1 +1 @@
1
- #bsf-optin-notice{padding:1px 12px;border-left-color:#007cba}#bsf-optin-notice .notice-container{padding-top:10px;padding-bottom:12px}#bsf-optin-notice .notice-content{margin:0}#bsf-optin-notice .notice-heading{padding:0 20px 12px 0}#bsf-optin-notice .button-primary{margin-right:5px}
1
+ [ID*="-optin-notice"]{padding:1px 12px;border-left-color:#007cba}[ID*="-optin-notice"] .notice-container{padding-top:10px;padding-bottom:12px}[ID*="-optin-notice"] .notice-content{margin:0}[ID*="-optin-notice"] .notice-heading{padding:0 20px 12px 0}[ID*="-optin-notice"] .button-primary{margin-right:5px}
admin/bsf-analytics/assets/css/unminified/style-rtl.css CHANGED
@@ -1,21 +1,21 @@
1
- #bsf-optin-notice {
2
  padding: 1px 12px;
3
  border-right-color: #007cba;
4
  }
5
 
6
- #bsf-optin-notice .notice-container {
7
  padding-top: 10px;
8
  padding-bottom: 12px;
9
  }
10
 
11
- #bsf-optin-notice .notice-content {
12
  margin: 0;
13
  }
14
 
15
- #bsf-optin-notice .notice-heading {
16
  padding: 0 0 12px 20px;
17
  }
18
 
19
- #bsf-optin-notice .button-primary {
20
  margin-left: 5px;
21
  }
1
+ [ID*="-optin-notice"] {
2
  padding: 1px 12px;
3
  border-right-color: #007cba;
4
  }
5
 
6
+ [ID*="-optin-notice"] .notice-container {
7
  padding-top: 10px;
8
  padding-bottom: 12px;
9
  }
10
 
11
+ [ID*="-optin-notice"] .notice-content {
12
  margin: 0;
13
  }
14
 
15
+ [ID*="-optin-notice"] .notice-heading {
16
  padding: 0 0 12px 20px;
17
  }
18
 
19
+ [ID*="-optin-notice"] .button-primary {
20
  margin-left: 5px;
21
  }
admin/bsf-analytics/assets/css/unminified/style.css CHANGED
@@ -1,21 +1,21 @@
1
- #bsf-optin-notice {
2
  padding: 1px 12px;
3
  border-left-color: #007cba;
4
  }
5
 
6
- #bsf-optin-notice .notice-container {
7
  padding-top: 10px;
8
  padding-bottom: 12px;
9
  }
10
 
11
- #bsf-optin-notice .notice-content {
12
  margin: 0;
13
  }
14
 
15
- #bsf-optin-notice .notice-heading {
16
  padding: 0 20px 12px 0;
17
  }
18
 
19
- #bsf-optin-notice .button-primary {
20
  margin-right: 5px;
21
  }
1
+ [ID*="-optin-notice"] {
2
  padding: 1px 12px;
3
  border-left-color: #007cba;
4
  }
5
 
6
+ [ID*="-optin-notice"] .notice-container {
7
  padding-top: 10px;
8
  padding-bottom: 12px;
9
  }
10
 
11
+ [ID*="-optin-notice"] .notice-content {
12
  margin: 0;
13
  }
14
 
15
+ [ID*="-optin-notice"] .notice-heading {
16
  padding: 0 20px 12px 0;
17
  }
18
 
19
+ [ID*="-optin-notice"] .button-primary {
20
  margin-right: 5px;
21
  }
admin/bsf-analytics/class-bsf-analytics-loader.php ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BSF analytics loader file.
4
+ *
5
+ * @version 1.0.0
6
+ *
7
+ * @package bsf-analytics
8
+ */
9
+
10
+ if ( ! defined( 'ABSPATH' ) ) {
11
+ exit();
12
+ }
13
+
14
+ /**
15
+ * Class BSF_Analytics_Loader.
16
+ */
17
+ class BSF_Analytics_Loader {
18
+
19
+ /**
20
+ * Analytics Entities.
21
+ *
22
+ * @access private
23
+ * @var array Entities array.
24
+ */
25
+ private $entities = array();
26
+
27
+ /**
28
+ * Analytics Version.
29
+ *
30
+ * @access private
31
+ * @var float analytics version.
32
+ */
33
+ private $analytics_version = '';
34
+
35
+ /**
36
+ * Analytics path.
37
+ *
38
+ * @access private
39
+ * @var string path array.
40
+ */
41
+ private $analytics_path = '';
42
+
43
+ /**
44
+ * Instance
45
+ *
46
+ * @access private
47
+ * @var object Class object.
48
+ */
49
+ private static $instance = null;
50
+
51
+ /**
52
+ * Get instace of class.
53
+ *
54
+ * @return object
55
+ */
56
+ public static function get_instance() {
57
+ if ( null === self::$instance ) {
58
+ self::$instance = new self();
59
+ }
60
+
61
+ return self::$instance;
62
+ }
63
+
64
+ /**
65
+ * Constructor
66
+ */
67
+ public function __construct() {
68
+ add_action( 'init', array( $this, 'load_analytics' ) );
69
+ }
70
+
71
+ /**
72
+ * Set entity for analytics.
73
+ *
74
+ * @param string $data Entity attributes data.
75
+ * @return void
76
+ */
77
+ public function set_entity( $data ) {
78
+ array_push( $this->entities, $data );
79
+ }
80
+
81
+ /**
82
+ * Load Analytics library.
83
+ *
84
+ * @return void
85
+ */
86
+ public function load_analytics() {
87
+ $unique_entities = array();
88
+
89
+ if ( ! empty( $this->entities ) ) {
90
+ foreach ( $this->entities as $entity ) {
91
+ foreach ( $entity as $key => $data ) {
92
+
93
+ if ( isset( $data['path'] ) ) {
94
+ if ( file_exists( $data['path'] . '/version.json' ) ) {
95
+ $file_contents = file_get_contents( $data['path'] . '/version.json' ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
96
+ $analytics_version = json_decode( $file_contents, 1 );
97
+ $analytics_version = $analytics_version['bsf-analytics-ver'];
98
+
99
+ if ( version_compare( $analytics_version, $this->analytics_version, '>' ) ) {
100
+ $this->analytics_version = $analytics_version;
101
+ $this->analytics_path = $data['path'];
102
+ }
103
+ }
104
+ }
105
+
106
+ if ( ! isset( $unique_entities[ $key ] ) ) {
107
+ $unique_entities[ $key ] = $data;
108
+ }
109
+ }
110
+ }
111
+
112
+ if ( file_exists( $this->analytics_path ) && ! class_exists( 'BSF_Analytics' ) ) {
113
+ require_once $this->analytics_path . '/class-bsf-analytics.php';
114
+ new BSF_Analytics( $unique_entities, $this->analytics_path, $this->analytics_version );
115
+ }
116
+ }
117
+ }
118
+ }
admin/bsf-analytics/class-bsf-analytics-stats.php CHANGED
@@ -194,7 +194,6 @@ if ( ! class_exists( 'BSF_Analytics_Stats' ) ) {
194
  * @since 1.0.0
195
  */
196
  private function get_curl_version() {
197
- $curl = array();
198
  if ( function_exists( 'curl_version' ) ) {
199
  $curl = curl_version(); // phpcs:ignore WordPress.WP.AlternativeFunctions.curl_curl_version
200
  }
194
  * @since 1.0.0
195
  */
196
  private function get_curl_version() {
 
197
  if ( function_exists( 'curl_version' ) ) {
198
  $curl = curl_version(); // phpcs:ignore WordPress.WP.AlternativeFunctions.curl_curl_version
199
  }
admin/bsf-analytics/class-bsf-analytics.php CHANGED
@@ -18,60 +18,79 @@ if ( ! class_exists( 'BSF_Analytics' ) ) {
18
  */
19
  class BSF_Analytics {
20
 
 
 
 
 
 
 
 
21
  /**
22
  * Member Variable
23
  *
24
  * @var string Usage tracking document URL
25
  */
26
- private $usage_doc_link = 'https://store.brainstormforce.com/usage-tracking/?utm_source=wp_dashboard&utm_medium=general_settings&utm_campaign=usage_tracking';
27
 
28
  /**
29
  * Setup actions, load files.
30
  *
 
 
 
31
  * @since 1.0.0
32
  */
33
- public function __construct() {
 
 
 
 
 
 
 
34
 
35
- define( 'BSF_ANALYTICS_FILE', __FILE__ );
36
- define( 'BSF_ANALYTICS_VERSION', '1.0.1' );
37
- define( 'BSF_ANALYTICS_PATH', dirname( __FILE__ ) );
38
- define( 'BSF_ANALYTICS_URI', $this->bsf_analytics_url() );
39
 
40
  add_action( 'admin_init', array( $this, 'handle_optin_optout' ) );
41
- add_action( 'cron_schedules', array( $this, 'every_two_days_schedule' ) );
42
  add_action( 'admin_notices', array( $this, 'option_notice' ) );
43
- add_action( 'astra_notice_before_markup_bsf-optin-notice', array( $this, 'enqueue_assets' ) );
44
 
45
- add_action( 'init', array( $this, 'schedule_unschedule_event' ) );
46
-
47
- if ( ! has_action( 'bsf_analytics_send', array( $this, 'send' ) ) ) {
48
- add_action( 'bsf_analytics_send', array( $this, 'send' ) );
49
- }
50
 
51
  add_action( 'admin_init', array( $this, 'register_usage_tracking_setting' ) );
52
 
53
- add_action( 'update_option_bsf_analytics_optin', array( $this, 'update_analytics_option_callback' ), 10, 3 );
54
- add_action( 'add_option_bsf_analytics_optin', array( $this, 'add_analytics_option_callback' ), 10, 2 );
55
-
56
  $this->includes();
57
  }
58
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
  /**
60
  * BSF Analytics URL
61
  *
 
62
  * @return String URL of bsf-analytics directory.
63
  * @since 1.0.0
64
  */
65
- public function bsf_analytics_url() {
66
 
67
- $path = wp_normalize_path( BSF_ANALYTICS_PATH );
68
- $theme_dir = wp_normalize_path( get_template_directory() );
69
 
70
- if ( strpos( $path, $theme_dir ) !== false ) {
71
- return rtrim( get_template_directory_uri() . '/admin/bsf-analytics/', '/' );
72
- } else {
73
- return rtrim( plugin_dir_url( BSF_ANALYTICS_FILE ), '/' );
74
- }
75
  }
76
 
77
  /**
@@ -129,21 +148,30 @@ if ( ! class_exists( 'BSF_Analytics' ) ) {
129
  * @since 1.0.0
130
  */
131
  public function is_tracking_enabled() {
132
- $is_enabled = get_site_option( 'bsf_analytics_optin' ) === 'yes' ? true : false;
133
- $is_enabled = $this->is_white_label_enabled() ? false : $is_enabled;
134
 
135
- return apply_filters( 'bsf_tracking_enabled', $is_enabled );
 
 
 
 
 
 
 
 
 
 
136
  }
137
 
138
  /**
139
  * Check if WHITE label is enabled for BSF products.
140
  *
 
141
  * @return bool
142
  * @since 1.0.0
143
  */
144
- public function is_white_label_enabled() {
145
 
146
- $options = apply_filters( 'bsf_white_label_options', array() );
147
  $is_enabled = false;
148
 
149
  if ( is_array( $options ) ) {
@@ -169,67 +197,75 @@ if ( ! class_exists( 'BSF_Analytics' ) ) {
169
  return;
170
  }
171
 
172
- // Don't display the notice if tracking is disabled or White Label is enabled for any of our plugins.
173
- if ( false !== get_site_option( 'bsf_analytics_optin', false ) || $this->is_white_label_enabled() ) {
174
- return;
175
- }
176
 
177
- // Show tracker consent notice after 24 hours from installed time.
178
- if ( strtotime( '+24 hours', $this->get_analytics_install_time() ) > time() ) {
179
- return;
180
- }
181
 
182
- /* translators: %s product name */
183
- $notice_string = __( 'Want to help make <strong>%1s</strong> even more awesome? Allow us to collect non-sensitive diagnostic data and usage information. ', 'fullwidth-templates' );
 
 
184
 
185
- if ( is_multisite() ) {
186
- $notice_string .= __( 'This will be applicable for all sites from the network.', 'fullwidth-templates' );
187
- }
 
188
 
189
- $language_dir = is_rtl() ? 'rtl' : 'ltr';
 
190
 
191
- Astra_Notices::add_notice(
192
- array(
193
- 'id' => 'bsf-optin-notice',
194
- 'type' => '',
195
- 'message' => sprintf(
196
- '<div class="notice-content">
197
- <div class="notice-heading">
198
- %1$s
199
- </div>
200
- <div class="astra-notices-container">
201
- <a href="%2$s" class="astra-notices button-primary">
202
- %3$s
203
- </a>
204
- <a href="%4$s" data-repeat-notice-after="%5$s" class="astra-notices button-secondary">
205
- %6$s
206
- </a>
207
- </div>
208
- </div>',
209
- /* translators: %s usage doc link */
210
- sprintf( $notice_string . '<span dir="%2s"><a href="%3s" target="_blank" rel="noreferrer noopener">%4s</a><span>', esc_html( $this->get_product_name() ), $language_dir, esc_url( $this->usage_doc_link ), __( ' Know More.', 'fullwidth-templates' ) ),
211
- add_query_arg(
212
- array(
213
- 'bsf_analytics_optin' => 'yes',
214
- 'bsf_analytics_nonce' => wp_create_nonce( 'bsf_analytics_optin' ),
215
- )
216
- ),
217
- __( 'Yes! Allow it', 'fullwidth-templates' ),
218
- add_query_arg(
219
- array(
220
- 'bsf_analytics_optin' => 'no',
221
- 'bsf_analytics_nonce' => wp_create_nonce( 'bsf_analytics_optin' ),
222
- )
 
 
 
 
 
 
 
 
 
 
 
223
  ),
224
- MONTH_IN_SECONDS,
225
- __( 'No Thanks', 'fullwidth-templates' )
226
- ),
227
- 'show_if' => true,
228
- 'repeat-notice-after' => false,
229
- 'priority' => 18,
230
- 'display-with-other-notices' => true,
231
- )
232
- );
233
  }
234
 
235
  /**
@@ -238,27 +274,35 @@ if ( ! class_exists( 'BSF_Analytics' ) ) {
238
  * @since 1.0.0
239
  */
240
  public function handle_optin_optout() {
241
- if ( ! isset( $_GET['bsf_analytics_nonce'] ) ) {
 
242
  return;
243
  }
244
 
245
- if ( ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['bsf_analytics_nonce'] ) ), 'bsf_analytics_optin' ) ) {
 
 
246
  return;
247
  }
248
 
249
- $optin_status = isset( $_GET['bsf_analytics_optin'] ) ? sanitize_text_field( wp_unslash( $_GET['bsf_analytics_optin'] ) ) : '';
 
 
 
 
250
 
251
  if ( 'yes' === $optin_status ) {
252
- $this->optin();
253
  } elseif ( 'no' === $optin_status ) {
254
- $this->optout();
255
  }
256
 
257
  wp_safe_redirect(
258
  remove_query_arg(
259
  array(
260
- 'bsf_analytics_optin',
261
- 'bsf_analytics_nonce',
 
262
  )
263
  )
264
  );
@@ -267,54 +311,21 @@ if ( ! class_exists( 'BSF_Analytics' ) ) {
267
  /**
268
  * Opt in to usage tracking.
269
  *
 
270
  * @since 1.0.0
271
  */
272
- private function optin() {
273
- update_site_option( 'bsf_analytics_optin', 'yes' );
274
  }
275
 
276
  /**
277
  * Opt out to usage tracking.
278
  *
 
279
  * @since 1.0.0
280
  */
281
- private function optout() {
282
- update_site_option( 'bsf_analytics_optin', 'no' );
283
- }
284
-
285
- /**
286
- * Add two days event schedule variables.
287
- *
288
- * @param array $schedules scheduled array data.
289
- * @since 1.0.0
290
- */
291
- public function every_two_days_schedule( $schedules ) {
292
- $schedules['every_two_days'] = array(
293
- 'interval' => 2 * DAY_IN_SECONDS,
294
- 'display' => __( 'Every two days', 'fullwidth-templates' ),
295
- );
296
-
297
- return $schedules;
298
- }
299
-
300
- /**
301
- * Schedule usage tracking event.
302
- *
303
- * @since 1.0.0
304
- */
305
- private function schedule_event() {
306
- if ( ! wp_next_scheduled( 'bsf_analytics_send' ) && $this->is_tracking_enabled() ) {
307
- wp_schedule_event( time(), 'every_two_days', 'bsf_analytics_send' );
308
- }
309
- }
310
-
311
- /**
312
- * Unschedule usage tracking event.
313
- *
314
- * @since 1.0.0
315
- */
316
- private function unschedule_event() {
317
- wp_clear_scheduled_hook( 'bsf_analytics_send' );
318
  }
319
 
320
  /**
@@ -333,22 +344,37 @@ if ( ! class_exists( 'BSF_Analytics' ) ) {
333
  */
334
  public function register_usage_tracking_setting() {
335
 
336
- if ( ! apply_filters( 'bsf_tracking_enabled', true ) || $this->is_white_label_enabled() ) {
337
- return;
338
- }
339
 
340
- register_setting(
341
- 'general', // Options group.
342
- 'bsf_analytics_optin', // Option name/database.
343
- array( 'sanitize_callback' => array( $this, 'sanitize_option' ) ) // sanitize callback function.
344
- );
345
 
346
- add_settings_field(
347
- 'bsf-analytics-optin', // Field ID.
348
- __( 'Usage Tracking', 'fullwidth-templates' ), // Field title.
349
- array( $this, 'render_settings_field_html' ), // Field callback function.
350
- 'general' // Settings page slug.
351
- );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
352
  }
353
 
354
  /**
@@ -369,15 +395,17 @@ if ( ! class_exists( 'BSF_Analytics' ) ) {
369
  /**
370
  * Print settings field HTML.
371
  *
 
372
  * @since 1.0.0
373
  */
374
- public function render_settings_field_html() {
375
  ?>
376
  <fieldset>
377
- <label for="bsf-analytics-optin">
378
- <input id="bsf-analytics-optin" type="checkbox" value="1" name="bsf_analytics_optin" <?php checked( get_site_option( 'bsf_analytics_optin', 'no' ), 'yes' ); ?>>
379
  <?php
380
- esc_html_e( 'Allow Brainstorm Force products to track non-sensitive usage tracking data.', 'fullwidth-templates' );
 
381
 
382
  if ( is_multisite() ) {
383
  esc_html_e( ' This will be applicable for all sites from the network.', 'fullwidth-templates' );
@@ -385,72 +413,26 @@ if ( ! class_exists( 'BSF_Analytics' ) ) {
385
  ?>
386
  </label>
387
  <?php
388
- echo wp_kses_post( sprintf( '<a href="%1s" target="_blank" rel="noreferrer noopener">%2s</a>', esc_url( $this->usage_doc_link ), __( 'Learn More.', 'fullwidth-templates' ) ) );
389
  ?>
390
  </fieldset>
391
  <?php
392
  }
393
 
394
- /**
395
- * Get current product name.
396
- *
397
- * @return string $plugin_data['Name] Name of plugin.
398
- * @since 1.0.0
399
- */
400
- private function get_product_name() {
401
-
402
- $base = wp_normalize_path( dirname( __FILE__ ) );
403
- $theme_dir = wp_normalize_path( get_template_directory() );
404
-
405
- if ( false !== strpos( $base, $theme_dir ) ) {
406
- $theme = wp_get_theme( get_template() );
407
- return $theme->get( 'Name' );
408
- }
409
-
410
- $base = plugin_basename( __FILE__ );
411
-
412
- $exploded_path = explode( '/', $base, 2 );
413
- $plugin_slug = $exploded_path[0];
414
-
415
- return $this->get_plugin_name( $plugin_slug );
416
- }
417
-
418
- /**
419
- * Get plugin name by plugin slug.
420
- *
421
- * @param string $plugin_slug Plugin slug.
422
- * @return string $plugin_info['Name'] Plugin name.
423
- */
424
- private function get_plugin_name( $plugin_slug ) {
425
-
426
- $plugins = get_option( 'active_plugins' );
427
-
428
- if ( ! function_exists( 'get_plugin_data' ) ) {
429
- require_once ABSPATH . 'wp-admin/includes/plugin.php';
430
- }
431
-
432
- foreach ( $plugins as $plugin_file ) {
433
- if ( 0 === strpos( $plugin_file, $plugin_slug ) ) {
434
- $plugin_path = WP_PLUGIN_DIR . '/' . $plugin_file;
435
- $plugin_data = get_plugin_data( $plugin_path );
436
- return $plugin_data['Name'];
437
- }
438
- }
439
- }
440
-
441
  /**
442
  * Set analytics installed time in option.
443
  *
 
444
  * @return string $time analytics installed time.
445
  * @since 1.0.0
446
  */
447
- private function get_analytics_install_time() {
448
 
449
- $time = get_site_option( 'bsf_analytics_installed_time' );
450
 
451
  if ( ! $time ) {
452
  $time = time();
453
- update_site_option( 'bsf_analytics_installed_time', time() );
454
  }
455
 
456
  return $time;
@@ -465,7 +447,9 @@ if ( ! class_exists( 'BSF_Analytics' ) ) {
465
  * @since 1.0.0
466
  */
467
  public function update_analytics_option_callback( $old_value, $value, $option ) {
468
- $this->add_option_to_network( $value );
 
 
469
  }
470
 
471
  /**
@@ -476,50 +460,49 @@ if ( ! class_exists( 'BSF_Analytics' ) ) {
476
  * @since 1.0.0
477
  */
478
  public function add_analytics_option_callback( $option, $value ) {
479
- $this->add_option_to_network( $value );
 
 
480
  }
481
 
482
  /**
483
- * Schedule or unschedule event based on analytics option value.
484
  *
485
  * @since 1.0.0
486
  */
487
- public function schedule_unschedule_event() {
488
 
489
- if ( true === $this->is_white_label_enabled() ) {
490
- $this->unschedule_event();
491
  return;
492
  }
493
 
494
- $analytics_option = get_site_option( 'bsf_analytics_optin' );
495
 
496
- if ( 'no' === $analytics_option ) {
497
- $this->unschedule_event();
498
- } elseif ( 'yes' === $analytics_option ) {
499
- $this->schedule_event();
500
  }
501
  }
502
 
503
  /**
504
  * Save analytics option to network.
505
  *
 
506
  * @param string $value value of option.
507
  * @since 1.0.0
508
  */
509
- public function add_option_to_network( $value ) {
510
 
511
  // If action coming from general settings page.
512
  if ( isset( $_POST['option_page'] ) && 'general' === $_POST['option_page'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
513
 
514
- if ( get_site_option( 'bsf_analytics_optin' ) ) {
515
- update_site_option( 'bsf_analytics_optin', $value );
516
  } else {
517
- add_site_option( 'bsf_analytics_optin', $value );
518
  }
519
  }
520
  }
521
  }
522
-
523
- new BSF_Analytics();
524
-
525
  }
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_notices', 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
  /**
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 ) ) {
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. ', 'fullwidth-templates' );
217
 
218
+ if ( is_multisite() ) {
219
+ $notice_string .= __( 'This will be applicable for all sites from the network.', 'fullwidth-templates' );
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', 'fullwidth-templates' ) ),
244
+ add_query_arg(
245
+ array(
246
+ $key . '_analytics_optin' => 'yes',
247
+ $key . '_analytics_nonce' => wp_create_nonce( $key . '_analytics_optin' ),
248
+ 'bsf_analytics_source' => $key,
249
+ )
250
+ ),
251
+ __( 'Yes! Allow it', 'fullwidth-templates' ),
252
+ add_query_arg(
253
+ array(
254
+ $key . '_analytics_optin' => 'no',
255
+ $key . '_analytics_nonce' => wp_create_nonce( $key . '_analytics_optin' ),
256
+ 'bsf_analytics_source' => $key,
257
+ )
258
+ ),
259
+ MONTH_IN_SECONDS,
260
+ __( 'No Thanks', 'fullwidth-templates' )
261
  ),
262
+ 'show_if' => true,
263
+ 'repeat-notice-after' => false,
264
+ 'priority' => 18,
265
+ 'display-with-other-notices' => true,
266
+ )
267
+ );
268
+ }
 
 
269
  }
270
 
271
  /**
274
  * @since 1.0.0
275
  */
276
  public function handle_optin_optout() {
277
+
278
+ if ( ! current_user_can( 'manage_options' ) ) {
279
  return;
280
  }
281
 
282
+ $source = isset( $_GET['bsf_analytics_source'] ) ? sanitize_text_field( wp_unslash( $_GET['bsf_analytics_source'] ) ) : '';
283
+
284
+ if ( ! isset( $_GET[ $source . '_analytics_nonce' ] ) ) {
285
  return;
286
  }
287
 
288
+ if ( ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET[ $source . '_analytics_nonce' ] ) ), $source . '_analytics_optin' ) ) {
289
+ return;
290
+ }
291
+
292
+ $optin_status = isset( $_GET[ $source . '_analytics_optin' ] ) ? sanitize_text_field( wp_unslash( $_GET[ $source . '_analytics_optin' ] ) ) : '';
293
 
294
  if ( 'yes' === $optin_status ) {
295
+ $this->optin( $source );
296
  } elseif ( 'no' === $optin_status ) {
297
+ $this->optout( $source );
298
  }
299
 
300
  wp_safe_redirect(
301
  remove_query_arg(
302
  array(
303
+ $source . '_analytics_optin',
304
+ $source . '_analytics_nonce',
305
+ 'bsf_analytics_source',
306
  )
307
  )
308
  );
311
  /**
312
  * Opt in to usage tracking.
313
  *
314
+ * @param string $source source of analytics.
315
  * @since 1.0.0
316
  */
317
+ private function optin( $source ) {
318
+ update_site_option( $source . '_analytics_optin', 'yes' );
319
  }
320
 
321
  /**
322
  * Opt out to usage tracking.
323
  *
324
+ * @param string $source source of analytics.
325
  * @since 1.0.0
326
  */
327
+ private function optout( $source ) {
328
+ update_site_option( $source . '_analytics_optin', 'no' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
329
  }
330
 
331
  /**
344
  */
345
  public function register_usage_tracking_setting() {
346
 
347
+ foreach ( $this->entities as $key => $data ) {
 
 
348
 
349
+ if ( ! apply_filters( $key . '_tracking_enabled', true ) || $this->is_white_label_enabled( $key ) ) {
350
+ return;
351
+ }
 
 
352
 
353
+ $usage_doc_link = isset( $data['usage_doc_link'] ) ? $data['usage_doc_link'] : $this->usage_doc_link;
354
+ $author = isset( $data['author'] ) ? $data['author'] : 'Brainstorm Force';
355
+
356
+ register_setting(
357
+ 'general', // Options group.
358
+ $key . '_analytics_optin', // Option name/database.
359
+ array( 'sanitize_callback' => array( $this, 'sanitize_option' ) ) // sanitize callback function.
360
+ );
361
+
362
+ add_settings_field(
363
+ $key . '-analytics-optin', // Field ID.
364
+ __( 'Usage Tracking', 'fullwidth-templates' ), // Field title.
365
+ array( $this, 'render_settings_field_html' ), // Field callback function.
366
+ 'general',
367
+ 'default', // Settings page slug.
368
+ array(
369
+ 'type' => 'checkbox',
370
+ 'title' => $author,
371
+ 'name' => $key . '_analytics_optin',
372
+ 'label_for' => $key . '-analytics-optin',
373
+ 'id' => $key . '-analytics-optin',
374
+ 'usage_doc_link' => $usage_doc_link,
375
+ )
376
+ );
377
+ }
378
  }
379
 
380
  /**
395
  /**
396
  * Print settings field HTML.
397
  *
398
+ * @param array $args arguments to field.
399
  * @since 1.0.0
400
  */
401
+ public function render_settings_field_html( $args ) {
402
  ?>
403
  <fieldset>
404
+ <label for="<?php echo esc_attr( $args['label_for'] ); ?>">
405
+ <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' ); ?>>
406
  <?php
407
+ /* translators: %s Product title */
408
+ echo esc_html( sprintf( __( 'Allow %s products to track non-sensitive usage tracking data.', 'fullwidth-templates' ), $args['title'] ) );// phpcs:ignore WordPress.WP.I18n.NonSingularStringLiteralText
409
 
410
  if ( is_multisite() ) {
411
  esc_html_e( ' This will be applicable for all sites from the network.', 'fullwidth-templates' );
413
  ?>
414
  </label>
415
  <?php
416
+ echo wp_kses_post( sprintf( '<a href="%1s" target="_blank" rel="noreferrer noopener">%2s</a>', esc_url( $args['usage_doc_link'] ), __( 'Learn More.', 'fullwidth-templates' ) ) );
417
  ?>
418
  </fieldset>
419
  <?php
420
  }
421
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
422
  /**
423
  * Set analytics installed time in option.
424
  *
425
+ * @param string $source source of analytics.
426
  * @return string $time analytics installed time.
427
  * @since 1.0.0
428
  */
429
+ private function get_analytics_install_time( $source ) {
430
 
431
+ $time = get_site_option( $source . '_analytics_installed_time' );
432
 
433
  if ( ! $time ) {
434
  $time = time();
435
+ update_site_option( $source . '_analytics_installed_time', time() );
436
  }
437
 
438
  return $time;
447
  * @since 1.0.0
448
  */
449
  public function update_analytics_option_callback( $old_value, $value, $option ) {
450
+ if ( is_multisite() ) {
451
+ $this->add_option_to_network( $option, $value );
452
+ }
453
  }
454
 
455
  /**
460
  * @since 1.0.0
461
  */
462
  public function add_analytics_option_callback( $option, $value ) {
463
+ if ( is_multisite() ) {
464
+ $this->add_option_to_network( $option, $value );
465
+ }
466
  }
467
 
468
  /**
469
+ * Send analaytics track event if tracking is enabled.
470
  *
471
  * @since 1.0.0
472
  */
473
+ public function maybe_track_analytics() {
474
 
475
+ if ( ! $this->is_tracking_enabled() ) {
 
476
  return;
477
  }
478
 
479
+ $analytics_track = get_site_transient( 'bsf_analytics_track' );
480
 
481
+ // If the last data sent is 2 days old i.e. transient is expired.
482
+ if ( ! $analytics_track ) {
483
+ $this->send();
484
+ set_site_transient( 'bsf_analytics_track', true, 2 * DAY_IN_SECONDS );
485
  }
486
  }
487
 
488
  /**
489
  * Save analytics option to network.
490
  *
491
+ * @param string $option name of option.
492
  * @param string $value value of option.
493
  * @since 1.0.0
494
  */
495
+ public function add_option_to_network( $option, $value ) {
496
 
497
  // If action coming from general settings page.
498
  if ( isset( $_POST['option_page'] ) && 'general' === $_POST['option_page'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
499
 
500
+ if ( get_site_option( $option ) ) {
501
+ update_site_option( $option, $value );
502
  } else {
503
+ add_site_option( $option, $value );
504
  }
505
  }
506
  }
507
  }
 
 
 
508
  }
admin/bsf-analytics/version.json ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ {
2
+ "bsf-analytics-ver": "1.1.0"
3
+ }
4
+
class-fullwidth-page-templates.php CHANGED
@@ -98,7 +98,22 @@ class Fullwidth_Page_Templates {
98
  // Astra Notices.
99
  require_once FPT_DIR . '/admin/notices/class-astra-notices.php';
100
  // BSF Analytics.
101
- require_once FPT_DIR . '/admin/bsf-analytics/class-bsf-analytics.php';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
  }
103
 
104
  public function post_type_template() {
98
  // Astra Notices.
99
  require_once FPT_DIR . '/admin/notices/class-astra-notices.php';
100
  // BSF Analytics.
101
+ if ( ! class_exists( 'BSF_Analytics_Loader' ) ) {
102
+ require_once FPT_DIR . 'admin/bsf-analytics/class-bsf-analytics-loader.php';
103
+ }
104
+
105
+ $bsf_analytics = BSF_Analytics_Loader::get_instance();
106
+
107
+ $bsf_analytics->set_entity(
108
+ array(
109
+ 'bsf' => array(
110
+ 'product_name' => 'Fullwidth Templates for Any Theme & Page Builder',
111
+ 'path' => FPT_DIR . 'admin/bsf-analytics',
112
+ 'author' => 'Brainstorm Force',
113
+ 'time_to_display' => '+24 hours',
114
+ ),
115
+ )
116
+ );
117
  }
118
 
119
  public function post_type_template() {
fullwidth-page-template.php CHANGED
@@ -7,7 +7,7 @@
7
  * Author URI: https://www.brainstormforce.com
8
  * Text Domain: fullwidth-templates
9
  * Domain Path: /languages
10
- * Version: 1.1.0
11
  *
12
  * @package Fullwidth_Page_Templates
13
  */
@@ -19,7 +19,7 @@ if ( ! defined( 'ABSPATH' ) ) {
19
 
20
  require_once 'class-fullwidth-page-templates.php';
21
 
22
- define( 'FPT_VER', '1.1.0' );
23
  define( 'FPT_DIR', plugin_dir_path( __FILE__ ) );
24
  define( 'FPT_URL', plugins_url( '/', __FILE__ ) );
25
  define( 'FPT_PATH', plugin_basename( __FILE__ ) );
7
  * Author URI: https://www.brainstormforce.com
8
  * Text Domain: fullwidth-templates
9
  * Domain Path: /languages
10
+ * Version: 1.1.1
11
  *
12
  * @package Fullwidth_Page_Templates
13
  */
19
 
20
  require_once 'class-fullwidth-page-templates.php';
21
 
22
+ define( 'FPT_VER', '1.1.1' );
23
  define( 'FPT_DIR', plugin_dir_path( __FILE__ ) );
24
  define( 'FPT_URL', plugins_url( '/', __FILE__ ) );
25
  define( 'FPT_PATH', plugin_basename( __FILE__ ) );
languages/fullwidth-templates.pot CHANGED
@@ -5,7 +5,7 @@ msgstr ""
5
  "Project-Id-Version: Fullwidth Page Templates 1.1.0\n"
6
  "Report-Msgid-Bugs-To: "
7
  "https://wordpress.org/support/plugin/fullwidth-templates\n"
8
- "POT-Creation-Date: 2020-06-15 07:37:56+00:00\n"
9
  "MIME-Version: 1.0\n"
10
  "Content-Type: text/plain; charset=utf-8\n"
11
  "Content-Transfer-Encoding: 8bit\n"
@@ -25,47 +25,44 @@ msgstr ""
25
  "X-Textdomain-Support: yes\n"
26
  "X-Generator: grunt-wp-i18n 1.0.3\n"
27
 
28
- #: admin/bsf-analytics/class-bsf-analytics.php:183
29
  #. translators: %s product name
30
  msgid ""
31
  "Want to help make <strong>%1s</strong> even more awesome? Allow us to "
32
  "collect non-sensitive diagnostic data and usage information. "
33
  msgstr ""
34
 
35
- #: admin/bsf-analytics/class-bsf-analytics.php:186
36
  msgid "This will be applicable for all sites from the network."
37
  msgstr ""
38
 
39
- #: admin/bsf-analytics/class-bsf-analytics.php:210
40
  #. translators: %s usage doc link
41
  msgid " Know More."
42
  msgstr ""
43
 
44
- #: admin/bsf-analytics/class-bsf-analytics.php:217
45
  msgid "Yes! Allow it"
46
  msgstr ""
47
 
48
- #: admin/bsf-analytics/class-bsf-analytics.php:225
49
  msgid "No Thanks"
50
  msgstr ""
51
 
52
- #: admin/bsf-analytics/class-bsf-analytics.php:294
53
- msgid "Every two days"
54
- msgstr ""
55
-
56
- #: admin/bsf-analytics/class-bsf-analytics.php:348
57
  msgid "Usage Tracking"
58
  msgstr ""
59
 
60
- #: admin/bsf-analytics/class-bsf-analytics.php:380
61
- msgid "Allow Brainstorm Force products to track non-sensitive usage tracking data."
 
62
  msgstr ""
63
 
64
- #: admin/bsf-analytics/class-bsf-analytics.php:383
65
  msgid " This will be applicable for all sites from the network."
66
  msgstr ""
67
 
68
- #: admin/bsf-analytics/class-bsf-analytics.php:388
69
  msgid "Learn More."
70
  msgstr ""
71
 
5
  "Project-Id-Version: Fullwidth Page Templates 1.1.0\n"
6
  "Report-Msgid-Bugs-To: "
7
  "https://wordpress.org/support/plugin/fullwidth-templates\n"
8
+ "POT-Creation-Date: 2020-08-19 11:31:57+00:00\n"
9
  "MIME-Version: 1.0\n"
10
  "Content-Type: text/plain; charset=utf-8\n"
11
  "Content-Transfer-Encoding: 8bit\n"
25
  "X-Textdomain-Support: yes\n"
26
  "X-Generator: grunt-wp-i18n 1.0.3\n"
27
 
28
+ #: admin/bsf-analytics/class-bsf-analytics.php:216
29
  #. translators: %s product name
30
  msgid ""
31
  "Want to help make <strong>%1s</strong> even more awesome? Allow us to "
32
  "collect non-sensitive diagnostic data and usage information. "
33
  msgstr ""
34
 
35
+ #: admin/bsf-analytics/class-bsf-analytics.php:219
36
  msgid "This will be applicable for all sites from the network."
37
  msgstr ""
38
 
39
+ #: admin/bsf-analytics/class-bsf-analytics.php:243
40
  #. translators: %s usage doc link
41
  msgid " Know More."
42
  msgstr ""
43
 
44
+ #: admin/bsf-analytics/class-bsf-analytics.php:251
45
  msgid "Yes! Allow it"
46
  msgstr ""
47
 
48
+ #: admin/bsf-analytics/class-bsf-analytics.php:260
49
  msgid "No Thanks"
50
  msgstr ""
51
 
52
+ #: admin/bsf-analytics/class-bsf-analytics.php:364
 
 
 
 
53
  msgid "Usage Tracking"
54
  msgstr ""
55
 
56
+ #: admin/bsf-analytics/class-bsf-analytics.php:408
57
+ #. translators: %s Product title
58
+ msgid "Allow %s products to track non-sensitive usage tracking data."
59
  msgstr ""
60
 
61
+ #: admin/bsf-analytics/class-bsf-analytics.php:411
62
  msgid " This will be applicable for all sites from the network."
63
  msgstr ""
64
 
65
+ #: admin/bsf-analytics/class-bsf-analytics.php:416
66
  msgid "Learn More."
67
  msgstr ""
68
 
readme.txt CHANGED
@@ -3,8 +3,8 @@ Contributors: brainstormforce, WPCrafter, ramiy
3
  Tags: full width, fullwidth, template, beaver builder, elementor, genesis, primer, full width template, remove sidebar, page builder
4
  Donate link: https://www.paypal.me/BrainstormForce
5
  Requires at least: 4.2
6
- Tested up to: 5.4
7
- Stable tag: 1.1.0
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
@@ -85,6 +85,10 @@ Check Screenshots for more details.
85
  5. Blank - No Header / Footer Template
86
 
87
  == Changelog ==
 
 
 
 
88
  = 1.1.0 =
89
  - New: Users can now share non-personal usage data to help us test and develop better products. ( <a href="https://store.brainstormforce.com/usage-tracking/?utm_source=changelog&utm_medium=readme&utm_campaign=usage_tracking" target="_blank" rel="noopener">Know More</a> )
90
 
3
  Tags: full width, fullwidth, template, beaver builder, elementor, genesis, primer, full width template, remove sidebar, page builder
4
  Donate link: https://www.paypal.me/BrainstormForce
5
  Requires at least: 4.2
6
+ Tested up to: 6.1
7
+ Stable tag: 1.1.1
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
85
  5. Blank - No Header / Footer Template
86
 
87
  == Changelog ==
88
+
89
+ = 1.1.1 =
90
+ - Fix: Fixed compatibility with other plugins with respect to the admin notice.
91
+
92
  = 1.1.0 =
93
  - New: Users can now share non-personal usage data to help us test and develop better products. ( <a href="https://store.brainstormforce.com/usage-tracking/?utm_source=changelog&utm_medium=readme&utm_campaign=usage_tracking" target="_blank" rel="noopener">Know More</a> )
94