forms handled on this request */ private $done = array(); public function key() { return 'fm'; } public function name() { return 'Forminator'; } public function active() { return class_exists( 'Forminator_API' ) || defined( 'FORMINATOR_VERSION' ); } public function forms() { $forms = array(); foreach ( $this->list_forms() as $id => $form ) { $fields = array(); foreach ( $form['fields'] as $field ) { $type = (string) ( $field['type'] ?? '' ); $slug = (string) ( $field['slug'] ?? '' ); if ( '' === $slug || $this->skip_type( $type ) || in_array( $type, array( 'section', 'page-break', 'gdpr', 'consent', 'postdata', 'stripe', 'stripe-ocs', 'paypal', 'group', 'upload', 'password', 'signature' ), true ) ) { continue; } $fields[] = array( 'key' => $slug, 'label' => wp_strip_all_tags( (string) ( $field['label'] ?? '' ) ) ?: $slug, 'type' => $type, ); } $forms[ (string) $id ] = array( 'title' => $form['title'], 'fields' => $fields, ); } return $forms; } public function listen() { add_action( 'forminator_custom_form_submit_before_set_fields', array( $this, 'on_fields' ), 10, 3 ); add_action( 'forminator_form_after_handle_submit', array( $this, 'on_after_submit' ), 10, 2 ); } /** * @param object $entry Entry model. * @param int $form_id * @param array $field_data [ ['name' => 'phone-1', 'value' => …], … ] */ public function on_fields( $entry, $form_id, $field_data ) { $answers = array(); foreach ( (array) $field_data as $item ) { if ( is_array( $item ) && isset( $item['name'] ) && '_' !== substr( (string) $item['name'], 0, 1 ) ) { $answers[ (string) $item['name'] ] = $this->value( $item['value'] ?? '' ); } } $this->send( (string) $form_id, $answers, $field_data ); } /** * Fallback when submissions aren't stored: the posted values, only after a successful submit. */ public function on_after_submit( $form_id, $response ) { $form_id = (string) $form_id; if ( isset( $this->done[ $form_id ] ) || empty( $response['success'] ) ) { return; } $answers = array(); foreach ( $this->fields_of( $form_id ) as $slug ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Forminator verified this submission (nonce, validation) before firing the hook. if ( isset( $_POST[ $slug ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- as above; each value is sanitised by value(). $answers[ $slug ] = $this->value( wp_unslash( $_POST[ $slug ] ) ); } } $this->send( $form_id, $answers, $response ); } private function send( $form_id, array $answers, $raw ) { if ( '' === $form_id || isset( $this->done[ $form_id ] ) ) { return; } $this->done[ $form_id ] = true; $forms = $this->list_forms(); Beon_Notify_Forms::submitted( $this->key(), $form_id, $answers, $forms[ $form_id ]['title'] ?? '', $raw ); } /** Name / address parts (keyed arrays) joined with spaces; choices with commas. */ private function value( $value ) { if ( is_array( $value ) && array_keys( $value ) !== range( 0, count( $value ) - 1 ) ) { return trim( implode( ' ', array_filter( array_map( array( $this, 'text' ), $value ), 'strlen' ) ) ); } return $this->text( is_array( $value ) ? $value : sanitize_textarea_field( (string) $value ) ); } private function fields_of( $form_id ) { $forms = $this->list_forms(); return array_filter( array_column( $forms[ $form_id ]['fields'] ?? array(), 'slug' ), 'strlen' ); } /** * Forms as id => {title, fields: [{slug, label, type}]}, through Forminator_API, * else the form data Forminator keeps on its `forminator_forms` posts. */ private function list_forms() { static $cache = null; if ( null !== $cache ) { return $cache; } $cache = array(); if ( class_exists( 'Forminator_API' ) && method_exists( 'Forminator_API', 'get_forms' ) ) { $models = Forminator_API::get_forms( null, 1, 999 ); foreach ( is_array( $models ) ? $models : array() as $model ) { $id = (int) ( $model->id ?? 0 ); $fields = array(); foreach ( (array) ( method_exists( $model, 'get_fields' ) ? $model->get_fields() : array() ) as $f ) { $raw = is_object( $f ) && isset( $f->raw ) ? (array) $f->raw : (array) $f; $fields[] = array( 'slug' => (string) ( is_object( $f ) && isset( $f->slug ) ? $f->slug : ( $raw['element_id'] ?? ( $raw['id'] ?? '' ) ) ), 'label' => (string) ( $raw['field_label'] ?? '' ), 'type' => (string) ( $raw['type'] ?? '' ), ); } if ( $id ) { $cache[ $id ] = array( 'title' => (string) ( $model->settings['formName'] ?? ( $model->name ?? '' ) ), 'fields' => $fields, ); } } if ( $cache ) { return $cache; } } $posts = get_posts( array( 'post_type' => 'forminator_forms', 'post_status' => array( 'publish', 'draft', 'private' ), 'posts_per_page' => -1, ) ); foreach ( $posts as $post ) { $meta = (array) get_post_meta( $post->ID, 'forminator_form_meta', true ); $fields = array(); foreach ( (array) ( $meta['fields'] ?? array() ) as $raw ) { $fields[] = array( 'slug' => (string) ( $raw['element_id'] ?? ( $raw['id'] ?? '' ) ), 'label' => (string) ( $raw['field_label'] ?? '' ), 'type' => (string) ( $raw['type'] ?? '' ), ); } $cache[ $post->ID ] = array( 'title' => (string) ( $meta['settings']['formName'] ?? $post->post_title ), 'fields' => $fields, ); } return $cache; } }