View file File name : save-to-database.php Content :<?php namespace ElementorPro\Modules\Forms\Submissions\Actions; use Elementor\Controls_Manager; use Elementor\Core\Utils\Collection; use ElementorPro\Plugin; use ElementorPro\Modules\Forms\Widgets\Form; use ElementorPro\Modules\Forms\Classes\Action_Base; use ElementorPro\Modules\Forms\Submissions\Component; use ElementorPro\Modules\Forms\Submissions\Database\Query; use ElementorPro\Modules\Forms\Submissions\Database\Repositories\Form_Snapshot_Repository; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } class Save_To_Database extends Action_Base { private $submission_id; private $actions_succeeded_count = 0; public function get_name() { return 'save-to-database'; } public function get_label() { return esc_html__( 'Collect Submissions', 'elementor-pro' ); } public function register_settings_section( $widget ) { $widget->start_controls_section( 'section_submissions', [ 'label' => esc_html__( 'Collect Submissions', 'elementor-pro' ), 'condition' => [ 'submit_actions' => $this->get_name(), ], ] ); $widget->add_control( 'submissions_action_message', [ // TODO: Remove define() with the release of Elementor 3.22 'type' => defined( 'Controls_Manager::ALERT' ) ? Controls_Manager::ALERT : 'alert', 'alert_type' => 'info', 'content' => sprintf( /* translators: 1: Link open tag, 2: Link open tag, 3: Link close tag. */ esc_html__( 'Collected Submissions will be saved to Elementor > %1$s Submissions %2$s', 'elementor-pro' ), sprintf( '<a href="%s" target="_blank" rel="noreferrer">', self_admin_url( 'admin.php?page=' . Component::PAGE_ID ) ), '</a>', ), ] ); $widget->end_controls_section(); } public function on_export( $element ) { // This action does not have to do nothing on export. } /** * @param \ElementorPro\Modules\Forms\Classes\Form_Record $record * @param \ElementorPro\Modules\Forms\Classes\Ajax_Handler $ajax_handler */ public function run( $record, $ajax_handler ) { $meta = $record->get_form_meta( [ 'page_url', 'page_title', 'user_agent', 'remote_ip' ] ); $actions_count = ( new Collection( $record->get_form_settings( 'submit_actions' ) ) ) ->filter(function ( $value ) { return $value !== $this->get_name(); }) ->count(); $post_id = $record->get_form_settings( 'form_post_id' ); $element_id = $ajax_handler->get_current_form()['id']; $form_name = $record->get_form_settings( 'form_name' ); $this->submission_id = Query::get_instance()->add_submission( [ 'main_meta_id' => 0, 'post_id' => $post_id, 'referer' => remove_query_arg( [ 'preview_id', 'preview_nonce', 'preview' ], $meta['page_url']['value'] ), 'referer_title' => $meta['page_title']['value'], 'element_id' => $element_id, 'form_name' => $form_name, 'campaign_id' => 0, 'user_id' => get_current_user_id(), 'user_ip' => $meta['remote_ip']['value'], 'user_agent' => $meta['user_agent']['value'], 'actions_count' => $actions_count, 'actions_succeeded_count' => 0, 'meta' => wp_json_encode( [ // TODO: Should be removed if there is an ability to edit "global widgets" 'edit_post_id' => $record->get_form_settings( 'edit_post_id' ), ] ), ], $record->get_field( null ) ); /** @var Form $form_instance */ $form_instance = Plugin::elementor()->elements_manager->create_element_instance( $ajax_handler->get_current_form() ); $fields = $record->get_form_settings( 'form_fields' ); // When created new submission, it should also update or create // a form snapshot to save to new state of the form in case the form changed or will // be deleted later. Form_Snapshot_Repository::instance() ->create_or_update( $post_id, $element_id, [ 'name' => $form_name, 'fields' => array_map( function ( $field, $index ) use ( $form_instance ) { // Apply filters to demonstrate the same behavior as the render behavior. (adding select fields dynamically, etc.) // Ref: modules/forms/widgets/form.php:2116 $field = apply_filters( 'elementor_pro/forms/render/item', $field, $index, $form_instance ); $field = apply_filters( "elementor_pro/forms/render/item/{$field['field_type']}", $field, $index, $form_instance ); $mapped_field = [ 'id' => $field['custom_id'], 'type' => $field['field_type'], 'label' => $field['field_label'], ]; if ( isset( $field['field_options'] ) ) { $mapped_field['options'] = preg_split( '/(\r\n|\n|\r)/', $field['field_options'] ); } if ( isset( $field['allow_multiple'] ) ) { $mapped_field['is_multiple'] = 'true' === $field['allow_multiple']; } return $mapped_field; }, $fields, array_keys( $fields ) ), ] ); } /** * It listen for all the form actions and log the result into the database. * * @param Action_Base $action Should be class based on ActionBase (do not type hint to support third party plugins) * @param \Exception|null $exception */ private function save_action_log( $action, \Exception $exception = null ) { if ( ! $this->submission_id || $action->get_name() === $this->get_name() ) { return; } $query = Query::get_instance(); $error_message = null; if ( $exception ) { $error_message = $exception->getMessage(); $status = Query::ACTIONS_LOG_STATUS_FAILED; } else { $this->actions_succeeded_count += 1; $query->update_submission( $this->submission_id, [ 'actions_succeeded_count' => $this->actions_succeeded_count, ] ); $status = Query::ACTIONS_LOG_STATUS_SUCCESS; } $query->add_action_log( $this->submission_id, $action, $status, $error_message ); } /** * Save_To_Database constructor. */ public function __construct() { add_action( 'elementor_pro/forms/actions/after_run', function ( Action_Base $action, \Exception $exception = null ) { $this->save_action_log( $action, $exception ); }, 10, 2 ); } }