Fullwidth Templates for Any Theme & Page Builder - Version 1.1.0

Version Description

  • New: Users can now share non-personal usage data to help us test and develop better products. ( Know More )
Download this release

Release Info

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

Code changes from version 1.0.3 to 1.1.0

admin/bsf-analytics/assets/css/minified/style.min-rtl.css ADDED
@@ -0,0 +1 @@
 
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 ADDED
@@ -0,0 +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}
admin/bsf-analytics/assets/css/unminified/style-rtl.css ADDED
@@ -0,0 +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
+ }
admin/bsf-analytics/assets/css/unminified/style.css ADDED
@@ -0,0 +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
+ }
admin/bsf-analytics/class-bsf-analytics-stats.php ADDED
@@ -0,0 +1,257 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BSF analytics stat class file.
4
+ *
5
+ * @package bsf-analytics
6
+ */
7
+
8
+ if ( ! defined( 'ABSPATH' ) ) {
9
+ exit; // Exit if accessed directly.
10
+ }
11
+
12
+ if ( ! class_exists( 'BSF_Analytics_Stats' ) ) {
13
+ /**
14
+ * BSF analytics stat class.
15
+ */
16
+ class BSF_Analytics_Stats {
17
+
18
+ /**
19
+ * Active plugins.
20
+ *
21
+ * Holds the sites active plugins list.
22
+ *
23
+ * @var array
24
+ */
25
+ private $plugins;
26
+
27
+ /**
28
+ * Instance of BSF_Analytics_Stats.
29
+ *
30
+ * Holds only the first object of class.
31
+ *
32
+ * @var object
33
+ */
34
+ private static $instance = null;
35
+
36
+ /**
37
+ * Create only once instance of a class.
38
+ *
39
+ * @return object
40
+ * @since 1.0.0
41
+ */
42
+ public static function instance() {
43
+ if ( null === self::$instance ) {
44
+ self::$instance = new self();
45
+ }
46
+
47
+ return self::$instance;
48
+ }
49
+
50
+ /**
51
+ * Get stats.
52
+ *
53
+ * @return array stats data.
54
+ * @since 1.0.0
55
+ */
56
+ public function get_stats() {
57
+ return apply_filters( 'bsf_core_stats', $this->get_default_stats() );
58
+ }
59
+
60
+ /**
61
+ * Retrieve stats for site.
62
+ *
63
+ * @return array stats data.
64
+ * @since 1.0.0
65
+ */
66
+ private function get_default_stats() {
67
+ return array(
68
+ 'graupi_version' => defined( 'BSF_UPDATER_VERSION' ) ? BSF_UPDATER_VERSION : false,
69
+ 'domain_name' => get_site_url(),
70
+ 'php_os' => PHP_OS,
71
+ 'server_software' => isset( $_SERVER['SERVER_SOFTWARE'] ) ? filter_var( wp_unslash( $_SERVER['SERVER_SOFTWARE'] ), FILTER_SANITIZE_STRING ) : '',
72
+ 'mysql_version' => $this->get_mysql_version(),
73
+ 'php_version' => $this->get_php_version(),
74
+ 'php_max_input_vars' => ini_get( 'max_input_vars' ), // phpcs:ignore:PHPCompatibility.IniDirectives.NewIniDirectives.max_input_varsFound
75
+ 'php_post_max_size' => ini_get( 'post_max_size' ),
76
+ 'php_max_execution_time' => ini_get( 'max_execution_time' ),
77
+ 'php_memory_limit' => ini_get( 'memory_limit' ),
78
+ 'zip_installed' => extension_loaded( 'zip' ),
79
+ 'imagick_availabile' => extension_loaded( 'imagick' ),
80
+ 'xmlreader_exists' => class_exists( 'XMLReader' ),
81
+ 'gd_available' => extension_loaded( 'gd' ),
82
+ 'curl_version' => $this->get_curl_version(),
83
+ 'curl_ssl_version' => $this->get_curl_ssl_version(),
84
+ 'is_writable' => $this->is_content_writable(),
85
+
86
+ 'wp_version' => get_bloginfo( 'version' ),
87
+ 'user_count' => $this->get_user_count(),
88
+ 'site_language' => get_locale(),
89
+ 'timezone' => wp_timezone_string(),
90
+ 'is_ssl' => is_ssl(),
91
+ 'is_multisite' => is_multisite(),
92
+ 'network_url' => network_site_url(),
93
+ 'external_object_cache' => (bool) wp_using_ext_object_cache(),
94
+ 'wp_debug' => WP_DEBUG,
95
+ 'wp_debug_display' => WP_DEBUG_DISPLAY,
96
+ 'script_debug' => SCRIPT_DEBUG,
97
+
98
+ 'active_plugins' => $this->get_active_plugins(),
99
+
100
+ 'active_theme' => get_template(),
101
+ 'active_stylesheet' => get_stylesheet(),
102
+ );
103
+ }
104
+
105
+ /**
106
+ * Get installed PHP version.
107
+ *
108
+ * @return float PHP version.
109
+ * @since 1.0.0
110
+ */
111
+ private function get_php_version() {
112
+ if ( defined( 'PHP_MAJOR_VERSION' ) && defined( 'PHP_MINOR_VERSION' ) && defined( 'PHP_RELEASE_VERSION' ) ) { // phpcs:ignore
113
+ return PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION . '.' . PHP_RELEASE_VERSION;
114
+ }
115
+
116
+ return phpversion();
117
+ }
118
+
119
+ /**
120
+ * User count on site.
121
+ *
122
+ * @return int User count.
123
+ * @since 1.0.0
124
+ */
125
+ private function get_user_count() {
126
+ if ( is_multisite() ) {
127
+ $user_count = get_user_count();
128
+ } else {
129
+ $count = count_users();
130
+ $user_count = $count['total_users'];
131
+ }
132
+
133
+ return $user_count;
134
+ }
135
+
136
+ /**
137
+ * Get active plugin's data.
138
+ *
139
+ * @return array active plugin's list.
140
+ * @since 1.0.0
141
+ */
142
+ private function get_active_plugins() {
143
+ if ( ! $this->plugins ) {
144
+ // Ensure get_plugin_data function is loaded.
145
+ if ( ! function_exists( 'get_plugin_data' ) ) {
146
+ require_once ABSPATH . 'wp-admin/includes/plugin.php';
147
+ }
148
+
149
+ $plugins = wp_get_active_and_valid_plugins();
150
+ $plugins = array_map( 'get_plugin_data', $plugins );
151
+ $this->plugins = array_map( array( $this, 'format_plugin' ), $plugins );
152
+ }
153
+
154
+ return $this->plugins;
155
+ }
156
+
157
+ /**
158
+ * Format plugin data.
159
+ *
160
+ * @param string $plugin plugin.
161
+ * @return array formatted plugin data.
162
+ * @since 1.0.0
163
+ */
164
+ public function format_plugin( $plugin ) {
165
+ return array(
166
+ 'name' => html_entity_decode( $plugin['Name'], ENT_COMPAT, 'UTF-8' ),
167
+ 'url' => $plugin['PluginURI'],
168
+ 'version' => $plugin['Version'],
169
+ 'slug' => $plugin['TextDomain'],
170
+ 'author_name' => html_entity_decode( wp_strip_all_tags( $plugin['Author'] ), ENT_COMPAT, 'UTF-8' ),
171
+ 'author_url' => $plugin['AuthorURI'],
172
+ );
173
+ }
174
+
175
+ /**
176
+ * Curl SSL version.
177
+ *
178
+ * @return float SSL version.
179
+ * @since 1.0.0
180
+ */
181
+ private function get_curl_ssl_version() {
182
+ $curl = array();
183
+ if ( function_exists( 'curl_version' ) ) {
184
+ $curl = curl_version(); // phpcs:ignore WordPress.WP.AlternativeFunctions.curl_curl_version
185
+ }
186
+
187
+ return isset( $curl['ssl_version'] ) ? $curl['ssl_version'] : false;
188
+ }
189
+
190
+ /**
191
+ * Get cURL version.
192
+ *
193
+ * @return float cURL version.
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
+ }
201
+
202
+ return isset( $curl['version'] ) ? $curl['version'] : false;
203
+ }
204
+
205
+ /**
206
+ * Get MySQL version.
207
+ *
208
+ * @return float MySQL version.
209
+ * @since 1.0.0
210
+ */
211
+ private function get_mysql_version() {
212
+ global $wpdb;
213
+ return $wpdb->db_version();
214
+ }
215
+
216
+ /**
217
+ * Check if content directory is writable.
218
+ *
219
+ * @return bool
220
+ * @since 1.0.0
221
+ */
222
+ private function is_content_writable() {
223
+ $upload_dir = wp_upload_dir();
224
+ return wp_is_writable( $upload_dir['basedir'] );
225
+ }
226
+ }
227
+ }
228
+
229
+ /**
230
+ * Polyfill for sites using WP version less than 5.3
231
+ */
232
+ if ( ! function_exists( 'wp_timezone_string' ) ) {
233
+ /**
234
+ * Get timezone string.
235
+ *
236
+ * @return string timezone string.
237
+ * @since 1.0.0
238
+ */
239
+ function wp_timezone_string() {
240
+ $timezone_string = get_option( 'timezone_string' );
241
+
242
+ if ( $timezone_string ) {
243
+ return $timezone_string;
244
+ }
245
+
246
+ $offset = (float) get_option( 'gmt_offset' );
247
+ $hours = (int) $offset;
248
+ $minutes = ( $offset - $hours );
249
+
250
+ $sign = ( $offset < 0 ) ? '-' : '+';
251
+ $abs_hour = abs( $hours );
252
+ $abs_mins = abs( $minutes * 60 );
253
+ $tz_offset = sprintf( '%s%02d:%02d', $sign, $abs_hour, $abs_mins );
254
+
255
+ return $tz_offset;
256
+ }
257
+ }
admin/bsf-analytics/class-bsf-analytics.php ADDED
@@ -0,0 +1,525 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 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
+ /**
78
+ * Get API URL for sending analytics.
79
+ *
80
+ * @return string API URL.
81
+ * @since 1.0.0
82
+ */
83
+ private function get_api_url() {
84
+ return defined( 'BSF_API_URL' ) ? BSF_API_URL : 'https://support.brainstormforce.com/';
85
+ }
86
+
87
+ /**
88
+ * Enqueue Scripts.
89
+ *
90
+ * @since 1.0.0
91
+ * @return void
92
+ */
93
+ public function enqueue_assets() {
94
+
95
+ /**
96
+ * Load unminified if SCRIPT_DEBUG is true.
97
+ *
98
+ * Directory and Extensions.
99
+ */
100
+ $dir_name = ( SCRIPT_DEBUG ) ? 'unminified' : 'minified';
101
+ $file_rtl = ( is_rtl() ) ? '-rtl' : '';
102
+ $css_ext = ( SCRIPT_DEBUG ) ? '.css' : '.min.css';
103
+
104
+ $css_uri = BSF_ANALYTICS_URI . '/assets/css/' . $dir_name . '/style' . $file_rtl . $css_ext;
105
+
106
+ wp_enqueue_style( 'bsf-analytics-admin-style', $css_uri, false, BSF_ANALYTICS_VERSION, 'all' );
107
+ }
108
+
109
+ /**
110
+ * Send analytics API call.
111
+ *
112
+ * @since 1.0.0
113
+ */
114
+ public function send() {
115
+ wp_remote_post(
116
+ $this->get_api_url() . 'wp-json/bsf-core/v1/analytics/',
117
+ array(
118
+ 'body' => BSF_Analytics_Stats::instance()->get_stats(),
119
+ 'timeout' => 5,
120
+ 'blocking' => false,
121
+ )
122
+ );
123
+ }
124
+
125
+ /**
126
+ * Check if usage tracking is enabled.
127
+ *
128
+ * @return bool
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 ) ) {
150
+ foreach ( $options as $option ) {
151
+ if ( true === $option ) {
152
+ $is_enabled = true;
153
+ break;
154
+ }
155
+ }
156
+ }
157
+
158
+ return $is_enabled;
159
+ }
160
+
161
+ /**
162
+ * Display admin notice for usage tracking.
163
+ *
164
+ * @since 1.0.0
165
+ */
166
+ public function option_notice() {
167
+
168
+ if ( ! current_user_can( 'manage_options' ) ) {
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
+ /**
236
+ * Process usage tracking opt out.
237
+ *
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
+ );
265
+ }
266
+
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
+ /**
321
+ * Load analytics stat class.
322
+ *
323
+ * @since 1.0.0
324
+ */
325
+ private function includes() {
326
+ require_once __DIR__ . '/class-bsf-analytics-stats.php';
327
+ }
328
+
329
+ /**
330
+ * Register usage tracking option in General settings page.
331
+ *
332
+ * @since 1.0.0
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
+ /**
355
+ * Sanitize Callback Function
356
+ *
357
+ * @param bool $input Option value.
358
+ * @since 1.0.0
359
+ */
360
+ public function sanitize_option( $input ) {
361
+
362
+ if ( ! $input || 'no' === $input ) {
363
+ return 'no';
364
+ }
365
+
366
+ return 'yes';
367
+ }
368
+
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' );
384
+ }
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;
457
+ }
458
+
459
+ /**
460
+ * Schedule/unschedule cron event on updation of option.
461
+ *
462
+ * @param string $old_value old value of option.
463
+ * @param string $value value of option.
464
+ * @param string $option Option name.
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
+ /**
472
+ * Analytics option add callback.
473
+ *
474
+ * @param string $option Option name.
475
+ * @param string $value value of option.
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
+ }
admin/notices/class-astra-notices.php ADDED
@@ -0,0 +1,350 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Astra Sites Notices
4
+ *
5
+ * Closing notice on click on `astra-notice-close` class.
6
+ *
7
+ * If notice has the data attribute `data-repeat-notice-after="%2$s"` then notice close for that SPECIFIC TIME.
8
+ * If notice has NO data attribute `data-repeat-notice-after="%2$s"` then notice close for the CURRENT USER FOREVER.
9
+ *
10
+ * > Create custom close notice link in the notice markup. E.g.
11
+ * `<a href="#" data-repeat-notice-after="<?php echo MONTH_IN_SECONDS; ?>" class="astra-notice-close">`
12
+ * It close the notice for 30 days.
13
+ *
14
+ * @package Astra Sites
15
+ * @since 1.4.0
16
+ */
17
+
18
+ if ( ! defined( 'ABSPATH' ) ) {
19
+ exit; // Exit if accessed directly.
20
+ }
21
+
22
+ if ( ! class_exists( 'Astra_Notices' ) ) :
23
+
24
+ /**
25
+ * Astra_Notices
26
+ *
27
+ * @since 1.4.0
28
+ */
29
+ class Astra_Notices {
30
+
31
+ /**
32
+ * Notices
33
+ *
34
+ * @access private
35
+ * @var array Notices.
36
+ * @since 1.4.0
37
+ */
38
+ private static $version = '1.1.5';
39
+
40
+ /**
41
+ * Notices
42
+ *
43
+ * @access private
44
+ * @var array Notices.
45
+ * @since 1.4.0
46
+ */
47
+ private static $notices = array();
48
+
49
+ /**
50
+ * Instance
51
+ *
52
+ * @access private
53
+ * @var object Class object.
54
+ * @since 1.4.0
55
+ */
56
+ private static $instance;
57
+
58
+ /**
59
+ * Initiator
60
+ *
61
+ * @since 1.4.0
62
+ * @return object initialized object of class.
63
+ */
64
+ public static function get_instance() {
65
+ if ( ! isset( self::$instance ) ) {
66
+ self::$instance = new self();
67
+ }
68
+ return self::$instance;
69
+ }
70
+
71
+ /**
72
+ * Constructor
73
+ *
74
+ * @since 1.4.0
75
+ */
76
+ public function __construct() {
77
+ add_action( 'admin_notices', array( $this, 'show_notices' ), 30 );
78
+ add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
79
+ add_action( 'wp_ajax_astra-notice-dismiss', array( $this, 'dismiss_notice' ) );
80
+ add_filter( 'wp_kses_allowed_html', array( $this, 'add_data_attributes' ), 10, 2 );
81
+ }
82
+
83
+ /**
84
+ * Filters and Returns a list of allowed tags and attributes for a given context.
85
+ *
86
+ * @param Array $allowedposttags Array of allowed tags.
87
+ * @param String $context Context type (explicit).
88
+ * @since 1.4.0
89
+ * @return Array
90
+ */
91
+ public function add_data_attributes( $allowedposttags, $context ) {
92
+ $allowedposttags['a']['data-repeat-notice-after'] = true;
93
+
94
+ return $allowedposttags;
95
+ }
96
+
97
+ /**
98
+ * Add Notice.
99
+ *
100
+ * @since 1.4.0
101
+ * @param array $args Notice arguments.
102
+ * @return void
103
+ */
104
+ public static function add_notice( $args = array() ) {
105
+ self::$notices[] = $args;
106
+ }
107
+
108
+ /**
109
+ * Dismiss Notice.
110
+ *
111
+ * @since 1.4.0
112
+ * @return void
113
+ */
114
+ public function dismiss_notice() {
115
+ $notice_id = ( isset( $_POST['notice_id'] ) ) ? sanitize_key( $_POST['notice_id'] ) : '';
116
+ $repeat_notice_after = ( isset( $_POST['repeat_notice_after'] ) ) ? absint( $_POST['repeat_notice_after'] ) : '';
117
+ $nonce = ( isset( $_POST['nonce'] ) ) ? sanitize_key( $_POST['nonce'] ) : '';
118
+
119
+ if ( false === wp_verify_nonce( $nonce, 'astra-notices' ) ) {
120
+ wp_send_json_error( _e( 'WordPress Nonce not validated.', 'fullwidth-templates' ) );
121
+ }
122
+
123
+ // Valid inputs?
124
+ if ( ! empty( $notice_id ) ) {
125
+ if ( ! empty( $repeat_notice_after ) ) {
126
+ set_transient( $notice_id, true, $repeat_notice_after );
127
+ } else {
128
+ update_user_meta( get_current_user_id(), $notice_id, 'notice-dismissed' );
129
+ }
130
+
131
+ wp_send_json_success();
132
+ }
133
+
134
+ wp_send_json_error();
135
+ }
136
+
137
+ /**
138
+ * Enqueue Scripts.
139
+ *
140
+ * @since 1.4.0
141
+ * @return void
142
+ */
143
+ public function enqueue_scripts() {
144
+ wp_register_script( 'astra-notices', self::_get_uri() . 'notices.js', array( 'jquery' ), self::$version, true );
145
+ wp_localize_script(
146
+ 'astra-notices',
147
+ 'astraNotices',
148
+ array(
149
+ '_notice_nonce' => wp_create_nonce( 'astra-notices' ),
150
+ )
151
+ );
152
+ }
153
+
154
+ /**
155
+ * Rating priority sort
156
+ *
157
+ * @since 1.5.2
158
+ * @param array $array1 array one.
159
+ * @param array $array2 array two.
160
+ * @return array
161
+ */
162
+ public function sort_notices( $array1, $array2 ) {
163
+ if ( ! isset( $array1['priority'] ) ) {
164
+ $array1['priority'] = 10;
165
+ }
166
+ if ( ! isset( $array2['priority'] ) ) {
167
+ $array2['priority'] = 10;
168
+ }
169
+
170
+ return $array1['priority'] - $array2['priority'];
171
+ }
172
+
173
+ /**
174
+ * Notice Types
175
+ *
176
+ * @since 1.4.0
177
+ * @return void
178
+ */
179
+ public function show_notices() {
180
+ $defaults = array(
181
+ 'id' => '', // Optional, Notice ID. If empty it set `astra-notices-id-<$array-index>`.
182
+ 'type' => 'info', // Optional, Notice type. Default `info`. Expected [info, warning, notice, error].
183
+ 'message' => '', // Optional, Message.
184
+ 'show_if' => true, // Optional, Show notice on custom condition. E.g. 'show_if' => if( is_admin() ) ? true, false, .
185
+ 'repeat-notice-after' => '', // Optional, Dismiss-able notice time. It'll auto show after given time.
186
+ 'display-notice-after' => false, // Optional, Dismiss-able notice time. It'll auto show after given time.
187
+ 'class' => '', // Optional, Additional notice wrapper class.
188
+ 'priority' => 10, // Priority of the notice.
189
+ 'display-with-other-notices' => true, // Should the notice be displayed if other notices are being displayed from Astra_Notices.
190
+ 'is_dismissible' => true,
191
+ );
192
+
193
+ // Count for the notices that are rendered.
194
+ $notices_displayed = 0;
195
+
196
+ // sort the array with priority.
197
+ usort( self::$notices, array( $this, 'sort_notices' ) );
198
+
199
+ foreach ( self::$notices as $key => $notice ) {
200
+ $notice = wp_parse_args( $notice, $defaults );
201
+
202
+ $notice['id'] = self::get_notice_id( $notice, $key );
203
+
204
+ $notice['classes'] = self::get_wrap_classes( $notice );
205
+
206
+ // Notices visible after transient expire.
207
+ if ( isset( $notice['show_if'] ) && true === $notice['show_if'] ) {
208
+
209
+ // don't display the notice if it is not supposed to be displayed with other notices.
210
+ if ( 0 !== $notices_displayed && false === $notice['display-with-other-notices'] ) {
211
+ continue;
212
+ }
213
+
214
+ if ( self::is_expired( $notice ) ) {
215
+ self::markup( $notice );
216
+ ++$notices_displayed;
217
+ }
218
+ }
219
+ }
220
+ }
221
+
222
+ /**
223
+ * Markup Notice.
224
+ *
225
+ * @since 1.4.0
226
+ * @param array $notice Notice markup.
227
+ * @return void
228
+ */
229
+ public static function markup( $notice = array() ) {
230
+ wp_enqueue_script( 'astra-notices' );
231
+
232
+ do_action( 'astra_notice_before_markup' );
233
+
234
+ do_action( "astra_notice_before_markup_{$notice['id']}" );
235
+
236
+ ?>
237
+ <div id="<?php echo esc_attr( $notice['id'] ); ?>" class="<?php echo esc_attr( $notice['classes'] ); ?>" data-repeat-notice-after="<?php echo esc_attr( $notice['repeat-notice-after'] ); ?>">
238
+ <div class="notice-container">
239
+ <?php do_action( "astra_notice_inside_markup_{$notice['id']}" ); ?>
240
+ <?php echo wp_kses_post( $notice['message'] ); ?>
241
+ </div>
242
+ </div>
243
+ <?php
244
+
245
+ do_action( "astra_notice_after_markup_{$notice['id']}" );
246
+
247
+ do_action( 'astra_notice_after_markup' );
248
+ }
249
+
250
+ /**
251
+ * Notice classes.
252
+ *
253
+ * @since 1.4.0
254
+ *
255
+ * @param array $notice Notice arguments.
256
+ * @return array Notice wrapper classes.
257
+ */
258
+ private static function get_wrap_classes( $notice ) {
259
+ $classes = array( 'astra-notice', 'notice' );
260
+
261
+ if ( $notice['is_dismissible'] ) {
262
+ $classes[] = 'is-dismissible';
263
+ }
264
+
265
+ $classes[] = $notice['class'];
266
+ if ( isset( $notice['type'] ) && '' !== $notice['type'] ) {
267
+ $classes[] = 'notice-' . $notice['type'];
268
+ }
269
+
270
+ return esc_attr( implode( ' ', $classes ) );
271
+ }
272
+
273
+ /**
274
+ * Get Notice ID.
275
+ *
276
+ * @since 1.4.0
277
+ *
278
+ * @param array $notice Notice arguments.
279
+ * @param int $key Notice array index.
280
+ * @return string Notice id.
281
+ */
282
+ private static function get_notice_id( $notice, $key ) {
283
+ if ( isset( $notice['id'] ) && ! empty( $notice['id'] ) ) {
284
+ return $notice['id'];
285
+ }
286
+
287
+ return 'astra-notices-id-' . $key;
288
+ }
289
+
290
+ /**
291
+ * Is notice expired?
292
+ *
293
+ * @since 1.4.0
294
+ *
295
+ * @param array $notice Notice arguments.
296
+ * @return boolean
297
+ */
298
+ private static function is_expired( $notice ) {
299
+ $transient_status = get_transient( $notice['id'] );
300
+
301
+ if ( false === $transient_status ) {
302
+ if ( isset( $notice['display-notice-after'] ) && false !== $notice['display-notice-after'] ) {
303
+ if ( 'delayed-notice' !== get_user_meta( get_current_user_id(), $notice['id'], true ) &&
304
+ 'notice-dismissed' !== get_user_meta( get_current_user_id(), $notice['id'], true ) ) {
305
+ set_transient( $notice['id'], 'delayed-notice', $notice['display-notice-after'] );
306
+ update_user_meta( get_current_user_id(), $notice['id'], 'delayed-notice' );
307
+
308
+ return false;
309
+ }
310
+ }
311
+
312
+ // Check the user meta status if current notice is dismissed or delay completed.
313
+ $meta_status = get_user_meta( get_current_user_id(), $notice['id'], true );
314
+
315
+ if ( empty( $meta_status ) || 'delayed-notice' === $meta_status ) {
316
+ return true;
317
+ }
318
+ }
319
+
320
+ return false;
321
+ }
322
+
323
+ /**
324
+ * Get URI
325
+ *
326
+ * @return mixed URL.
327
+ */
328
+ public static function _get_uri() {
329
+ $path = wp_normalize_path( dirname( __FILE__ ) );
330
+ $theme_dir = wp_normalize_path( get_template_directory() );
331
+ $plugin_dir = wp_normalize_path( WP_PLUGIN_DIR );
332
+
333
+ if ( strpos( $path, $theme_dir ) !== false ) {
334
+ return trailingslashit( get_template_directory_uri() . str_replace( $theme_dir, '', $path ) );
335
+ } elseif ( strpos( $path, $plugin_dir ) !== false ) {
336
+ return plugin_dir_url( __FILE__ );
337
+ } elseif ( strpos( $path, dirname( plugin_basename( __FILE__ ) ) ) !== false ) {
338
+ return plugin_dir_url( __FILE__ );
339
+ }
340
+
341
+ return;
342
+ }
343
+
344
+ }
345
+
346
+ /**
347
+ * Kicking this off by calling 'get_instance()' method
348
+ */
349
+ Astra_Notices::get_instance();
350
+ endif;
admin/notices/notices.js ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Customizer controls toggles
3
+ *
4
+ * @package Astra
5
+ */
6
+
7
+ ( function( $ ) {
8
+
9
+ /**
10
+ * Helper class for the main Customizer interface.
11
+ *
12
+ * @since 1.0.0
13
+ * @class ASTCustomizer
14
+ */
15
+ AstraNotices = {
16
+
17
+ /**
18
+ * Initializes our custom logic for the Customizer.
19
+ *
20
+ * @since 1.0.0
21
+ * @method init
22
+ */
23
+ init: function()
24
+ {
25
+ this._bind();
26
+ },
27
+
28
+ /**
29
+ * Binds events for the Astra Portfolio.
30
+ *
31
+ * @since 1.0.0
32
+ * @access private
33
+ * @method _bind
34
+ */
35
+ _bind: function()
36
+ {
37
+ $( document ).on('click', '.astra-notice-close', AstraNotices._dismissNoticeNew );
38
+ $( document ).on('click', '.astra-notice .notice-dismiss', AstraNotices._dismissNotice );
39
+ },
40
+
41
+ _dismissNotice: function( event ) {
42
+ event.preventDefault();
43
+
44
+ var repeat_notice_after = $( this ).parents('.astra-notice').data( 'repeat-notice-after' ) || '';
45
+ var notice_id = $( this ).parents('.astra-notice').attr( 'id' ) || '';
46
+
47
+ AstraNotices._ajax( notice_id, repeat_notice_after );
48
+ },
49
+
50
+ _dismissNoticeNew: function( event ) {
51
+ event.preventDefault();
52
+
53
+ var repeat_notice_after = $( this ).attr( 'data-repeat-notice-after' ) || '';
54
+ var notice_id = $( this ).parents('.astra-notice').attr( 'id' ) || '';
55
+
56
+ var $el = $( this ).parents('.astra-notice');
57
+ $el.fadeTo( 100, 0, function() {
58
+ $el.slideUp( 100, function() {
59
+ $el.remove();
60
+ });
61
+ });
62
+
63
+ AstraNotices._ajax( notice_id, repeat_notice_after );
64
+
65
+ var link = $( this ).attr( 'href' ) || '';
66
+ var target = $( this ).attr( 'target' ) || '';
67
+ if( '' !== link && '_blank' === target ) {
68
+ window.open(link , '_blank');
69
+ }
70
+ },
71
+
72
+ _ajax: function( notice_id, repeat_notice_after ) {
73
+
74
+ if( '' === notice_id ) {
75
+ return;
76
+ }
77
+
78
+ $.ajax({
79
+ url: ajaxurl,
80
+ type: 'POST',
81
+ data: {
82
+ action : 'astra-notice-dismiss',
83
+ notice_id : notice_id,
84
+ repeat_notice_after : parseInt( repeat_notice_after ),
85
+ nonce : astraNotices._notice_nonce
86
+ },
87
+ });
88
+
89
+ }
90
+ };
91
+
92
+ $( function() {
93
+ AstraNotices.init();
94
+ } );
95
+ } )( jQuery );
class-fullwidth-page-templates.php CHANGED
@@ -95,6 +95,10 @@ class Fullwidth_Page_Templates {
95
 
96
  private function includes() {
97
  require_once FPT_DIR . '/templates/default/template-helpers.php';
 
 
 
 
98
  }
99
 
100
  public function post_type_template() {
95
 
96
  private function includes() {
97
  require_once FPT_DIR . '/templates/default/template-helpers.php';
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() {
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.0.3
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.0.3' );
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.0
11
  *
12
  * @package Fullwidth_Page_Templates
13
  */
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__ ) );
languages/fullwidth-templates.pot CHANGED
@@ -1,15 +1,15 @@
1
- # Copyright (C) 2018 Brainstorm Force
2
  # This file is distributed under the same license as the Fullwidth Page Templates package.
3
  msgid ""
4
  msgstr ""
5
- "Project-Id-Version: Fullwidth Page Templates 1.0.2\n"
6
  "Report-Msgid-Bugs-To: "
7
- "https://wordpress.org/support/plugin/fullwidth-page-template\n"
8
- "POT-Creation-Date: 2018-05-10 11:18:00+00:00\n"
9
  "MIME-Version: 1.0\n"
10
  "Content-Type: text/plain; charset=utf-8\n"
11
  "Content-Transfer-Encoding: 8bit\n"
12
- "PO-Revision-Date: 2018-MO-DA HO:MI+ZONE\n"
13
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14
  "Language-Team: LANGUAGE <LL@li.org>\n"
15
  "Language: en\n"
@@ -23,7 +23,55 @@ msgstr ""
23
  "X-Poedit-SearchPath-0: .\n"
24
  "X-Poedit-Bookmarks: \n"
25
  "X-Textdomain-Support: yes\n"
26
- "X-Generator: grunt-wp-i18n1.0.2\n"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
 
28
  #: class-fullwidth-page-templates.php:21
29
  msgid "FW No Sidebar"
1
+ # Copyright (C) 2020 Brainstorm Force
2
  # This file is distributed under the same license as the Fullwidth Page Templates package.
3
  msgid ""
4
  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"
12
+ "PO-Revision-Date: 2020-MO-DA HO:MI+ZONE\n"
13
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14
  "Language-Team: LANGUAGE <LL@li.org>\n"
15
  "Language: en\n"
23
  "X-Poedit-SearchPath-0: .\n"
24
  "X-Poedit-Bookmarks: \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: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
+
72
+ #: admin/notices/class-astra-notices.php:120
73
+ msgid "WordPress Nonce not validated."
74
+ msgstr ""
75
 
76
  #: class-fullwidth-page-templates.php:21
77
  msgid "FW No Sidebar"
readme.txt CHANGED
@@ -1,10 +1,10 @@
1
  === Fullwidth Templates for Any Theme & Page Builder ===
2
- Contributors: brainstormforce, nikschavan, 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.brainstormforce.com/payment/
5
  Requires at least: 4.2
6
- Tested up to: 4.9.5
7
- Stable tag: 1.0.3
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
@@ -85,6 +85,8 @@ Check Screenshots for more details.
85
  5. Blank - No Header / Footer Template
86
 
87
  == Changelog ==
 
 
88
 
89
  = 1.0.3 =
90
  - Make the plugin translation compatible.
1
  === Fullwidth Templates for Any Theme & Page Builder ===
2
+ 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
  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
 
91
  = 1.0.3 =
92
  - Make the plugin translation compatible.