class-avcf-abilities-forminator-pro.php
3 weeks ago
class-avcf-abilities-forminator.php
3 weeks ago
class-avcf-forminator-detector.php
3 weeks ago
class-avcf-forminator-helpers.php
3 weeks ago
class-avcf-forminator-helpers.php
211 lines
| 1 | <?php |
| 2 | /** |
| 3 | * Forminator — shared helpers for the standalone Forminator ability cluster. |
| 4 | * |
| 5 | * Uses Forminator_API for forms/entries (the form model exposes ->fields and |
| 6 | * ->settings; entries expose ->meta_data and ->is_spam) and direct $wpdb on |
| 7 | * frmt_form_entry for stats/counts (is_spam column flags spam). Notifications |
| 8 | * live in the form settings under 'notifications' or 'email-notifications'. |
| 9 | * Built on Forminator's API; not runtime-tested here. |
| 10 | * |
| 11 | * @package atarim-visual-collaboration |
| 12 | */ |
| 13 | |
| 14 | if ( ! defined('ABSPATH') ) { |
| 15 | exit; |
| 16 | } |
| 17 | |
| 18 | class AVCF_Forminator_Helpers { |
| 19 | |
| 20 | const PLUGIN_SLUG = 'forminator'; |
| 21 | const PLUGIN_LABEL = 'Forminator'; |
| 22 | |
| 23 | public static function entry_table() { global $wpdb; return $wpdb->prefix . 'frmt_form_entry'; } |
| 24 | |
| 25 | public static function settings_array( $form ) { |
| 26 | if ( is_object( $form ) && property_exists( $form, 'settings' ) && is_array( $form->settings ) ) { return $form->settings; } |
| 27 | return []; |
| 28 | } |
| 29 | |
| 30 | public static function extract_id( $form ) { |
| 31 | if ( is_object( $form ) && property_exists( $form, 'id' ) ) { return (int) $form->id; } |
| 32 | if ( is_array( $form ) && isset( $form['id'] ) ) { return (int) $form['id']; } |
| 33 | return 0; |
| 34 | } |
| 35 | |
| 36 | public static function extract_title( $form ) { |
| 37 | $s = self::settings_array( $form ); |
| 38 | if ( isset( $s['formName'] ) ) { return (string) $s['formName']; } |
| 39 | if ( isset( $s['form-name'] ) ) { return (string) $s['form-name']; } |
| 40 | if ( is_object( $form ) && property_exists( $form, 'name' ) ) { return (string) $form->name; } |
| 41 | return ''; |
| 42 | } |
| 43 | |
| 44 | public static function extract_status( $form ) { |
| 45 | if ( is_object( $form ) && property_exists( $form, 'status' ) ) { return $form->status === 'publish' ? 'active' : (string) $form->status; } |
| 46 | return 'active'; |
| 47 | } |
| 48 | |
| 49 | public static function extract_created( $form ) { |
| 50 | if ( is_object( $form ) && property_exists( $form, 'raw' ) && isset( $form->raw->post_date ) ) { return (string) $form->raw->post_date; } |
| 51 | return null; |
| 52 | } |
| 53 | |
| 54 | public static function map_form_summary( $form ) { |
| 55 | $form_id = self::extract_id( $form ); |
| 56 | return [ |
| 57 | 'id' => $form_id, |
| 58 | 'plugin' => self::PLUGIN_SLUG, |
| 59 | 'title' => self::extract_title( $form ), |
| 60 | 'status' => self::extract_status( $form ), |
| 61 | 'entries_total' => $form_id > 0 ? self::count_entries( $form_id, false ) : 0, |
| 62 | 'last_submission' => $form_id > 0 ? self::last_submission_at( $form_id ) : null, |
| 63 | 'created_at' => self::extract_created( $form ), |
| 64 | ]; |
| 65 | } |
| 66 | |
| 67 | public static function map_fields( $form ) { |
| 68 | $fields = []; |
| 69 | $raw_fields = is_object( $form ) && property_exists( $form, 'fields' ) ? $form->fields : []; |
| 70 | if ( ! is_array( $raw_fields ) ) { return $fields; } |
| 71 | foreach ( $raw_fields as $f ) { |
| 72 | $slug = is_object( $f ) && property_exists( $f, 'slug' ) ? (string) $f->slug : ( is_array( $f ) && isset( $f['slug'] ) ? (string) $f['slug'] : '' ); |
| 73 | $type = is_object( $f ) && property_exists( $f, 'type' ) ? (string) $f->type : ( is_array( $f ) && isset( $f['type'] ) ? (string) $f['type'] : 'unknown' ); |
| 74 | $fs = ( is_object( $f ) && property_exists( $f, 'raw' ) && is_array( $f->raw ) ) ? $f->raw : ( is_array( $f ) ? $f : [] ); |
| 75 | $options = []; |
| 76 | if ( isset( $fs['options'] ) && is_array( $fs['options'] ) ) { |
| 77 | foreach ( $fs['options'] as $opt ) { if ( isset( $opt['label'] ) ) { $options[] = (string) $opt['label']; } } |
| 78 | } |
| 79 | $fields[] = [ |
| 80 | 'id' => $slug, |
| 81 | 'type' => $type, |
| 82 | 'label' => isset( $fs['field_label'] ) ? (string) $fs['field_label'] : $slug, |
| 83 | 'required' => ! empty( $fs['required'] ), |
| 84 | 'options' => $options, |
| 85 | ]; |
| 86 | } |
| 87 | return $fields; |
| 88 | } |
| 89 | |
| 90 | /** Returns [ key, list ] where key is the settings key in use, list is the notification rows. */ |
| 91 | public static function notifications_block( $settings ) { |
| 92 | $key = isset( $settings['notifications'] ) && is_array( $settings['notifications'] ) ? 'notifications' |
| 93 | : ( isset( $settings['email-notifications'] ) && is_array( $settings['email-notifications'] ) ? 'email-notifications' : null ); |
| 94 | return [ $key, $key === null ? [] : $settings[ $key ] ]; |
| 95 | } |
| 96 | |
| 97 | public static function map_notifications( $settings ) { |
| 98 | $list = self::notifications_block( $settings ); |
| 99 | $out = []; |
| 100 | foreach ( (array) $list[1] as $idx => $n ) { |
| 101 | if ( ! is_array( $n ) ) { continue; } |
| 102 | $out[] = [ |
| 103 | 'id' => (string) ( isset( $n['slug'] ) ? $n['slug'] : $idx ), |
| 104 | 'name' => isset( $n['label'] ) ? (string) $n['label'] : ( 'Notification ' . $idx ), |
| 105 | 'recipients' => self::parse_recipients( isset( $n['recipients'] ) ? (string) $n['recipients'] : ( isset( $n['email-recipients'] ) ? (string) $n['email-recipients'] : '' ) ), |
| 106 | 'subject' => isset( $n['email-subject'] ) ? (string) $n['email-subject'] : ( isset( $n['subject'] ) ? (string) $n['subject'] : '' ), |
| 107 | 'enabled' => true, |
| 108 | ]; |
| 109 | } |
| 110 | return $out; |
| 111 | } |
| 112 | |
| 113 | public static function map_form_full( $form, $include_raw = false ) { |
| 114 | $form_id = self::extract_id( $form ); |
| 115 | $settings = self::settings_array( $form ); |
| 116 | $fields = self::map_fields( $form ); |
| 117 | return [ |
| 118 | 'id' => $form_id, |
| 119 | 'plugin' => self::PLUGIN_SLUG, |
| 120 | 'title' => self::extract_title( $form ), |
| 121 | 'status' => self::extract_status( $form ), |
| 122 | 'field_count' => count( $fields ), |
| 123 | 'fields' => $fields, |
| 124 | 'notifications' => self::map_notifications( $settings ), |
| 125 | 'created_at' => self::extract_created( $form ), |
| 126 | 'shortcode' => sprintf( '[forminator_form id="%d"]', $form_id ), |
| 127 | 'raw' => $include_raw ? $settings : null, |
| 128 | ]; |
| 129 | } |
| 130 | |
| 131 | public static function build_label_map( $form ) { |
| 132 | $map = []; |
| 133 | if ( is_object( $form ) && property_exists( $form, 'fields' ) && is_array( $form->fields ) ) { |
| 134 | foreach ( $form->fields as $f ) { |
| 135 | $slug = is_object( $f ) && property_exists( $f, 'slug' ) ? (string) $f->slug : ''; |
| 136 | if ( $slug === '' ) { continue; } |
| 137 | $fs = ( is_object( $f ) && property_exists( $f, 'raw' ) && is_array( $f->raw ) ) ? $f->raw : []; |
| 138 | $map[ $slug ] = isset( $fs['field_label'] ) ? (string) $fs['field_label'] : $slug; |
| 139 | } |
| 140 | } |
| 141 | return $map; |
| 142 | } |
| 143 | |
| 144 | public static function entry_is_spam( $entry ) { |
| 145 | return is_object( $entry ) && property_exists( $entry, 'is_spam' ) ? (bool) $entry->is_spam : false; |
| 146 | } |
| 147 | |
| 148 | public static function normalize_entry( $raw_entry, $form_id, $label_map, $include_raw = true ) { |
| 149 | $entry_id = is_object( $raw_entry ) && property_exists( $raw_entry, 'entry_id' ) ? (int) $raw_entry->entry_id : 0; |
| 150 | $form_id = (int) $form_id; |
| 151 | $fields = []; |
| 152 | $meta = is_object( $raw_entry ) && property_exists( $raw_entry, 'meta_data' ) && is_array( $raw_entry->meta_data ) ? $raw_entry->meta_data : []; |
| 153 | foreach ( $meta as $slug => $m ) { |
| 154 | $fields[] = [ 'id' => (string) $slug, 'label' => isset( $label_map[ $slug ] ) ? $label_map[ $slug ] : (string) $slug, 'type' => '', 'value' => isset( $m['value'] ) ? $m['value'] : '' ]; |
| 155 | } |
| 156 | return [ |
| 157 | 'id' => $entry_id, |
| 158 | 'plugin' => self::PLUGIN_SLUG, |
| 159 | 'form_id' => $form_id, |
| 160 | 'submitted_at' => is_object( $raw_entry ) && property_exists( $raw_entry, 'date_created_sql' ) ? (string) $raw_entry->date_created_sql : '', |
| 161 | 'source_url' => null, |
| 162 | 'ip_address' => null, |
| 163 | 'user_id' => 0, |
| 164 | 'status' => self::entry_is_spam( $raw_entry ) ? 'spam' : 'published', |
| 165 | 'fields' => $fields, |
| 166 | 'raw' => $include_raw ? $raw_entry : null, |
| 167 | ]; |
| 168 | } |
| 169 | |
| 170 | public static function count_entries( $form_id, $include_spam ) { |
| 171 | global $wpdb; |
| 172 | $table = self::entry_table(); |
| 173 | $where = $include_spam ? 'form_id = %d' : 'form_id = %d AND is_spam = 0'; |
| 174 | return (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM `{$table}` WHERE {$where}", (int) $form_id ) ); |
| 175 | } |
| 176 | |
| 177 | public static function last_submission_at( $form_id ) { |
| 178 | global $wpdb; |
| 179 | $table = self::entry_table(); |
| 180 | $row = $wpdb->get_var( $wpdb->prepare( "SELECT MAX(date_created) FROM `{$table}` WHERE form_id = %d", (int) $form_id ) ); |
| 181 | return $row ? (string) $row : null; |
| 182 | } |
| 183 | |
| 184 | public static function stats( $form_id, $args = [] ) { |
| 185 | global $wpdb; |
| 186 | $table = self::entry_table(); |
| 187 | $where = [ 'form_id = %d', 'is_spam = 0' ]; $params = [ (int) $form_id ]; |
| 188 | if ( ! empty( $args['date_from'] ) ) { $where[] = 'date_created >= %s'; $params[] = (string) $args['date_from']; } |
| 189 | if ( ! empty( $args['date_to'] ) ) { $where[] = 'date_created <= %s'; $params[] = (string) $args['date_to']; } |
| 190 | $where_sql = implode( ' AND ', $where ); |
| 191 | $by_day = $wpdb->get_results( $wpdb->prepare( "SELECT DATE(date_created) as day, COUNT(*) as count FROM `{$table}` WHERE {$where_sql} GROUP BY DATE(date_created) ORDER BY day ASC", $params ), ARRAY_A ); |
| 192 | $ext = $wpdb->get_row( $wpdb->prepare( "SELECT MIN(date_created) as first_date, MAX(date_created) as last_date, COUNT(*) as total FROM `{$table}` WHERE {$where_sql}", $params ), ARRAY_A ); |
| 193 | return [ |
| 194 | 'total' => isset( $ext['total'] ) ? (int) $ext['total'] : 0, |
| 195 | 'first_date' => isset( $ext['first_date'] ) && $ext['first_date'] ? (string) $ext['first_date'] : null, |
| 196 | 'last_date' => isset( $ext['last_date'] ) && $ext['last_date'] ? (string) $ext['last_date'] : null, |
| 197 | 'by_day' => is_array( $by_day ) ? $by_day : [], |
| 198 | ]; |
| 199 | } |
| 200 | |
| 201 | public static function parse_recipients( $str ) { |
| 202 | if ( (string) $str === '' ) { return []; } |
| 203 | $out = []; |
| 204 | foreach ( (array) preg_split( '/[,\n;]+/', (string) $str ) as $part ) { |
| 205 | $clean = trim( (string) $part ); |
| 206 | if ( $clean !== '' ) { $out[] = $clean; } |
| 207 | } |
| 208 | return $out; |
| 209 | } |
| 210 | } |
| 211 |