PluginProbe
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz / 1.12.2
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz v1.12.2
2.12.6 2.12.5 2.12.4 2.12.3 2.12.2 2.12.1 2.12.0 2.11.1 2.11.0 2.10.1 2.10.0 2.9.1 2.9.0 2.8.2 2.8.1 2.7.0 2.7.1 2.8.0 trunk 0.0.10 0.0.11 0.0.12 0.0.13 0.0.2 0.0.3 All 96 releases
sureforms / inc / field-validation.php
field-validation.php
243 lines 9.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Field Validation Class
4 *
5 * Handles all field validation for SureForms
6 *
7 * @package SureForms
8 * @since 1.12.2
9 */
10
11 namespace SRFM\Inc;
12
13 if ( ! defined( 'ABSPATH' ) ) {
14 exit; // Exit if accessed directly.
15 }
16
17 /**
18 * Field Validation Class
19 */
20 class Field_Validation {
21 /**
22 * Add block configuration for form fields.
23 *
24 * This function processes blocks in a form and stores their configuration as post meta.
25 * It applies filters to allow extensions to modify block configs and stores processed
26 * values for blocks that need special handling (like upload fields).
27 *
28 * @param array<mixed> $blocks Array of blocks to process.
29 * @param int $form_id Form post ID.
30 * @return void
31 * @since 1.12.2
32 */
33 public static function add_block_config( $blocks, $form_id ) {
34 // Initialize array to store processed block configurations.
35 $block_config = [];
36
37 // Loop through each block.
38 foreach ( $blocks as $block ) {
39 // Ensure $block is an array and has the required structure.
40 if ( ! is_array( $block ) ) {
41 continue;
42 }
43 if ( ! isset( $block['blockName'] ) || ! isset( $block['attrs'] ) || ! is_array( $block['attrs'] ) ) {
44 continue;
45 }
46 // Validate block id.
47 if ( ! array_key_exists( 'block_id', $block['attrs'] ) || empty( $block['attrs']['block_id'] ) || ! is_string( $block['attrs']['block_id'] ) ) {
48 continue;
49 }
50
51 $block_id = sanitize_text_field( $block['attrs']['block_id'] );
52
53 // Allow extensions to process and modify block config.
54 $config = apply_filters( 'srfm_block_config', [ 'block' => $block ] );
55
56 // If block was processed by a filter, add its processed value.
57 if ( isset( $config['processed_value'] ) && ! empty( $config['processed_value'] ) ) {
58 $block_config[ $block_id ] = $config['processed_value'];
59 continue;
60 }
61 }
62
63 // Only update meta if we have processed configurations.
64 if ( ! empty( $block_config ) ) {
65 update_post_meta( $form_id, '_srfm_block_config', $block_config );
66 }
67 }
68
69 /**
70 * Retrieve or migrate the block configuration for legacy forms.
71 *
72 * This function checks if the _srfm_block_config post meta exists for the given form ID.
73 * Example: get_post_meta( 123, '_srfm_block_config', true ) might return an array of block configs.
74 * If not found, it attempts to parse the form's post content and generate the block config.
75 * Example: If a legacy form with ID 123 has no _srfm_block_config, but its post_content contains blocks,
76 * the function will parse those blocks and call add_block_config() to generate and store the config.
77 *
78 * @param int $form_id The ID of the form post.
79 * @since 1.12.2
80 * @return array|null The block configuration array, or null if not found or invalid.
81 */
82 public static function get_or_migrate_block_config_for_legacy_form( $form_id ) {
83 // Validate that $form_id is a positive integer.
84 // Example: $form_id = 123 is valid; $form_id = -1 or 'abc' is not.
85 if ( ! is_int( $form_id ) || $form_id <= 0 ) {
86 return null;
87 }
88
89 // Retrieve the block config from post meta.
90 // Example: $block_config = [ 'block-1' => [ ... ], 'block-2' => [ ... ] ].
91 $block_config = get_post_meta( $form_id, '_srfm_block_config', true );
92 if ( ! empty( $block_config ) && is_array( $block_config ) ) {
93 // If it exists and is an array, return it directly (no migration needed).
94 // Example: Returning the existing $block_config array.
95 return $block_config;
96 }
97
98 // Get the post by ID and validate.
99 // Example: $post = get_post( 123 ); $post->post_content should contain block markup.
100 $post = get_post( $form_id );
101 if ( ! ( $post instanceof \WP_Post ) || empty( $post->post_content ) ) {
102 return null;
103 }
104
105 // Parse the blocks from the post content and attempt migration.
106 // Example: $blocks = parse_blocks( $post->post_content ); $blocks is an array of block arrays.
107 if ( function_exists( 'parse_blocks' ) ) {
108 $blocks = parse_blocks( $post->post_content );
109 if ( is_array( $blocks ) && ! empty( $blocks ) ) {
110 self::add_block_config( $blocks, $form_id );
111 }
112 }
113
114 // Retrieve the block config again after migration attempt.
115 // Example: After migration, $block_config should now be an array if successful.
116 $block_config = get_post_meta( $form_id, '_srfm_block_config', true );
117
118 return ! empty( $block_config ) && is_array( $block_config ) ? $block_config : null;
119 }
120
121 /**
122 * Prepare validation data for a given form.
123 *
124 * Retrieves the form block configuration from post meta and adds a 'name_with_id'
125 * key to each block, which is a unique identifier for the field (used for validation).
126 *
127 * @param int $current_form_id The ID of the form post.
128 * @since 1.12.2
129 * @return array|null The processed form configuration array, or null if not found.
130 */
131 public static function prepared_validation_data( $current_form_id ) {
132 // Retrieve the form block configuration from post meta.
133 $get_form_config = self::get_or_migrate_block_config_for_legacy_form( $current_form_id );
134
135 // If the configuration is an array, add a 'name_with_id' key to each block.
136 if ( is_array( $get_form_config ) ) {
137 foreach ( $get_form_config as $index => $block ) {
138 // Ensure both 'blockName' and 'block_id' exist before creating the identifier.
139 if ( isset( $block['blockName'] ) ) {
140 // 'name_with_id' is used as a unique field identifier for validation.
141 // Example: 'sureforms-input-abc123' for blockName 'sureforms/input' and block_id 'abc123'
142 $get_form_config[ $index ]['name_with_id'] = str_replace( '/', '-', $block['blockName'] ) . '-' . $index;
143 }
144 }
145 }
146
147 // Return the processed configuration array, or an empty array if not found.
148 return is_array( $get_form_config ) ? $get_form_config : [];
149 }
150
151 /**
152 * Validate form data for a given form.
153 *
154 * This function checks each field in the submitted form data (including uploaded files)
155 * and applies the 'srfm_validate_form_data' filter to validate each field according to
156 * its configuration. Only fields with keys containing '-lbl-' (SureForms fields) are processed.
157 * If a field fails validation, its error message is added to the $not_valid_fields array.
158 *
159 * @param array<mixed> $form_data The submitted form data (sanitized).
160 * @param int|mixed $current_form_id The ID of the form being validated.
161 * @since 1.12.2
162 * @return array An array of invalid fields and their error messages. Empty if all fields are valid.
163 */
164 public static function validate_form_data( $form_data, $current_form_id ) {
165 if ( ! is_array( $form_data ) || ! is_numeric( $current_form_id ) ) {
166 return [];
167 }
168
169 // Holds fields that are not valid. Example: [ 'srfm-email-c867d9d9-lbl-email' => 'This field is required.' ].
170 $not_valid_fields = [];
171
172 // Retrieve the processed form configuration for validation.
173 $get_form_config = self::prepared_validation_data( Helper::get_integer_value( $current_form_id ) );
174
175 $form_data = apply_filters( 'srfm_field_validation_data', $form_data );
176
177 // Iterate over each field in the form data.
178 foreach ( $form_data as $key => $value ) {
179 /**
180 * Only process SureForms fields.
181 * The '-lbl-' substring is mandatory in SureForms field keys.
182 * Example: $key = 'srfm-email-c867d9d9-lbl-email'
183 */
184 if ( false === strpos( $key, '-lbl-' ) ) {
185 continue;
186 }
187
188 $get_name_with_id = explode( '-lbl-', $key );
189 // Extract the part after the last '-' in the key, if it matches the pattern.
190 // Example: $get_name_with_id[0] = "srfm-email-c867d9d9".
191 // $extracted_id = "c867d9d9".
192 $extracted_id = '';
193 if ( is_string( $key ) && preg_match( '/-([a-zA-Z0-9]+)$/', $get_name_with_id[0], $matches ) ) {
194 $extracted_id = $matches[1];
195 // Now $extracted_id contains "c867d9d9" for "srfm-email-c867d9d9".
196 }
197
198 // $get_slug will be the slug after the first hyphen in the second part.
199 // Example: $get_name_with_id[1] = "email" or "field-email", $get_slug = "email".
200 $get_slug = isset( $get_name_with_id[1] ) ? preg_replace( '/^[^-]+-/', '', $get_name_with_id[1] ) : '';
201
202 // $get_field_name is the field name without the block id.
203 // Example: "srfm-email-c867d9d9" => "srfm-email".
204 $get_field_name = str_replace( '-' . $extracted_id, '', $get_name_with_id[0] );
205
206 // Apply the validation filter for the current field.
207 // Example: Passes all relevant field data to the filter for validation.
208 $field_validated = apply_filters(
209 'srfm_validate_form_data',
210 [
211 'field_key' => $key,
212 'field_value' => $value,
213 'form_id' => $current_form_id,
214 'form_config' => $get_form_config,
215 'block_id' => $extracted_id,
216 'block_slug' => $get_slug,
217 'name_with_id' => $get_name_with_id[0],
218 'field_name' => $get_field_name,
219 ]
220 );
221
222 // Check the result of the validation.
223 // Example: $field_validated = [ 'validated' => false, 'error' => 'This field is required.' ].
224 if ( isset( $field_validated['validated'] ) ) {
225 // If the field is valid, skip to the next field.
226 if ( true === $field_validated['validated'] ) {
227 continue;
228 }
229
230 // If the field is not valid, add the error message to the result array.
231 // Example: $not_valid_fields[ 'srfm-email-c867d9d9-lbl-email' ] = 'This field is required.'.
232 if ( false === $field_validated['validated'] ) {
233 $not_valid_fields[ $key ] = $field_validated['error'] ?? __( 'Field is not valid.', 'sureforms' );
234 }
235 }
236 }
237
238 // Return the array of invalid fields and their error messages.
239 // Example: [ 'srfm-email-c867d9d9-lbl-email' => 'This field is required.' ].
240 return $not_valid_fields;
241 }
242 }
243