PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 6.6
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v6.6
6.35 6.34 6.33.1 6.33 6.32.1 6.32 6.31 6.25 6.25.1 6.26 6.26.1 6.27 6.28 6.29 6.3 6.3.1 6.3.2 6.30 6.4 6.4.1 6.4.2 6.5 6.5.1 6.5.2 6.5.3 All 141 releases
formidable / classes / controllers / FrmEntriesAJAXSubmitController.php

FrmEntriesAJAXSubmitController.php in Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More 6.6, at classes/controllers/FrmEntriesAJAXSubmitController.php

214 lines 6.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if ( ! defined( 'ABSPATH' ) ) {
3 die( 'You are not allowed to call this page directly.' );
4 }
5
6 /**
7 * @since 6.2
8 */
9 class FrmEntriesAJAXSubmitController {
10
11 /**
12 * Create an entry when the ajax_submit option is on.
13 * If Pro is active, FrmProEntriesController::ajax_create will be used instead.
14 *
15 * @return void
16 */
17 public static function ajax_create() {
18 self::fix_woocommerce_conflict(); // This is called before we exit early to cover the conflict in Pro as well.
19
20 if ( is_callable( 'FrmProEntriesController::ajax_create' ) ) {
21 // Let Pro handle AJAX Submit if it's available.
22 // This is because Pro requires additional code to support other Pro features.
23 return;
24 }
25
26 if ( ! FrmAppHelper::doing_ajax() ) {
27 // Normally, this function would be triggered with the wp_ajax hook, but we need it fired sooner.
28 return;
29 }
30
31 if ( 'frm_entries_create' !== FrmAppHelper::get_post_param( 'action', '', 'sanitize_title' ) ) {
32 // Not a Formidable AJAX create request so exit early.
33 return;
34 }
35
36 $response = array(
37 'errors' => array(),
38 'content' => '',
39 'pass' => false,
40 );
41
42 $form_id = FrmAppHelper::get_post_param( 'form_id', 0, 'absint' );
43 if ( ! $form_id ) {
44 echo json_encode( $response );
45 wp_die();
46 }
47
48 $form = FrmForm::getOne( $form_id );
49 if ( ! $form ) {
50 echo json_encode( $response );
51 wp_die();
52 }
53
54 $is_ajax_on = FrmForm::is_ajax_on( $form );
55 if ( ! $is_ajax_on ) {
56 // This continues in the Pro version as it is required for other features including in-place edit.
57 // In Lite, if AJAX submit is not on, just exit early as this function is getting called incorrectly.
58 echo json_encode( $response );
59 wp_die();
60 }
61
62 $errors = FrmEntryValidate::validate( wp_unslash( $_POST ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
63
64 if ( ! $errors ) {
65 global $frm_vars;
66 $frm_vars['ajax'] = true;
67 $frm_vars['css_loaded'] = true;
68
69 FrmEntriesController::process_entry( '', true );
70
71 $title = FrmFormState::get_from_request( 'title', 'auto' );
72 $description = FrmFormState::get_from_request( 'description', 'auto' );
73 $response['content'] .= FrmFormsController::show_form( $form->id, '', $title, $description );
74
75 // Trigger the footer scripts if there is a form to show.
76 if ( ! empty( $frm_vars['forms_loaded'] ) ) {
77 ob_start();
78 self::print_ajax_scripts();
79 $response['content'] .= ob_get_contents();
80 ob_end_clean();
81
82 // Mark the end of added footer content.
83 $response['content'] .= '<span class="frm_end_ajax_' . $form->id . '"></span>';
84 }
85 } else {
86 $obj = array();
87 foreach ( $errors as $field => $error ) {
88 $field_id = str_replace( 'field', '', $field );
89 $error = self::maybe_modify_ajax_error( $error, $field_id, $form, $errors );
90 $obj[ $field_id ] = $error;
91 }
92
93 $response['errors'] = $obj;
94 $invalid_msg = FrmFormsHelper::get_invalid_error_message( array( 'form' => $form ) );
95 $response['error_message'] = FrmFormsHelper::get_success_message(
96 array(
97 'message' => $invalid_msg,
98 'form' => $form,
99 'entry_id' => 0,
100 'class' => FrmFormsHelper::form_error_class(),
101 )
102 );
103 }
104
105 $response = self::check_for_failed_form_submission( $response, $form->id );
106
107 echo json_encode( $response );
108 wp_die();
109 }
110
111 /**
112 * Prevent WooCommerce 7.6.0 from triggering a fatal error when wp_print_footer_scripts is called.
113 *
114 * @since 6.2.3
115 *
116 * @return void
117 */
118 private static function fix_woocommerce_conflict() {
119 add_action(
120 'wp_print_footer_scripts',
121 function() {
122 if ( ! function_exists( 'get_current_screen' ) ) {
123 require_once ABSPATH . 'wp-admin/includes/screen.php';
124 }
125
126 if ( ! class_exists( 'WP_Screen', false ) ) {
127 require_once ABSPATH . 'wp-admin/includes/class-wp-screen.php';
128 }
129
130 FrmAppHelper::set_current_screen_and_hook_suffix();
131 },
132 1
133 );
134 }
135
136 /**
137 * Load CAPTCHA script after AJAX submit so subsequent form CAPTCHAs don't break.
138 *
139 * @since 6.2
140 *
141 * @return void
142 */
143 private static function print_ajax_scripts() {
144 global $wp_scripts;
145 $keep_scripts = array( 'captcha-api' );
146 $keep_scripts = apply_filters( 'frm_ajax_load_scripts', $keep_scripts );
147 $registered_scripts = (array) $wp_scripts->registered;
148 $registered_scripts = array_diff( array_keys( $registered_scripts ), $keep_scripts );
149 $wp_scripts->done = array_merge( $wp_scripts->done, $registered_scripts );
150 wp_print_footer_scripts();
151 }
152
153 /**
154 * If a field has custom HTML for errors, apply it around the message.
155 *
156 * @since 6.2
157 *
158 * @param string $error
159 * @param string $field_id
160 * @param stdClass $form the form being submitted (not necessarily the field's form when embedded/repeated).
161 * @param array $errors all errors that were caught in this form submission, passed into the frm_before_replace_shortcodes filter for reference.
162 * @return string
163 */
164 private static function maybe_modify_ajax_error( $error, $field_id, $form, $errors ) {
165 if ( false !== strpos( $field_id, '-' ) ) {
166 // repeated fields look like field_id-repeater_id-iteration, so pull the first value for the field id.
167 list( $use_field_id ) = explode( '-', $field_id );
168 } else {
169 $use_field_id = $field_id;
170 }
171
172 if ( ! is_numeric( $use_field_id ) ) {
173 return $error;
174 }
175
176 $use_field = FrmField::getOne( $use_field_id );
177
178 if ( ! $use_field ) {
179 return $error;
180 }
181
182 $use_field = FrmFieldsHelper::setup_edit_vars( $use_field );
183 $error_body = FrmFieldsController::pull_custom_error_body_from_custom_html( $form, $use_field, $errors );
184
185 if ( false !== $error_body ) {
186 $error = str_replace( '[error]', $error, $error_body );
187 $error = str_replace( '[key]', $field_id, $error );
188 }
189
190 return $error;
191 }
192
193 /**
194 * Confirm that the result of calling FrmFormsController::show_form added the failed message for a duplicate entry to the HTML.
195 * If it did, move the message to the errors key instead of returning the content.
196 *
197 * @since 6.2
198 *
199 * @param array $response
200 * @param string|int $form_id
201 * @return array
202 */
203 private static function check_for_failed_form_submission( $response, $form_id ) {
204 $frm_settings = FrmAppHelper::get_settings( array( 'current_form' => $form_id ) );
205
206 if ( false !== strpos( $response['content'], $frm_settings->failed_msg ) ) {
207 $response['errors']['failed'] = $frm_settings->failed_msg;
208 $response['content'] = '';
209 }
210
211 return $response;
212 }
213 }
214