PluginProbe
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz / 1.12.0
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz v1.12.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.12.0, at admin/analytics.php

466 lines 12.9 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 'restricted_forms' => $this->get_restricted_forms(),
104 ];
105
106 $stats_data['plugin_data']['sureforms'] = array_merge_recursive( $stats_data['plugin_data']['sureforms'], $this->global_settings_data() );
107
108 // Add onboarding analytics data.
109 $stats_data['plugin_data']['sureforms'] = array_merge_recursive( $stats_data['plugin_data']['sureforms'], $this->onboarding_analytics_data() );
110
111 return $stats_data;
112 }
113
114 /**
115 * Return total number of forms using instant forms.
116 *
117 * @since 1.4.0
118 * @return int
119 */
120 public function instant_forms_enabled() {
121 $meta_query = [
122 [
123 'key' => '_srfm_instant_form_settings',
124 'value' => '"enable_instant_form";b:1;',
125 'compare' => 'LIKE',
126 ],
127 ];
128
129 return $this->custom_wp_query_total_posts( $meta_query );
130 }
131
132 /**
133 * Return total number of ai generated forms.
134 *
135 * @since 1.4.0
136 * @return int
137 */
138 public function ai_generated_forms() {
139 $meta_query = [
140 [
141 'key' => '_srfm_is_ai_generated',
142 'value' => '',
143 'compare' => '!=', // Checks if the value is NOT empty.
144 ],
145 ];
146
147 return $this->custom_wp_query_total_posts( $meta_query );
148 }
149
150 /**
151 * Return most used anti-spam type on this site.
152 *
153 * @since 1.4.4
154 * @return int
155 */
156 public function most_used_anti_spam() {
157 global $wpdb;
158
159 // Attempt to get from cache first.
160 $cache_key = 'most_used_anti_spam';
161 $cached_result = wp_cache_get( $cache_key, 'sureforms' );
162
163 if ( false !== $cached_result ) {
164 return $cached_result;
165 }
166
167 $meta_key = '_srfm_captcha_security_type';
168
169 // Query to get the most used captcha type.
170 // PHPCS: Ignore direct database query warning, as there is no built-in alternative.
171 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
172 $result = $wpdb->get_row(
173 $wpdb->prepare(
174 "
175 SELECT meta_value, COUNT(meta_value) as count
176 FROM {$wpdb->postmeta}
177 WHERE meta_key = %s
178 AND meta_value != ''
179 GROUP BY meta_value
180 ORDER BY count DESC
181 LIMIT 1
182 ",
183 $meta_key
184 ),
185 ARRAY_A
186 );
187
188 $output = '';
189 if ( $result && ! empty( $result['meta_value'] ) ) {
190 switch ( $result['meta_value'] ) {
191 case 'g-recaptcha':
192 $output = 'Google reCAPTCHA';
193 break;
194
195 case 'cf-turnstile':
196 $output = 'CloudFlare Turnstile';
197 break;
198
199 case 'hcaptcha':
200 $output = 'hCaptcha';
201 break;
202
203 default:
204 $output = '';
205 break;
206 }
207 }
208
209 // Store result in cache for 1 hour.
210 wp_cache_set( $cache_key, $output, 'sureforms', HOUR_IN_SECONDS );
211
212 return $output;
213 }
214
215 /**
216 * Returns total number of forms using custom css.
217 *
218 * @since 1.4.0
219 * @return int
220 */
221 public function forms_using_custom_css() {
222 $meta_query = [
223 [
224 'key' => '_srfm_form_custom_css',
225 'value' => '',
226 'compare' => '!=', // Checks if the value is NOT empty.
227 ],
228 ];
229
230 return $this->custom_wp_query_total_posts( $meta_query );
231 }
232
233 /**
234 * Return total number of restricted forms.
235 *
236 * @since 1.10.1
237 * @return int
238 */
239 public function get_restricted_forms() {
240 $meta_query = [
241 [
242 'key' => '_srfm_form_restriction',
243 'value' => '"status":true',
244 'compare' => 'LIKE',
245 ],
246 ];
247
248 return $this->custom_wp_query_total_posts( $meta_query );
249 }
250
251 /**
252 * Generates global setting data for analytics
253 *
254 * @since 1.4.0
255 * @return array
256 */
257 public function global_settings_data() {
258 $global_data = [];
259
260 $security_settings = get_option( 'srfm_security_settings_options', [] );
261 $global_data['boolean_values']['honeypot_enabled'] = isset( $security_settings['srfm_honeypot'] ) && true === $security_settings['srfm_honeypot'];
262
263 $email_summary_data = get_option( 'srfm_email_summary_settings_options', [] );
264 $global_data['boolean_values']['email_summary_enabled'] = isset( $email_summary_data['srfm_email_summary'] ) && true === $email_summary_data['srfm_email_summary'];
265
266 $global_data['boolean_values']['suretriggers_active'] = is_plugin_active( 'suretriggers/suretriggers.php' );
267
268 $bsf_internal_referrer = get_option( 'bsf_product_referers', [] );
269 if ( ! empty( $bsf_internal_referrer['sureforms'] ) ) {
270 $global_data['internal_referer'] = $bsf_internal_referrer['sureforms'];
271 } else {
272 $global_data['internal_referer'] = '';
273 }
274
275 $general_settings = get_option( 'srfm_general_settings_options', [] );
276 $global_data['boolean_values']['ip_logging_enabled'] = ! empty( $general_settings['srfm_ip_log'] );
277
278 $validation_messages = get_option( 'srfm_default_dynamic_block_option', [] );
279 $global_data['boolean_values']['custom_validation_message'] = ! empty( $validation_messages ) && is_array( $validation_messages );
280
281 return $global_data;
282 }
283
284 /**
285 * Generates onboarding analytics data
286 *
287 * @since 1.9.1
288 * @return array
289 */
290 public function onboarding_analytics_data() {
291 $onboarding_data = [];
292 $analytics_option = Helper::get_srfm_option( 'onboarding_analytics', [] );
293
294 if ( empty( $analytics_option ) ) {
295 return $onboarding_data;
296 }
297
298 // Process skipped steps - store as an array.
299 if ( ! empty( $analytics_option['skippedSteps'] ) && is_array( $analytics_option['skippedSteps'] ) ) {
300 // Map step keys to more descriptive names.
301 $step_mapping = [
302 'welcome' => 'Welcome',
303 'connect' => 'Connect',
304 'emailDelivery' => 'SureMail',
305 'premiumFeatures' => 'Features',
306 'done' => 'Done',
307 ];
308
309 // Transform the step keys to their descriptive names.
310 $mapped_steps = array_map(
311 static function( $step ) use ( $step_mapping ) {
312 return $step_mapping[ $step ] ?? $step;
313 },
314 $analytics_option['skippedSteps']
315 );
316
317 // Store as an array.
318 $onboarding_data['onboarding_skipped_steps'] = $mapped_steps;
319 }
320
321 // SureMail Installation Status.
322 if ( isset( $analytics_option['suremailInstalled'] ) ) {
323 $onboarding_data['boolean_values']['onboarding_suremail_installed'] = (bool) $analytics_option['suremailInstalled'];
324 }
325
326 // Account Connection Status.
327 if ( isset( $analytics_option['accountConnected'] ) ) {
328 $onboarding_data['boolean_values']['onboarding_account_connected'] = (bool) $analytics_option['accountConnected'];
329 }
330
331 // Onboarding Completion Status.
332 if ( isset( $analytics_option['completed'] ) ) {
333 $onboarding_data['boolean_values']['onboarding_completed'] = (bool) $analytics_option['completed'];
334 }
335
336 // Onboarding Early Exit Status.
337 if ( isset( $analytics_option['exitedEarly'] ) ) {
338 $onboarding_data['boolean_values']['onboarding_exited_early'] = (bool) $analytics_option['exitedEarly'];
339 }
340
341 // Onboarding Selected Premium Features.
342 if ( ! empty( $analytics_option['premiumFeatures'] ) && ! empty( $analytics_option['premiumFeatures']['selectedFeatures'] ) ) {
343 // Map feature IDs to more descriptive names - exclude free features.
344 $feature_mapping = [
345 // Starter features.
346 'multi_step_form' => 'Multi-step Forms',
347 'conditional_logic' => 'Conditional Fields',
348 'webhooks' => 'Webhooks',
349 'advanced_fields' => 'Advanced Fields',
350
351 // Pro features.
352 'conversational_forms' => 'Conversational Forms',
353 'digital_signatures' => 'Digital Signatures',
354
355 // Business features.
356 'calculations' => 'Calculators',
357 'user_registration' => 'User Registration and Login',
358 'custom_app' => 'Custom App',
359 'pdf_generation' => 'PDF Generation',
360 ];
361
362 // Filter out any free features that might have been included.
363 $premium_features = array_filter(
364 $analytics_option['premiumFeatures']['selectedFeatures'],
365 static function( $feature ) {
366 // Exclude free features (ai-form-generation and entries).
367 return 'ai-form-generation' !== $feature && 'entries' !== $feature;
368 }
369 );
370
371 // Transform the feature IDs to their descriptive names.
372 $mapped_features = array_map(
373 static function( $feature ) use ( $feature_mapping ) {
374 return $feature_mapping[ $feature ] ?? $feature;
375 },
376 $premium_features
377 );
378
379 // Store as an array.
380 $onboarding_data['onboarding_selected_premium_features'] = $mapped_features;
381 }
382
383 return $onboarding_data;
384 }
385
386 /**
387 * Returns user status.
388 *
389 * @since 1.8.0
390 * @return string
391 */
392 public function user_status() {
393 // First, check if user_active is already set in srfm_options.
394 if ( Helper::get_srfm_option( 'user_active', false ) ) {
395 return 'active';
396 }
397 // Get up to 10 published SureForms.
398 $forms = get_posts(
399 [
400 'post_type' => SRFM_FORMS_POST_TYPE,
401 'posts_per_page' => 10,
402 'post_status' => 'publish',
403 ]
404 );
405 if ( empty( $forms ) ) {
406 return 'inactive';
407 }
408 foreach ( $forms as $form ) {
409 if ( ! get_post_meta( $form->ID, '_astra_sites_imported_post', true ) ) {
410 // Mark user as active in srfm_options.
411 Helper::update_srfm_option( 'user_active', true );
412 return 'active';
413 }
414 }
415 return 'inactive';
416 }
417
418 /**
419 * Return pointer popup clicked status.
420 *
421 * @return string pointer click status.
422 * @since 1.8.0
423 */
424 public function pointer_popup_clicked() {
425 // Get both values from srfm_options.
426 $accepted = Helper::get_srfm_option( 'pointer_popup_accepted', false );
427 $dismissed = Helper::get_srfm_option( 'pointer_popup_dismissed', false );
428 // If neither action has occurred.
429 if ( ! $accepted && ! $dismissed ) {
430 return '';
431 }
432
433 // If both are set, return the most recent one.
434 if ( $accepted && $dismissed ) {
435 return $accepted > $dismissed ? 'accepted' : 'dismissed';
436 }
437
438 // If only one is set, return it.
439 return $accepted ? 'accepted' : 'dismissed';
440 }
441
442 /**
443 * Runs custom WP_Query to fetch data as per requirement
444 *
445 * @param array $meta_query meta query array for WP_Query.
446 * @since 1.4.0
447 * @return int
448 */
449 private function custom_wp_query_total_posts( $meta_query ) {
450
451 $args = [
452 'post_type' => SRFM_FORMS_POST_TYPE,
453 'post_status' => 'publish',
454 'posts_per_page' => -1,
455 '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.
456 ];
457
458 $query = new \WP_Query( $args );
459 $posts_count = $query->found_posts;
460
461 wp_reset_postdata();
462
463 return $posts_count;
464 }
465 }
466