xecuted because of the filter on `wp_redirect`. // The code, that is below listen(), runs only if no redirect happened. $this->listen(); $form_data = $this->form_data; if ( empty( $form_data ) ) { $form_data = wpforms()->obj( 'form' )->get( $form_id, [ 'content_only' => true ] ); // phpcs:ignore WPForms.Comments.PHPDocHooks.RequiredHookDocumentation, WPForms.PHP.ValidateHooks.InvalidHookName $form_data = apply_filters( 'wpforms_frontend_form_data', $form_data ); } if ( ! empty( $this->errors[ $form_id ] ) ) { $this->ajax_process_errors( $form_id, $form_data ); wp_send_json_error(); } ob_start(); wpforms()->obj( 'frontend' )->confirmation( $form_data ); // phpcs:ignore WPForms.Comments.PHPDocHooks.RequiredHookDocumentation, WPForms.PHP.ValidateHooks.InvalidHookName $response = apply_filters( 'wpforms_ajax_submit_success_response', [ 'confirmation' => ob_get_clean() ], $form_id, $form_data ); // phpcs:ignore WPForms.Comments.PHPDocHooks.RequiredHookDocumentation, WPForms.PHP.ValidateHooks.InvalidHookName do_action( 'wpforms_ajax_submit_completed', $form_id, $response ); wp_send_json_success( $response ); } /** * Process AJAX errors. * * @since 1.5.3 * * @todo This should be re-used/combined for AMP verify-xhr requests. * * @param int $form_id Form ID. * @param array $form_data Form data and settings. */ protected function ajax_process_errors( $form_id, $form_data ) { $errors = $this->errors[ $form_id ] ?? []; // phpcs:ignore WPForms.Comments.PHPDocHooks.RequiredHookDocumentation, WPForms.PHP.ValidateHooks.InvalidHookName $errors = apply_filters( 'wpforms_ajax_submit_errors', $errors, $form_id, $form_data ); if ( empty( $errors ) ) { wp_send_json_error(); } // General errors are errors that cannot be populated with the jQuery Validate plugin. $general_errors = array_intersect_key( $errors, array_flip( [ 'header', 'footer', 'header_styled', 'footer_styled', 'recaptcha' ] ) ); foreach ( $general_errors as $key => $error ) { ob_start(); wpforms()->obj( 'frontend' )->form_error( $key, $error, $form_data ); $general_errors[ $key ] = ob_get_clean(); } $fields = $form_data['fields'] ?? []; // Get registered fields errors only. $field_errors = array_intersect_key( $errors, $fields ); // Transform field ids to field names for jQuery Validate plugin. foreach ( $field_errors as $key => $error ) { $name = $this->ajax_error_field_name( $fields[ $key ], $form_data, $error ); if ( $name ) { $field_errors[ $name ] = $error; } unset( $field_errors[ $key ] ); } $response = []; if ( $general_errors ) { $response['errors']['general'] = $general_errors; } if ( $field_errors ) { $response['errors']['field'] = $field_errors; } // phpcs:ignore WPForms.Comments.PHPDocHooks.RequiredHookDocumentation, WPForms.PHP.ValidateHooks.InvalidHookName $response = apply_filters( 'wpforms_ajax_submit_errors_response', $response, $form_id, $form_data ); // phpcs:ignore WPForms.Comments.PHPDocHooks.RequiredHookDocumentation, WPForms.PHP.ValidateHooks.InvalidHookName do_action( 'wpforms_ajax_submit_completed', $form_id, $response ); wp_send_json_error( $response ); } /** * Get a field name for an ajax error message. * * @since 1.6.3 * * @param array $field Field settings. * @param array $form_data Form data and settings. * @param string|string[] $error Error message. * * @return string */ private function ajax_error_field_name( array $field, array $form_data, $error ): string { $props = wpforms()->obj( 'frontend' )->get_field_properties( $field, $form_data ); /** * Filter the field name for an ajax error message. * * @since 1.6.3 * * @param string $name Error field name. * @param array $field Field. * @param array $props Field properties. * @param string|string[] $error Error message. */ return (string) apply_filters( 'wpforms_process_ajax_error_field_name', '', $field, $props, $error ); } /** * Process AJAX redirect. * * @since 1.5.3 * * @param string $url Redirect URL. */ public function ajax_process_redirect( $url ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing $form_id = isset( $_POST['wpforms']['id'] ) ? absint( $_POST['wpforms']['id'] ) : 0; if ( empty( $form_id ) ) { wp_send_json_error(); } $response = [ 'form_id' => $form_id, 'redirect_url' => $url, ]; // phpcs:ignore WPForms.Comments.PHPDocHooks.RequiredHookDocumentation, WPForms.PHP.ValidateHooks.InvalidHookName $response = apply_filters( 'wpforms_ajax_submit_redirect', $response, $form_id, $url ); // phpcs:ignore WPForms.Comments.PHPDocHooks.RequiredHookDocumentation, WPForms.PHP.ValidateHooks.InvalidHookName do_action( 'wpforms_ajax_submit_completed', $form_id, $response ); wp_send_json_success( $response ); } /** * Conditionally add a new_tab key to the AJAX response. * * @since 1.9.2 * * @param array $response AJAX response. * * @return array AJAX response. */ public function maybe_open_in_new_tab( array $response ): array { $open_in_new_tab = $this->confirmation['redirect_new_tab'] ?? false; if ( $open_in_new_tab ) { $response['new_tab'] = true; } return $response; } /** * Validate action value for ajax form submission. * * @since 1.9.3 * * @return bool */ private function is_valid_ajax_submit_action(): bool { // In the case of AMP form submission, the action is not set. if ( wpforms_is_amp( false ) ) { return true; } // phpcs:ignore WordPress.Security.NonceVerification.Missing return ! empty( $_POST['action'] ) && $_POST['action'] === 'wpforms_submit'; } /** * Get current email handler. * * @since 1.9.4 * * @return mixed|Mailer|WPForms_WP_Emails|null */ public function get_email_handler() { return $this->email_handler; } }