PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 6.32
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v6.32
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
← All changes | classes/models/FrmFieldFormHtml.php +197 -49 6.36.32 View file →
@@ -5,13 +5,18 @@
5 5
6 6 /**
7 7 * @since 3.0
8 8 */
9 -
10 9 class FrmFieldFormHtml {
11 10
11 + /**
12 + * @var string
13 + */
12 14 private $html;
13 15
16 + /**
17 + * @var string
18 + */
14 19 private $html_id;
15 20
16 21 /**
17 22 * @var FrmFieldType
@@ -17,12 +22,21 @@
17 22 * @var FrmFieldType
18 23 */
19 24 private $field_obj;
20 25
26 + /**
27 + * @var int|string
28 + */
21 29 private $field_id;
22 30
31 + /**
32 + * @var array|object
33 + */
23 34 private $form = array();
24 35
36 + /**
37 + * @var array
38 + */
25 39 private $pass_args = array();
26 40
27 41 /**
28 42 * @since 3.0
@@ -41,9 +55,11 @@
41 55 /**
42 56 * @since 3.0
43 57 *
44 58 * @param string $param
45 - * @param array $atts
59 + * @param array $atts
60 + *
61 + * @return void
46 62 */
47 63 private function _set( $param, $atts ) {
48 64 if ( isset( $atts[ $param ] ) ) {
49 65 $this->{$param} = $atts[ $param ];
@@ -53,8 +69,10 @@
53 69 /**
54 70 * @since 3.0
55 71 *
56 72 * @param array $atts
73 + *
74 + * @return void
57 75 */
58 76 private function set_html( $atts ) {
59 77 $this->set_from_field(
60 78 $atts,
@@ -68,8 +86,10 @@
68 86 /**
69 87 * @since 3.0
70 88 *
71 89 * @param array $atts
90 + *
91 + * @return void
72 92 */
73 93 private function set_field_id( $atts ) {
74 94 $this->set_from_field(
75 95 $atts,
@@ -83,13 +103,16 @@
83 103 /**
84 104 * @since 3.0
85 105 *
86 106 * @param array $atts
107 + *
108 + * @return void
87 109 */
88 110 private function set_pass_args( $atts ) {
89 111 $this->pass_args = $atts;
90 112
91 113 $exclude = array( 'field_obj', 'html' );
114 +
92 115 foreach ( $exclude as $ex ) {
93 116 if ( isset( $atts[ $ex ] ) ) {
94 117 unset( $this->pass_args[ $ex ] );
95 118 }
@@ -100,8 +123,10 @@
100 123 * @since 3.0
101 124 *
102 125 * @param array $atts
103 126 * @param array $set
127 + *
128 + * @return void
104 129 */
105 130 private function set_from_field( $atts, $set ) {
106 131 if ( isset( $atts[ $set['param'] ] ) ) {
107 132 $this->{$set['param']} = $atts[ $set['param'] ];
@@ -109,8 +134,11 @@
109 134 $this->{$set['param']} = $this->field_obj->get_field_column( $set['default'] );
110 135 }
111 136 }
112 137
138 + /**
139 + * @return string
140 + */
113 141 public function get_html() {
114 142 $this->replace_shortcodes_before_input();
115 143 $this->replace_shortcodes_with_atts();
116 144 $this->replace_shortcodes_after_input();
@@ -119,8 +147,10 @@
119 147 }
120 148
121 149 /**
122 150 * @since 3.0
151 + *
152 + * @return void
123 153 */
124 154 private function replace_shortcodes_before_input() {
125 155 $this->html = apply_filters( 'frm_before_replace_shortcodes', $this->html, $this->field_obj->get_field(), $this->pass_args['errors'], $this->form );
126 156
@@ -136,29 +166,35 @@
136 166 $this->replace_entry_key();
137 167 $this->replace_form_shortcodes();
138 168 $this->process_wp_shortcodes();
139 169 $this->maybe_replace_description_shortcode( true );
170 +
171 + $this->add_multiple_input_attributes();
140 172 }
141 173
142 174 /**
143 175 * @since 3.0
176 + *
177 + * @return void
144 178 */
145 179 private function replace_field_values() {
146 - //replace [id]
180 + // Replace [id].
147 181 $this->html = str_replace( '[id]', $this->field_id, $this->html );
148 182
149 - // set the label for
183 + // Set the label for
150 184 $this->html = str_replace( 'field_[key]', $this->html_id, $this->html );
151 185
152 - //replace [key]
186 + // Replace [key].
153 187 $this->html = str_replace( '[key]', $this->field_obj->get_field_column( 'field_key' ), $this->html );
154 188
155 - //replace [field_name]
189 + // Replace [field_name].
156 190 $this->html = str_replace( '[field_name]', FrmAppHelper::maybe_kses( $this->field_obj->get_field_column( 'name' ) ), $this->html );
157 191 }
158 192
159 193 /**
160 194 * @since 3.0
195 + *
196 + * @return void
161 197 */
162 198 private function replace_required_label_shortcode() {
163 199 $required = FrmField::is_required( $this->field_obj->get_field() ) ? $this->field_obj->get_field_column( 'required_indicator' ) : '';
164 200 FrmShortcodeHelper::remove_inline_conditions( ! empty( $required ), 'required_label', $required, $this->html );
@@ -168,12 +204,17 @@
168 204 * If this is an HTML field, the values are included in the description.
169 205 * In this case, we don't want to run the wp shortcodes with the description included.
170 206 *
171 207 * @since 3.0
208 + *
209 + * @param bool $wp_processed
210 + *
211 + * @return void
172 212 */
173 213 private function maybe_replace_description_shortcode( $wp_processed = false ) {
174 214 $is_html = 'html' === $this->field_obj->get_field_column( 'type' );
175 - $should_replace = ( $is_html && $wp_processed ) || ( ! $is_html && ! $wp_processed );
215 + $should_replace = $is_html ? $wp_processed : ! $wp_processed;
216 +
176 217 if ( $should_replace ) {
177 218 $this->replace_description_shortcode();
178 219 }
179 220 }
@@ -179,13 +220,16 @@
179 220 }
180 221
181 222 /**
182 223 * @since 3.0
224 + *
225 + * @return void
183 226 */
184 227 private function replace_description_shortcode() {
185 228 $this->maybe_add_description_id();
186 229 $description = FrmAppHelper::maybe_kses( $this->field_obj->get_field_column( 'description' ) );
187 - FrmShortcodeHelper::remove_inline_conditions( ( $description && $description != '' ), 'description', $description, $this->html );
230 + // phpcs:ignore Universal.Operators.StrictComparisons
231 + FrmShortcodeHelper::remove_inline_conditions( $description && $description != '', 'description', $description, $this->html );
188 232 }
189 233
190 234 /**
191 235 * Add an ID to the description for aria-describedby.
@@ -191,11 +235,15 @@
191 235 * Add an ID to the description for aria-describedby.
192 236 * This ID was added to the HTML in v3.0.
193 237 *
194 238 * @since 3.0
239 + *
240 + * @return void
195 241 */
196 242 private function maybe_add_description_id() {
197 243 $description = $this->field_obj->get_field_column( 'description' );
244 +
245 + // phpcs:ignore Universal.Operators.StrictComparisons
198 246 if ( $description != '' ) {
199 247 $this->add_element_id( 'description', 'desc' );
200 248 }
201 249 }
@@ -203,11 +251,17 @@
203 251 /**
204 252 * Insert an ID if it doesn't exist.
205 253 *
206 254 * @since 3.06.02
255 + *
256 + * @param string $param
257 + * @param string $id
258 + *
259 + * @return void
207 260 */
208 261 private function add_element_id( $param, $id ) {
209 262 preg_match_all( '/(\[if\s+' . $param . '\])(.*?)(\[\/if\s+' . $param . '\])/mis', $this->html, $inner_html );
263 +
210 264 if ( ! isset( $inner_html[2] ) ) {
211 265 return;
212 266 }
213 267
@@ -214,33 +268,51 @@
214 268 if ( ! is_string( $inner_html[2] ) && count( $inner_html[2] ) === 1 ) {
215 269 $inner_html[2] = $inner_html[2][0];
216 270 }
217 271
218 - if ( is_string( $inner_html[2] ) ) {
219 - $has_id = strpos( $inner_html[2], ' id=' );
220 - if ( ! $has_id ) {
221 - $id = 'frm_' . $id . '_' . $this->html_id;
222 - $this->html = str_replace( 'class="frm_' . $param, 'id="' . esc_attr( $id ) . '" class="frm_' . esc_attr( $param ), $this->html );
223 - }
272 + if ( ! is_string( $inner_html[2] ) ) {
273 + return;
224 274 }
275 +
276 + $has_id = str_contains( $inner_html[2], ' id=' );
277 +
278 + if ( $has_id ) {
279 + return;
280 + }
281 +
282 + $id = 'frm_' . $id . '_' . $this->html_id;
283 + $this->html = str_replace( 'class="frm_' . $param, 'id="' . esc_attr( $id ) . '" class="frm_' . esc_attr( $param ), $this->html );
225 284 }
226 285
227 286 /**
228 287 * @since 3.0
288 + *
289 + * @return void
229 290 */
230 291 private function replace_error_shortcode() {
231 292 $this->maybe_add_error_id();
232 - $error = isset( $this->pass_args['errors'][ 'field' . $this->field_id ] ) ? $this->pass_args['errors'][ 'field' . $this->field_id ] : false;
293 + $error = $this->pass_args['errors'][ 'field' . $this->field_id ] ?? false;
233 294
234 - if ( ! empty( $error ) && false === strpos( $this->html, 'role="alert"' ) && FrmAppHelper::should_include_alert_role_on_field_errors() ) {
295 + if ( ! $error ) {
296 + FrmShortcodeHelper::remove_inline_conditions( false, 'error', $error, $this->html );
297 + return;
298 + }
299 +
300 + $include_alert_role_on_field_errors = FrmAppHelper::should_include_alert_role_on_field_errors();
301 + $has_alert_role = str_contains( $this->html, 'role="alert"' );
302 +
303 + if ( ! $has_alert_role && $include_alert_role_on_field_errors ) {
235 304 $error_body = self::get_error_body( $this->html );
236 - if ( is_string( $error_body ) && false === strpos( $error_body, 'role=' ) ) {
305 +
306 + if ( is_string( $error_body ) && ! str_contains( $error_body, 'role=' ) ) {
237 307 $new_error_body = preg_replace( '/class="frm_error/', 'role="alert" class="frm_error', $error_body, 1 );
238 308 $this->html = str_replace( '[if error]' . $error_body . '[/if error]', '[if error]' . $new_error_body . '[/if error]', $this->html );
239 309 }
310 + } elseif ( ! $include_alert_role_on_field_errors && $has_alert_role ) {
311 + $this->html = str_replace( 'role="alert"', '', $this->html );
240 312 }
241 313
242 - FrmShortcodeHelper::remove_inline_conditions( ! empty( $error ), 'error', $error, $this->html );
314 + FrmShortcodeHelper::remove_inline_conditions( true, 'error', $error, $this->html );
243 315 }
244 316
245 317 /**
246 318 * Pull the HTML between [if error] and [/if error] shortcodes.
@@ -245,23 +317,25 @@
245 317 /**
246 318 * Pull the HTML between [if error] and [/if error] shortcodes.
247 319 *
248 320 * @param string $html
249 - * @return string|false
321 + *
322 + * @return false|string
250 323 */
251 324 private static function get_error_body( $html ) {
252 325 $start = strpos( $html, '[if error]' );
326 +
253 327 if ( false === $start ) {
254 328 return false;
255 329 }
256 330
257 331 $end = strpos( $html, '[/if error]', $start );
332 +
258 333 if ( false === $end ) {
259 334 return false;
260 335 }
261 336
262 - $error_body = substr( $html, $start + 10, $end - $start - 10 );
263 - return $error_body;
337 + return substr( $html, $start + 10, $end - $start - 10 );
264 338 }
265 339
266 340 /**
267 341 * Add an ID to the error message for aria-describedby.
@@ -267,8 +341,10 @@
267 341 * Add an ID to the error message for aria-describedby.
268 342 * This ID was added to the HTML in v3.06.02.
269 343 *
270 344 * @since 3.06.02
345 + *
346 + * @return void
271 347 */
272 348 private function maybe_add_error_id() {
273 349 if ( ! isset( $this->pass_args['errors'][ 'field' . $this->field_id ] ) ) {
274 350 return;
@@ -280,8 +356,10 @@
280 356 /**
281 357 * Replace [required_class]
282 358 *
283 359 * @since 3.0
360 + *
361 + * @return void
284 362 */
285 363 private function replace_required_class() {
286 364 $required_class = FrmField::is_required( $this->field_obj->get_field() ) ? ' frm_required_field' : '';
287 365 $this->html = str_replace( '[required_class]', $required_class, $this->html );
@@ -288,29 +366,35 @@
288 366 }
289 367
290 368 /**
291 369 * @since 3.0
370 + *
371 + * @return void
292 372 */
293 373 private function replace_form_shortcodes() {
294 - if ( ! empty( $this->form ) ) {
295 - $form = (array) $this->form;
374 + if ( ! $this->form ) {
375 + return;
376 + }
296 377
297 - //replace [form_key]
298 - $this->html = str_replace( '[form_key]', $form['form_key'], $this->html );
378 + $form = (array) $this->form;
299 379
300 - //replace [form_name]
301 - $this->html = str_replace( '[form_name]', $form['name'], $this->html );
302 - }
380 + // Replace [form_key].
381 + $this->html = str_replace( '[form_key]', $form['form_key'], $this->html );
382 +
383 + // Replace [form_name].
384 + $this->html = str_replace( '[form_name]', $form['name'], $this->html );
303 385 }
304 386
305 387 /**
306 388 * @since 3.0
389 + *
390 + * @return void
307 391 */
308 392 public function replace_shortcodes_after_input() {
309 393 $this->html .= "\n";
310 394
311 395 // Stop html filtering on confirmation field to prevent loop
312 - if ( $this->field_obj->get_field_column( 'conf_field' ) != 'stop' ) {
396 + if ( $this->field_obj->get_field_column( 'conf_field' ) !== 'stop' ) {
313 397 $this->filter_for_more_shortcodes();
314 398 }
315 399 }
316 400
@@ -315,13 +399,15 @@
315 399 }
316 400
317 401 /**
318 402 * @since 3.0
403 + *
404 + * @return void
319 405 */
320 406 private function filter_for_more_shortcodes() {
321 407 $atts = $this->pass_args;
322 408
323 - //If field is not in repeating section
409 + // If field is not in repeating section.
324 410 if ( empty( $atts['section_id'] ) ) {
325 411 $atts = array(
326 412 'errors' => $this->pass_args['errors'],
327 413 'form' => $this->form,
@@ -335,11 +421,13 @@
335 421 *
336 422 * @since 3.0
337 423 *
338 424 * @param string $html
425 + *
426 + * @return void
339 427 */
340 428 public function remove_collapse_shortcode( &$html ) {
341 - if ( strpos( $html, '[collapse_this]' ) ) {
429 + if ( str_contains( $html, '[collapse_this]' ) ) {
342 430 $html = str_replace( '[collapse_this]', '', $html );
343 431 }
344 432 }
345 433
@@ -344,8 +432,10 @@
344 432 }
345 433
346 434 /**
347 435 * @since 3.0
436 + *
437 + * @return void
348 438 */
349 439 private function replace_shortcodes_with_atts() {
350 440 preg_match_all( "/\[(input|deletelink)\b(.*?)(?:(\/))?\]/s", $this->html, $shortcodes, PREG_PATTERN_ORDER );
351 441
@@ -351,14 +441,13 @@
351 441
352 442 foreach ( $shortcodes[0] as $short_key => $tag ) {
353 443 $shortcode_atts = FrmShortcodeHelper::get_shortcode_attribute_array( $shortcodes[2][ $short_key ] );
354 444 $tag = FrmShortcodeHelper::get_shortcode_tag( $shortcodes, $short_key );
445 + $replace_with = '';
355 446
356 - $replace_with = '';
357 -
358 - if ( $tag == 'deletelink' && FrmAppHelper::pro_is_installed() ) {
447 + if ( $tag === 'deletelink' && FrmAppHelper::pro_is_installed() ) {
359 448 $replace_with = FrmProEntriesController::entry_delete_link( $shortcode_atts );
360 - } elseif ( $tag == 'input' ) {
449 + } elseif ( $tag === 'input' ) {
361 450 $replace_with = $this->replace_input_shortcode( $shortcode_atts );
362 451 }
363 452
364 453 $this->html = str_replace( $shortcodes[0][ $short_key ], $replace_with, $this->html );
@@ -371,9 +460,8 @@
371 460 * @return string
372 461 */
373 462 private function replace_input_shortcode( $shortcode_atts ) {
374 463 $shortcode_atts = $this->prepare_input_shortcode_atts( $shortcode_atts );
375 -
376 464 return $this->field_obj->include_front_field_input( $this->pass_args, $shortcode_atts );
377 465 }
378 466
379 467 /**
@@ -382,12 +470,12 @@
382 470 * @return array
383 471 */
384 472 private function prepare_input_shortcode_atts( $shortcode_atts ) {
385 473 if ( isset( $shortcode_atts['opt'] ) ) {
386 - $shortcode_atts['opt'] --;
474 + --$shortcode_atts['opt'];
387 475 }
388 476
389 - $field_class = isset( $shortcode_atts['class'] ) ? $shortcode_atts['class'] : '';
477 + $field_class = $shortcode_atts['class'] ?? '';
390 478 $this->field_obj->set_field_column( 'input_class', $field_class );
391 479
392 480 if ( isset( $shortcode_atts['class'] ) ) {
393 481 unset( $shortcode_atts['class'] );
@@ -392,9 +480,9 @@
392 480 if ( isset( $shortcode_atts['class'] ) ) {
393 481 unset( $shortcode_atts['class'] );
394 482 }
395 483
396 - $shortcode_atts['aria-invalid'] = isset( $this->pass_args['errors'][ 'field' . $this->field_id ] ) ? 'true' : 'false';
484 + $this->field_obj->set_aria_invalid_error( $shortcode_atts, $this->pass_args );
397 485
398 486 $this->field_obj->set_field_column( 'shortcodes', $shortcode_atts );
399 487
400 488 return $shortcode_atts;
@@ -404,8 +492,10 @@
404 492 * Add the label position class into the HTML
405 493 * If the label position is inside, add a class to show the label if the field has a value.
406 494 *
407 495 * @since 3.0
496 + *
497 + * @return void
408 498 */
409 499 private function add_class_to_label() {
410 500 $label_class = $this->field_obj->get_label_class();
411 501 $this->html = str_replace( '[label_position]', $label_class, $this->html );
@@ -414,8 +504,10 @@
414 504 /**
415 505 * Replace [entry_key]
416 506 *
417 507 * @since 3.0
508 + *
509 + * @return void
418 510 */
419 511 private function replace_entry_key() {
420 512 $entry_key = FrmAppHelper::simple_get( 'entry', 'sanitize_title' );
421 513 $this->html = str_replace( '[entry_key]', $entry_key, $this->html );
@@ -424,17 +516,21 @@
424 516 /**
425 517 * Add classes to a field div
426 518 *
427 519 * @since 3.0
520 + *
521 + * @return void
428 522 */
429 523 private function add_field_div_classes() {
430 524 $classes = $this->get_field_div_classes();
431 525
432 - if ( $this->field_obj->get_field_column( 'type' ) == 'html' && strpos( $this->html, '[error_class]' ) === false ) {
433 - // there is no error_class shortcode for HTML fields
434 - $this->html = str_replace( 'class="frm_form_field', 'class="frm_form_field ' . $classes, $this->html );
526 + if ( in_array( $this->field_obj->get_field_column( 'type' ), array( 'html', 'summary' ), true ) && ! str_contains( $this->html, '[error_class]' ) ) {
527 + // There is no error_class shortcode for HTML fields
528 + $this->html = str_replace( 'class="frm_form_field', 'class="frm_form_field ' . esc_attr( $classes ), $this->html );
529 + return;
435 530 }
436 - $this->html = str_replace( '[error_class]', $classes, $this->html );
531 +
532 + $this->html = str_replace( '[error_class]', esc_attr( $classes ), $this->html );
437 533 }
438 534
439 535 /**
440 536 * Get the classes for a field div
@@ -440,9 +536,9 @@
440 536 * Get the classes for a field div
441 537 *
442 538 * @since 3.0
443 539 *
444 - * @return string $classes
540 + * @return string Classes.
445 541 */
446 542 private function get_field_div_classes() {
447 543 // Add error class
448 544 $classes = isset( $this->pass_args['errors'][ 'field' . $this->field_id ] ) ? ' frm_blank_field' : '';
@@ -448,11 +544,12 @@
448 544 $classes = isset( $this->pass_args['errors'][ 'field' . $this->field_id ] ) ? ' frm_blank_field' : '';
449 545
450 546 // Add label position class
451 547 $settings = $this->field_obj->display_field_settings();
452 - if ( isset( $settings['label_position'] ) && $settings['label_position'] ) {
548 +
549 + if ( ! empty( $settings['label_position'] ) ) {
453 550 $label_position = $this->field_obj->get_field_column( 'label' );
454 - $classes .= ' frm_' . $label_position . '_container';
551 + $classes .= ' frm_' . $label_position . '_container';
455 552
456 553 // Add class if field has value, to be used for floating label styling.
457 554 if ( 'inside' === $label_position && $this->field_obj->get_field_column( 'value' ) ) {
458 555 $classes .= ' frm_label_float_top';
@@ -460,12 +557,14 @@
460 557 }
461 558
462 559 // Add CSS layout classes
463 560 $extra_classes = $this->field_obj->get_field_column( 'classes' );
464 - if ( ! empty( $extra_classes ) ) {
465 - if ( ! strpos( $this->html, 'frm_form_field ' ) ) {
561 +
562 + if ( $extra_classes ) {
563 + if ( ! str_contains( $this->html, 'frm_form_field ' ) ) {
466 564 $classes .= ' frm_form_field';
467 565 }
566 +
468 567 $classes .= ' ' . $extra_classes;
469 568 }
470 569
471 570 $classes .= $this->field_obj->get_container_class();
@@ -470,9 +569,12 @@
470 569
471 570 $classes .= $this->field_obj->get_container_class();
472 571
473 572 // Get additional classes
474 - return apply_filters( 'frm_field_div_classes', $classes, $this->field_obj->get_field(), array( 'field_id' => $this->field_id ) );
573 + $classes = apply_filters( 'frm_field_div_classes', $classes, $this->field_obj->get_field(), array( 'field_id' => $this->field_id ) );
574 +
575 + // Remove unexpected characters from class.
576 + return implode( ' ', array_map( 'FrmFormsHelper::sanitize_layout_class', explode( ' ', $classes ) ) );
475 577 }
476 578
477 579 /**
478 580 * This filters shortcodes in the field HTML
@@ -477,11 +579,57 @@
477 579 /**
478 580 * This filters shortcodes in the field HTML
479 581 *
480 582 * @since 3.0
583 + *
584 + * @return void
481 585 */
482 586 private function process_wp_shortcodes() {
483 587 if ( apply_filters( 'frm_do_html_shortcodes', true ) ) {
484 588 $this->html = do_shortcode( $this->html );
485 589 }
590 + }
591 +
592 + /**
593 + * Adds multiple input attributes.
594 + *
595 + * @since 6.4.1
596 + *
597 + * @return void
598 + */
599 + private function add_multiple_input_attributes() {
600 + $field_type = $this->field_obj->get_field_column( 'type' );
601 +
602 + // Check if the field type is one of the following.
603 + if ( ! in_array( $field_type, array( 'radio', 'checkbox', 'data', 'product', 'scale' ), true ) ) {
604 + return;
605 + }
606 +
607 + $field = (array) $this->field_obj->get_field();
608 + $attributes = array();
609 +
610 + // Check if the field type is 'data' or 'product'.
611 + if ( in_array( $field_type, array( 'data', 'product' ), true ) ) {
612 + $data_type = FrmField::get_option( $field, 'data_type' );
613 + $is_radio = 'radio' === $data_type;
614 + } else {
615 + $is_radio = 'radio' === $field_type || 'scale' === $field_type;
616 + }
617 +
618 + // Add 'role' attribute to the field.
619 + $attributes['role'] = $is_radio ? 'radiogroup' : 'group';
620 +
621 + // Add 'aria-required' attribute to the field if required.
622 + if ( $is_radio && '1' === $field['required'] ) {
623 + $attributes['aria-required'] = 'true';
624 + }
625 +
626 + // Add 'aria-invalid' attribute to the group if there are errors.
627 + if ( isset( $this->pass_args['errors'][ 'field' . $this->field_id ] ) ) {
628 + $attributes['aria-invalid'] = 'true';
629 + }
630 +
631 + // Concatenate attributes into a string, and replace the role="group" in the HTML with the attributes string.
632 + $html_attributes = FrmAppHelper::array_to_html_params( $attributes );
633 + $this->html = str_replace( ' role="group"', $html_attributes, $this->html );
486 634 }
487 635 }