PluginProbe ʕ •ᴥ•ʔ
Atarim – AI Agency for WordPress: Edit Pages, Fix Code, Update Plugins, SEO & Client Feedback / trunk
Atarim – AI Agency for WordPress: Edit Pages, Fix Code, Update Plugins, SEO & Client Feedback vtrunk
5.1.3 5.1.2 5.1.1 5.1 5.0 trunk 3.10 3.11 3.12 3.13 3.14 3.15 3.16 3.17 3.18 3.19 3.2.0 3.2.1 3.22 3.22.1 3.22.2 3.22.3 3.22.4 3.22.5 3.22.6 3.3.0 3.3.1 3.3.2 3.3.2.1 3.3.2.2 3.3.3 3.30 3.31 3.32 3.4 3.4.1 3.4.3 3.4.4 3.5 3.5.1 3.6 3.6.1 3.7 3.8 3.9 3.9.1 3.9.2 3.9.3 3.9.4 3.9.6 3.9.6.1 4.0 4.0.1 4.0.2 4.0.3 4.0.4 4.0.5 4.0.6 4.0.7 4.0.8 4.0.9 4.1.0 4.1.1 4.1.2 4.1.3 4.2 4.2.1 4.2.2 4.3 4.3.1 4.3.2 4.3.3 4.3.4 4.3.5 4.4
atarim-visual-collaboration / third-party / forms / fluent-forms / class-avcf-fluent-helpers.php
atarim-visual-collaboration / third-party / forms / fluent-forms Last commit date
class-avcf-abilities-fluent-pro.php 3 weeks ago class-avcf-abilities-fluent.php 3 weeks ago class-avcf-fluent-detector.php 1 month ago class-avcf-fluent-helpers.php 3 weeks ago
class-avcf-fluent-helpers.php
214 lines
1 <?php
2 /**
3 * Fluent Forms — shared helpers for the standalone Fluent ability cluster.
4 *
5 * Fluent stores everything in its own tables, accessed here via direct $wpdb
6 * (the proven path from the old adapter): fluentform_forms (form_fields JSON),
7 * fluentform_submissions (response JSON), fluentform_form_meta (notifications
8 * and other settings as JSON value rows). Field definitions are nested —
9 * containers wrap children under 'fields', grids under 'columns'[].'fields' —
10 * so extraction recurses. Raw-$wpdb on a third-party schema is version-fragile;
11 * not runtime-tested here.
12 *
13 * @package atarim-visual-collaboration
14 */
15
16 if ( ! defined('ABSPATH') ) {
17 exit;
18 }
19
20 class AVCF_Fluent_Helpers {
21
22 const PLUGIN_SLUG = 'fluent';
23 const PLUGIN_LABEL = 'Fluent Forms';
24
25 public static function forms_table() { global $wpdb; return $wpdb->prefix . 'fluentform_forms'; }
26 public static function subs_table() { global $wpdb; return $wpdb->prefix . 'fluentform_submissions'; }
27 public static function meta_table() { global $wpdb; return $wpdb->prefix . 'fluentform_form_meta'; }
28
29 public static function map_form_summary( $row ) {
30 $form_id = (int) $row->id;
31 return [
32 'id' => $form_id,
33 'plugin' => self::PLUGIN_SLUG,
34 'title' => (string) $row->title,
35 'status' => (string) $row->status === 'published' ? 'active' : (string) $row->status,
36 'entries_total' => self::count_entries( $form_id, false ),
37 'last_submission' => self::last_submission_at( $form_id ),
38 'created_at' => isset( $row->created_at ) ? (string) $row->created_at : null,
39 ];
40 }
41
42 /** Recursively walk Fluent's nested field structure into a flat list. */
43 public static function extract_field( $f, &$fields ) {
44 if ( ! is_array( $f ) ) { return; }
45 $element = isset( $f['element'] ) ? (string) $f['element'] : '';
46 if ( in_array( $element, [ 'submit_button', 'section_break', 'recaptcha', 'hcaptcha', 'turnstile' ], true ) ) { return; }
47
48 if ( isset( $f['fields'] ) && is_array( $f['fields'] ) ) {
49 foreach ( $f['fields'] as $child ) { self::extract_field( $child, $fields ); }
50 return;
51 }
52 if ( isset( $f['columns'] ) && is_array( $f['columns'] ) ) {
53 foreach ( $f['columns'] as $col ) {
54 if ( isset( $col['fields'] ) && is_array( $col['fields'] ) ) {
55 foreach ( $col['fields'] as $child ) { self::extract_field( $child, $fields ); }
56 }
57 }
58 return;
59 }
60
61 $attrs = isset( $f['attributes'] ) && is_array( $f['attributes'] ) ? $f['attributes'] : [];
62 $settings = isset( $f['settings'] ) && is_array( $f['settings'] ) ? $f['settings'] : [];
63 $name = isset( $attrs['name'] ) ? (string) $attrs['name'] : '';
64 if ( $name === '' ) { return; }
65
66 $options = [];
67 if ( isset( $settings['advanced_options'] ) && is_array( $settings['advanced_options'] ) ) {
68 foreach ( $settings['advanced_options'] as $opt ) { if ( isset( $opt['label'] ) ) { $options[] = (string) $opt['label']; } }
69 }
70
71 $fields[] = [
72 'id' => $name,
73 'type' => $element,
74 'label' => isset( $settings['label'] ) ? (string) $settings['label'] : $name,
75 'required' => isset( $settings['validation_rules']['required']['value'] ) && ! empty( $settings['validation_rules']['required']['value'] ),
76 'options' => $options,
77 ];
78 }
79
80 public static function fields_from_row( $row ) {
81 $form_fields = isset( $row->form_fields ) ? $row->form_fields : '{}';
82 $decoded = json_decode( $form_fields, true );
83 $fields = [];
84 if ( is_array( $decoded ) && isset( $decoded['fields'] ) && is_array( $decoded['fields'] ) ) {
85 foreach ( $decoded['fields'] as $f ) { self::extract_field( $f, $fields ); }
86 }
87 return $fields;
88 }
89
90 public static function build_label_map( $fields ) {
91 $map = [];
92 foreach ( (array) $fields as $f ) {
93 if ( isset( $f['id'] ) ) { $map[ (string) $f['id'] ] = isset( $f['label'] ) ? (string) $f['label'] : (string) $f['id']; }
94 }
95 return $map;
96 }
97
98 /** Returns the raw decoded notifications map (nid => notif array), or []. */
99 public static function read_notifications_raw( $form_id ) {
100 global $wpdb;
101 $meta_table = self::meta_table();
102 $val = $wpdb->get_var( $wpdb->prepare( "SELECT value FROM `{$meta_table}` WHERE form_id = %d AND meta_key = %s LIMIT 1", (int) $form_id, 'notifications' ) );
103 if ( ! $val ) { return []; }
104 $decoded = json_decode( $val, true );
105 return is_array( $decoded ) ? $decoded : [];
106 }
107
108 public static function map_notifications( $raw ) {
109 $out = [];
110 foreach ( (array) $raw as $nid => $n ) {
111 if ( ! is_array( $n ) ) { continue; }
112 $email = isset( $n['sendTo']['email'] ) ? (string) $n['sendTo']['email'] : ( isset( $n['email'] ) ? (string) $n['email'] : '' );
113 $out[] = [
114 'id' => (string) $nid,
115 'name' => isset( $n['name'] ) ? (string) $n['name'] : ( 'Notification ' . $nid ),
116 'recipients' => self::parse_recipients( $email ),
117 'subject' => isset( $n['subject'] ) ? (string) $n['subject'] : '',
118 'enabled' => ! isset( $n['enabled'] ) || ! empty( $n['enabled'] ),
119 ];
120 }
121 return $out;
122 }
123
124 public static function map_form_full( $row, $include_raw = false ) {
125 $form_id = (int) $row->id;
126 $fields = self::fields_from_row( $row );
127 $notifications = self::map_notifications( self::read_notifications_raw( $form_id ) );
128 return [
129 'id' => $form_id,
130 'plugin' => self::PLUGIN_SLUG,
131 'title' => (string) $row->title,
132 'status' => (string) $row->status === 'published' ? 'active' : (string) $row->status,
133 'field_count' => count( $fields ),
134 'fields' => $fields,
135 'notifications' => $notifications,
136 'created_at' => isset( $row->created_at ) ? (string) $row->created_at : null,
137 'modified_at' => isset( $row->updated_at ) ? (string) $row->updated_at : null,
138 'shortcode' => sprintf( '[fluentform id="%d"]', $form_id ),
139 'raw' => $include_raw ? $row : null,
140 ];
141 }
142
143 public static function normalize_entry( $row, $form_id, $label_map, $include_raw = true ) {
144 $entry_id = isset( $row->id ) ? (int) $row->id : 0;
145 $form_id = (int) $form_id;
146 $response = isset( $row->response ) ? $row->response : '';
147 $decoded = is_string( $response ) ? json_decode( $response, true ) : ( is_array( $response ) ? $response : [] );
148
149 $fields = [];
150 if ( is_array( $decoded ) ) {
151 foreach ( $decoded as $fid => $value ) {
152 $fields[] = [ 'id' => (string) $fid, 'label' => isset( $label_map[ (string) $fid ] ) ? $label_map[ (string) $fid ] : (string) $fid, 'type' => '', 'value' => $value ];
153 }
154 }
155
156 $status_raw = isset( $row->status ) ? (string) $row->status : 'unread';
157 $norm = $status_raw === 'spam' ? 'spam' : ( $status_raw === 'trashed' ? 'trash' : 'published' );
158
159 return [
160 'id' => $entry_id,
161 'plugin' => self::PLUGIN_SLUG,
162 'form_id' => $form_id,
163 'submitted_at' => isset( $row->created_at ) ? (string) $row->created_at : '',
164 'source_url' => isset( $row->source_url ) ? (string) $row->source_url : null,
165 'ip_address' => isset( $row->ip ) ? (string) $row->ip : null,
166 'user_id' => isset( $row->user_id ) ? (int) $row->user_id : 0,
167 'status' => $norm,
168 'fields' => $fields,
169 'raw' => $include_raw ? $row : null,
170 ];
171 }
172
173 public static function count_entries( $form_id, $include_spam ) {
174 global $wpdb;
175 $table = self::subs_table();
176 $where = $include_spam ? 'form_id = %d' : "form_id = %d AND status != 'spam'";
177 return (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM `{$table}` WHERE {$where}", (int) $form_id ) );
178 }
179
180 public static function last_submission_at( $form_id ) {
181 global $wpdb;
182 $table = self::subs_table();
183 $row = $wpdb->get_var( $wpdb->prepare( "SELECT MAX(created_at) FROM `{$table}` WHERE form_id = %d", (int) $form_id ) );
184 return $row ? (string) $row : null;
185 }
186
187 public static function stats( $form_id, $args = [] ) {
188 global $wpdb;
189 $table = self::subs_table();
190 $where = [ 'form_id = %d', "status != 'spam'" ]; $params = [ (int) $form_id ];
191 if ( ! empty( $args['date_from'] ) ) { $where[] = 'created_at >= %s'; $params[] = (string) $args['date_from']; }
192 if ( ! empty( $args['date_to'] ) ) { $where[] = 'created_at <= %s'; $params[] = (string) $args['date_to']; }
193 $where_sql = implode( ' AND ', $where );
194 $by_day = $wpdb->get_results( $wpdb->prepare( "SELECT DATE(created_at) as day, COUNT(*) as count FROM `{$table}` WHERE {$where_sql} GROUP BY DATE(created_at) ORDER BY day ASC", $params ), ARRAY_A );
195 $ext = $wpdb->get_row( $wpdb->prepare( "SELECT MIN(created_at) as first_date, MAX(created_at) as last_date, COUNT(*) as total FROM `{$table}` WHERE {$where_sql}", $params ), ARRAY_A );
196 return [
197 'total' => isset( $ext['total'] ) ? (int) $ext['total'] : 0,
198 'first_date' => isset( $ext['first_date'] ) && $ext['first_date'] ? (string) $ext['first_date'] : null,
199 'last_date' => isset( $ext['last_date'] ) && $ext['last_date'] ? (string) $ext['last_date'] : null,
200 'by_day' => is_array( $by_day ) ? $by_day : [],
201 ];
202 }
203
204 public static function parse_recipients( $str ) {
205 if ( (string) $str === '' ) { return []; }
206 $out = [];
207 foreach ( (array) preg_split( '/[,\n;]+/', (string) $str ) as $part ) {
208 $clean = trim( (string) $part );
209 if ( $clean !== '' ) { $out[] = $clean; }
210 }
211 return $out;
212 }
213 }
214