PluginProbe
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz / 2.12.3
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz v2.12.3
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
← All changes | admin/analytics.php +6 -119 trunk2.12.3 View file →
@@ -6,11 +6,9 @@
6 6 */
7 7
8 8 namespace SRFM\Admin;
9 9
10 -use SRFM\Inc\Database\Register;
11 10 use SRFM\Inc\Database\Tables\Entries;
12 -use SRFM\Inc\Form_Views;
13 11 use SRFM\Inc\Helper;
14 12 use SRFM\Inc\Learn;
15 13 use SRFM\Inc\Traits\Get_Instance;
16 14
@@ -130,9 +128,9 @@
130 128 * @since 1.4.0
131 129 * @return array
132 130 */
133 131 public function add_srfm_analytics_data( $stats_data ) {
134 - $stats_data['plugin_data']['sureforms'] = [
132 + $stats_data['plugin_data']['sureforms'] = [
135 133 'free_version' => SRFM_VER,
136 134 'site_language' => get_locale(),
137 135 'most_used_anti_spam' => $this->most_used_anti_spam(),
138 136 'user_status' => $this->user_status(),
@@ -137,12 +135,8 @@
137 135 'most_used_anti_spam' => $this->most_used_anti_spam(),
138 136 'user_status' => $this->user_status(),
139 137 'pointer_popup_clicked' => $this->pointer_popup_clicked(),
140 138 ];
141 - // Every query against the entries table errors when the table is missing, so
142 - // resolve that once here rather than letting each caller below trip over it.
143 - $entries_table_missing = Register::is_entries_table_missing();
144 -
145 139 $stats_data['plugin_data']['sureforms']['numeric_values'] = [
146 140 'total_forms' => wp_count_posts( SRFM_FORMS_POST_TYPE )->publish ?? 0,
147 141 'instant_forms_enabled' => $this->instant_forms_enabled(),
148 142 'forms_using_custom_css' => $this->forms_using_custom_css(),
@@ -148,22 +142,15 @@
148 142 'forms_using_custom_css' => $this->forms_using_custom_css(),
149 143 'ai_generated_forms' => $this->ai_generated_forms(),
150 144 'ai_generated_payment_forms' => $this->ai_generated_forms( 'payments' ),
151 145 'payment_forms' => $this->get_payment_forms_count(),
152 - 'total_entries' => $entries_table_missing ? 0 : Entries::get_total_entries_by_status(),
146 + 'total_entries' => Entries::get_total_entries_by_status(),
153 147 'restricted_forms' => $this->get_restricted_forms(),
154 148 'embed_styling_gb_default' => self::embed_styling_gutenberg_count( 'default' ),
155 149 'embed_styling_el_default' => self::embed_styling_elementor_count( 'default' ),
156 150 'embed_styling_br_default' => self::embed_styling_bricks_count( 'default' ),
157 - 'total_form_views' => $this->total_form_views(),
158 - 'forms_with_views' => $this->forms_with_views(),
159 151 ];
160 152
161 - // Whether the entries table is currently missing. An event fires once when a
162 - // site first sees the notice; this is what shows the state persisting, and
163 - // catches a recurrence that the event's one-time dedup would swallow.
164 - $stats_data['plugin_data']['sureforms']['boolean_values']['db_entries_table_missing'] = $entries_table_missing;
165 -
166 153 $stats_data['plugin_data']['sureforms'] = array_merge_recursive( $stats_data['plugin_data']['sureforms'], $this->global_settings_data() );
167 154 // Add KPI tracking data.
168 155 $kpi_data = $this->get_kpi_tracking_data();
169 156 if ( ! empty( $kpi_data ) ) {
@@ -500,81 +487,12 @@
500 487
501 488 // Payment analytics - check if any payment method is enabled.
502 489 $global_data['boolean_values']['stripe_enabled'] = $this->is_stripe_enabled();
503 490
504 - // Delegated rather than read from $general_settings directly, so the telemetry
505 - // can never disagree with what the Forms list actually shows. That matters
506 - // because the default has already changed once: reimplementing the check here
507 - // means a future change has two places to be made and one to be forgotten.
508 - $global_data['boolean_values']['form_views_columns_enabled'] = Form_Views::get_instance()->is_tracking_enabled();
509 -
510 491 return $global_data;
511 492 }
512 493
513 494 /**
514 - * Total page views counted across all published forms.
515 - *
516 - * Paired with `forms_with_views` and the existing `total_entries`, this is what
517 - * makes the conversion figure interpretable in the warehouse: a site with views
518 - * but no entries reads very differently from one with neither.
519 - *
520 - * Counts only published forms, so views left behind by a trashed or draft form
521 - * do not inflate the total against a denominator that no longer includes them.
522 - *
523 - * @since 2.12.6
524 - * @return int
525 - */
526 - public function total_form_views() {
527 - global $wpdb;
528 -
529 - // Deliberately uncached: the only caller is the analytics payload builder,
530 - // which runs once per cron pass. A cache would never see a second read inside
531 - // a request, and any TTL would always have expired between passes — while
532 - // still going stale if a second caller ever appeared.
533 - // PHPCS: Ignore direct database query warning, as there is no built-in alternative.
534 - // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
535 - $total = $wpdb->get_var(
536 - $wpdb->prepare(
537 - "
538 - SELECT SUM( pm.meta_value )
539 - FROM {$wpdb->postmeta} pm
540 - INNER JOIN {$wpdb->posts} p ON p.ID = pm.post_id
541 - WHERE pm.meta_key = %s
542 - AND p.post_type = %s
543 - AND p.post_status = 'publish'
544 - ",
545 - Form_Views::META_KEY,
546 - SRFM_FORMS_POST_TYPE
547 - )
548 - );
549 -
550 - return Helper::get_integer_value( $total );
551 - }
552 -
553 - /**
554 - * Number of published forms that have been viewed at least once.
555 - *
556 - * Distinguishes "the feature is on but nothing is embedded anywhere" from "the
557 - * beacon is firing" — a total alone cannot, because one busy form looks the
558 - * same as many quiet ones.
559 - *
560 - * @since 2.12.6
561 - * @return int
562 - */
563 - public function forms_with_views() {
564 - return $this->custom_wp_query_total_posts(
565 - [
566 - [
567 - 'key' => Form_Views::META_KEY,
568 - 'value' => 0,
569 - 'compare' => '>',
570 - 'type' => 'NUMERIC',
571 - ],
572 - ]
573 - );
574 - }
575 -
576 - /**
577 495 * Returns user status.
578 496 *
579 497 * @since 1.8.0
580 498 * @return string
@@ -801,24 +719,8 @@
801 719 );
802 720 }
803 721
804 722 /**
805 - * Track the plugin_activated event with the correct install referer.
806 - *
807 - * Dedup in self::events()->track() ensures this fires only once. Runs on
808 - * 'shutdown' (see detect_state_events()) so it reads bsf_product_referers
809 - * after any late-writing referer call has had a chance to run.
810 - *
811 - * @since 2.12.6
812 - * @return void
813 - */
814 - public function track_plugin_activated_event() {
815 - $bsf_referrers = get_option( 'bsf_product_referers', [] );
816 - $source = ! empty( $bsf_referrers['sureforms'] ) ? $bsf_referrers['sureforms'] : 'self';
817 - self::events()->track( 'plugin_activated', SRFM_VER, [ 'source' => $source ] );
818 - }
819 -
820 - /**
821 723 * Extract non-inherit formTheme values from Bricks element data.
822 724 *
823 725 * Recursively walks the unserialized Bricks elements array looking for
824 726 * sureforms elements with custom formTheme settings.
@@ -921,16 +823,8 @@
921 823 * @since 2.4.0
922 824 * @return int Daily submissions count.
923 825 */
924 826 private function get_daily_submissions_count( $date ) {
925 - // Guarded here rather than at the call site: this is the function that runs
926 - // the query, so a future caller is covered too. Every read against a missing
927 - // entries table raises a DB error, and the daily send would raise one per
928 - // day counted on exactly the sites whose breakage we most need reported.
929 - if ( Register::is_entries_table_missing() ) {
930 - return 0;
931 - }
932 -
933 827 $start_date = $date . ' 00:00:00';
934 828 $end_date = $date . ' 23:59:59';
935 829
936 830 $where_conditions = [
@@ -958,19 +852,12 @@
958 852 * @since 2.5.1
959 853 * @return void
960 854 */
961 855 private function detect_state_events() {
962 - // plugin_activated: deferred to 'shutdown' so that a referring plugin/theme's
963 - // own BSF_UTM_Analytics::update_referer() call — which some products (incorrectly)
964 - // make only after their activate_plugin() call returns, in the same request — has
965 - // already run by the time we read bsf_product_referers. Reading this synchronously
966 - // here would race that write, since this constructor can execute mid-request while
967 - // SureForms itself is being activated by that other plugin.
968 - if ( did_action( 'shutdown' ) ) {
969 - $this->track_plugin_activated_event();
970 - } else {
971 - add_action( 'shutdown', [ $this, 'track_plugin_activated_event' ], PHP_INT_MAX );
972 - }
856 + // plugin_activated: dedup in self::events()->track() ensures this fires only once.
857 + $bsf_referrers = get_option( 'bsf_product_referers', [] );
858 + $source = ! empty( $bsf_referrers['sureforms'] ) ? $bsf_referrers['sureforms'] : 'self';
859 + self::events()->track( 'plugin_activated', SRFM_VER, [ 'source' => $source ] );
973 860
974 861 // One-time: re-send onboarding_completed with full properties (v2).
975 862 if ( ! Helper::get_srfm_option( 'onboarding_event_v2_flushed', false )
976 863 && \SRFM\Inc\Onboarding::get_instance()->get_onboarding_status() ) {