PluginProbe
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz / 1.10.0
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz v1.10.0
2.12.6 2.12.5 2.12.4 2.12.3 2.12.2 2.12.1 2.12.0 2.11.1 2.11.0 2.10.1 2.10.0 2.9.1 2.9.0 2.8.2 2.8.1 2.7.0 2.7.1 2.8.0 trunk 0.0.10 0.0.11 0.0.12 0.0.13 0.0.2 0.0.3 All 96 releases
sureforms / admin / analytics.php

analytics.php in SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz 1.10.0, at admin/analytics.php

447 lines 12.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Analytics class helps to connect BSFAnalytics.
4 *
5 * @package sureforms.
6 */
7
8 namespace SRFM\Admin;
9
10 use SRFM\Inc\Database\Tables\Entries;
11 use SRFM\Inc\Helper;
12 use SRFM\Inc\Traits\Get_Instance;
13
14 if ( ! defined( 'ABSPATH' ) ) {
15 exit; // Exit if accessed directly.
16 }
17 /**
18 * Analytics class.
19 *
20 * @since 1.4.0
21 */
22 class Analytics {
23 use Get_Instance;
24
25 /**
26 * Class constructor.
27 *
28 * @return void
29 * @since 1.4.0
30 */
31 public function __construct() {
32 /*
33 * BSF Analytics.
34 */
35 if ( ! class_exists( 'BSF_Analytics_Loader' ) ) {
36 require_once SRFM_DIR . 'inc/lib/bsf-analytics/class-bsf-analytics-loader.php';
37 }
38
39 if ( ! class_exists( 'Astra_Notices' ) ) {
40 require_once SRFM_DIR . 'inc/lib/astra-notices/class-astra-notices.php';
41 }
42
43 add_filter(
44 'uds_survey_allowed_screens',
45 static function () {
46 return [ 'plugins' ];
47 }
48 );
49
50 $srfm_bsf_analytics = \BSF_Analytics_Loader::get_instance();
51
52 $srfm_bsf_analytics->set_entity(
53 [
54 'sureforms' => [
55 'product_name' => 'SureForms',
56 'path' => SRFM_DIR . 'inc/lib/bsf-analytics',
57 'author' => 'SureForms',
58 'time_to_display' => '+24 hours',
59 'deactivation_survey' => apply_filters(
60 'srfm_deactivation_survey_data',
61 [
62 [
63 'id' => 'deactivation-survey-sureforms',
64 'popup_logo' => SRFM_URL . 'admin/assets/sureforms-logo.png',
65 'plugin_slug' => 'sureforms',
66 'popup_title' => 'Quick Feedback',
67 'support_url' => 'https://sureforms.com/contact/',
68 'popup_description' => 'If you have a moment, please share why you are deactivating SureForms:',
69 'show_on_screens' => [ 'plugins' ],
70 'plugin_version' => SRFM_VER,
71 ],
72 ]
73 ),
74 'hide_optin_checkbox' => true,
75 ],
76 ]
77 );
78
79 add_filter( 'bsf_core_stats', [ $this, 'add_srfm_analytics_data' ] );
80 }
81
82 /**
83 * Callback function to add SureForms specific analytics data.
84 *
85 * @param array $stats_data existing stats_data.
86 * @since 1.4.0
87 * @return array
88 */
89 public function add_srfm_analytics_data( $stats_data ) {
90 $stats_data['plugin_data']['sureforms'] = [
91 'free_version' => SRFM_VER,
92 'site_language' => get_locale(),
93 'most_used_anti_spam' => $this->most_used_anti_spam(),
94 'user_status' => $this->user_status(),
95 'pointer_popup_clicked' => $this->pointer_popup_clicked(),
96 ];
97 $stats_data['plugin_data']['sureforms']['numeric_values'] = [
98 'total_forms' => wp_count_posts( SRFM_FORMS_POST_TYPE )->publish ?? 0,
99 'instant_forms_enabled' => $this->instant_forms_enabled(),
100 'forms_using_custom_css' => $this->forms_using_custom_css(),
101 'ai_generated_forms' => $this->ai_generated_forms(),
102 'total_entries' => Entries::get_total_entries_by_status(),
103 ];
104
105 $stats_data['plugin_data']['sureforms'] = array_merge_recursive( $stats_data['plugin_data']['sureforms'], $this->global_settings_data() );
106
107 // Add onboarding analytics data.
108 $stats_data['plugin_data']['sureforms'] = array_merge_recursive( $stats_data['plugin_data']['sureforms'], $this->onboarding_analytics_data() );
109
110 return $stats_data;
111 }
112
113 /**
114 * Return total number of forms using instant forms.
115 *
116 * @since 1.4.0
117 * @return int
118 */
119 public function instant_forms_enabled() {
120 $meta_query = [
121 [
122 'key' => '_srfm_instant_form_settings',
123 'value' => '"enable_instant_form";b:1;',
124 'compare' => 'LIKE',
125 ],
126 ];
127
128 return $this->custom_wp_query_total_posts( $meta_query );
129 }
130
131 /**
132 * Return total number of ai generated forms.
133 *
134 * @since 1.4.0
135 * @return int
136 */
137 public function ai_generated_forms() {
138 $meta_query = [
139 [
140 'key' => '_srfm_is_ai_generated',
141 'value' => '',
142 'compare' => '!=', // Checks if the value is NOT empty.
143 ],
144 ];
145
146 return $this->custom_wp_query_total_posts( $meta_query );
147 }
148
149 /**
150 * Return most used anti-spam type on this site.
151 *
152 * @since 1.4.4
153 * @return int
154 */
155 public function most_used_anti_spam() {
156 global $wpdb;
157
158 // Attempt to get from cache first.
159 $cache_key = 'most_used_anti_spam';
160 $cached_result = wp_cache_get( $cache_key, 'sureforms' );
161
162 if ( false !== $cached_result ) {
163 return $cached_result;
164 }
165
166 $meta_key = '_srfm_captcha_security_type';
167
168 // Query to get the most used captcha type.
169 // PHPCS: Ignore direct database query warning, as there is no built-in alternative.
170 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
171 $result = $wpdb->get_row(
172 $wpdb->prepare(
173 "
174 SELECT meta_value, COUNT(meta_value) as count
175 FROM {$wpdb->postmeta}
176 WHERE meta_key = %s
177 AND meta_value != ''
178 GROUP BY meta_value
179 ORDER BY count DESC
180 LIMIT 1
181 ",
182 $meta_key
183 ),
184 ARRAY_A
185 );
186
187 $output = '';
188 if ( $result && ! empty( $result['meta_value'] ) ) {
189 switch ( $result['meta_value'] ) {
190 case 'g-recaptcha':
191 $output = 'Google reCAPTCHA';
192 break;
193
194 case 'cf-turnstile':
195 $output = 'CloudFlare Turnstile';
196 break;
197
198 case 'hcaptcha':
199 $output = 'hCaptcha';
200 break;
201
202 default:
203 $output = '';
204 break;
205 }
206 }
207
208 // Store result in cache for 1 hour.
209 wp_cache_set( $cache_key, $output, 'sureforms', HOUR_IN_SECONDS );
210
211 return $output;
212 }
213
214 /**
215 * Returns total number of forms using custom css.
216 *
217 * @since 1.4.0
218 * @return int
219 */
220 public function forms_using_custom_css() {
221 $meta_query = [
222 [
223 'key' => '_srfm_form_custom_css',
224 'value' => '',
225 'compare' => '!=', // Checks if the value is NOT empty.
226 ],
227 ];
228
229 return $this->custom_wp_query_total_posts( $meta_query );
230 }
231
232 /**
233 * Generates global setting data for analytics
234 *
235 * @since 1.4.0
236 * @return array
237 */
238 public function global_settings_data() {
239 $global_data = [];
240
241 $security_settings = get_option( 'srfm_security_settings_options', [] );
242 $global_data['boolean_values']['honeypot_enabled'] = isset( $security_settings['srfm_honeypot'] ) && true === $security_settings['srfm_honeypot'];
243
244 $email_summary_data = get_option( 'srfm_email_summary_settings_options', [] );
245 $global_data['boolean_values']['email_summary_enabled'] = isset( $email_summary_data['srfm_email_summary'] ) && true === $email_summary_data['srfm_email_summary'];
246
247 $global_data['boolean_values']['suretriggers_active'] = is_plugin_active( 'suretriggers/suretriggers.php' );
248
249 $bsf_internal_referrer = get_option( 'bsf_product_referers', [] );
250 if ( ! empty( $bsf_internal_referrer['sureforms'] ) ) {
251 $global_data['internal_referer'] = $bsf_internal_referrer['sureforms'];
252 } else {
253 $global_data['internal_referer'] = '';
254 }
255
256 $general_settings = get_option( 'srfm_general_settings_options', [] );
257 $global_data['boolean_values']['ip_logging_enabled'] = ! empty( $general_settings['srfm_ip_log'] );
258
259 $validation_messages = get_option( 'srfm_default_dynamic_block_option', [] );
260 $global_data['boolean_values']['custom_validation_message'] = ! empty( $validation_messages ) && is_array( $validation_messages );
261
262 return $global_data;
263 }
264
265 /**
266 * Generates onboarding analytics data
267 *
268 * @since 1.9.1
269 * @return array
270 */
271 public function onboarding_analytics_data() {
272 $onboarding_data = [];
273 $analytics_option = Helper::get_srfm_option( 'onboarding_analytics', [] );
274
275 if ( empty( $analytics_option ) ) {
276 return $onboarding_data;
277 }
278
279 // Process skipped steps - store as an array.
280 if ( ! empty( $analytics_option['skippedSteps'] ) && is_array( $analytics_option['skippedSteps'] ) ) {
281 // Map step keys to more descriptive names.
282 $step_mapping = [
283 'welcome' => 'Welcome',
284 'connect' => 'Connect',
285 'emailDelivery' => 'SureMail',
286 'premiumFeatures' => 'Features',
287 'done' => 'Done',
288 ];
289
290 // Transform the step keys to their descriptive names.
291 $mapped_steps = array_map(
292 static function( $step ) use ( $step_mapping ) {
293 return $step_mapping[ $step ] ?? $step;
294 },
295 $analytics_option['skippedSteps']
296 );
297
298 // Store as an array.
299 $onboarding_data['onboarding_skipped_steps'] = $mapped_steps;
300 }
301
302 // SureMail Installation Status.
303 if ( isset( $analytics_option['suremailInstalled'] ) ) {
304 $onboarding_data['boolean_values']['onboarding_suremail_installed'] = (bool) $analytics_option['suremailInstalled'];
305 }
306
307 // Account Connection Status.
308 if ( isset( $analytics_option['accountConnected'] ) ) {
309 $onboarding_data['boolean_values']['onboarding_account_connected'] = (bool) $analytics_option['accountConnected'];
310 }
311
312 // Onboarding Completion Status.
313 if ( isset( $analytics_option['completed'] ) ) {
314 $onboarding_data['boolean_values']['onboarding_completed'] = (bool) $analytics_option['completed'];
315 }
316
317 // Onboarding Early Exit Status.
318 if ( isset( $analytics_option['exitedEarly'] ) ) {
319 $onboarding_data['boolean_values']['onboarding_exited_early'] = (bool) $analytics_option['exitedEarly'];
320 }
321
322 // Onboarding Selected Premium Features.
323 if ( ! empty( $analytics_option['premiumFeatures'] ) && ! empty( $analytics_option['premiumFeatures']['selectedFeatures'] ) ) {
324 // Map feature IDs to more descriptive names - exclude free features.
325 $feature_mapping = [
326 // Starter features.
327 'multi_step_form' => 'Multi-step Forms',
328 'conditional_logic' => 'Conditional Fields',
329 'webhooks' => 'Webhooks',
330 'advanced_fields' => 'Advanced Fields',
331
332 // Pro features.
333 'conversational_forms' => 'Conversational Forms',
334 'digital_signatures' => 'Digital Signatures',
335
336 // Business features.
337 'calculations' => 'Calculators',
338 'user_registration' => 'User Registration and Login',
339 'custom_app' => 'Custom App',
340 'pdf_generation' => 'PDF Generation',
341 ];
342
343 // Filter out any free features that might have been included.
344 $premium_features = array_filter(
345 $analytics_option['premiumFeatures']['selectedFeatures'],
346 static function( $feature ) {
347 // Exclude free features (ai-form-generation and entries).
348 return 'ai-form-generation' !== $feature && 'entries' !== $feature;
349 }
350 );
351
352 // Transform the feature IDs to their descriptive names.
353 $mapped_features = array_map(
354 static function( $feature ) use ( $feature_mapping ) {
355 return $feature_mapping[ $feature ] ?? $feature;
356 },
357 $premium_features
358 );
359
360 // Store as an array.
361 $onboarding_data['onboarding_selected_premium_features'] = $mapped_features;
362 }
363
364 return $onboarding_data;
365 }
366
367 /**
368 * Returns user status.
369 *
370 * @since 1.8.0
371 * @return string
372 */
373 public function user_status() {
374 // First, check if user_active is already set in srfm_options.
375 if ( Helper::get_srfm_option( 'user_active', false ) ) {
376 return 'active';
377 }
378 // Get up to 10 published SureForms.
379 $forms = get_posts(
380 [
381 'post_type' => SRFM_FORMS_POST_TYPE,
382 'posts_per_page' => 10,
383 'post_status' => 'publish',
384 ]
385 );
386 if ( empty( $forms ) ) {
387 return 'inactive';
388 }
389 foreach ( $forms as $form ) {
390 if ( ! get_post_meta( $form->ID, '_astra_sites_imported_post', true ) ) {
391 // Mark user as active in srfm_options.
392 Helper::update_srfm_option( 'user_active', true );
393 return 'active';
394 }
395 }
396 return 'inactive';
397 }
398
399 /**
400 * Return pointer popup clicked status.
401 *
402 * @return string pointer click status.
403 * @since 1.8.0
404 */
405 public function pointer_popup_clicked() {
406 // Get both values from srfm_options.
407 $accepted = Helper::get_srfm_option( 'pointer_popup_accepted', false );
408 $dismissed = Helper::get_srfm_option( 'pointer_popup_dismissed', false );
409 // If neither action has occurred.
410 if ( ! $accepted && ! $dismissed ) {
411 return '';
412 }
413
414 // If both are set, return the most recent one.
415 if ( $accepted && $dismissed ) {
416 return $accepted > $dismissed ? 'accepted' : 'dismissed';
417 }
418
419 // If only one is set, return it.
420 return $accepted ? 'accepted' : 'dismissed';
421 }
422
423 /**
424 * Runs custom WP_Query to fetch data as per requirement
425 *
426 * @param array $meta_query meta query array for WP_Query.
427 * @since 1.4.0
428 * @return int
429 */
430 private function custom_wp_query_total_posts( $meta_query ) {
431
432 $args = [
433 'post_type' => SRFM_FORMS_POST_TYPE,
434 'post_status' => 'publish',
435 'posts_per_page' => -1,
436 'meta_query' => $meta_query, //phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Meta query required as we need to fetch count of nested data.
437 ];
438
439 $query = new \WP_Query( $args );
440 $posts_count = $query->found_posts;
441
442 wp_reset_postdata();
443
444 return $posts_count;
445 }
446 }
447