PluginProbe
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder / 6.2.15
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder v6.2.15
6.2.15 6.2.14 6.2.13 6.2.12 6.2.10 6.2.11 6.2.9 6.2.8 6.2.7 6.2.6 6.2.5 6.2.4 6.2.3 6.2.2 3.6.22 3.6.31 3.6.40 3.6.41 3.6.42 3.6.50 3.6.51 3.6.60 3.6.61 3.6.62 3.6.64 All 197 releases
← All changes | app/Services/FormBuilder/FormBuilder.php +339 -84 3.6.51 → 6.2.15 View file →
@@ -8,9 +8,10 @@
8 8 class FormBuilder
9 9 {
10 10 /**
11 11 * The Applivcation instance
12 - * @var Framework\Foundation\Application
12 + *
13 + * @var \FluentForm\Framework\Foundation\Application
13 14 */
14 15 protected $app = null;
15 16
16 17 protected $form = null;
@@ -16,17 +17,19 @@
16 17 protected $form = null;
17 18
18 19 /**
19 20 * Conditional logic for elements
21 + *
20 22 * @var array
21 23 */
22 - public $conditions = array();
24 + public $conditions = [];
23 25
24 26 /**
25 27 * Validation rules for elements
28 + *
26 29 * @var array
27 30 */
28 - public $validationRules = array();
31 + public $validationRules = [];
29 32
30 33 public $tabIndex = 1;
31 34
32 35 public $fieldLists = [];
@@ -34,9 +37,10 @@
34 37 public $containerCounter;
35 38
36 39 /**
37 40 * Construct the form builder instance
38 - * @param Framework\Foundation\Application $app
41 + *
42 + * @param \FluentForm\Framework\Foundation\Application $app
39 43 */
40 44 public function __construct($app)
41 45 {
42 46 $this->app = $app;
@@ -44,21 +48,25 @@
44 48 }
45 49
46 50 /**
47 51 * Render the form
48 - * @param \StdClass $form [Form entry from database]
52 + *
53 + * @param \StdClass $form [Form entry from database]
54 + *
49 55 * @return mixed
50 56 */
51 - public function build($form, $extraCssClass = '', $instanceCssClass = '')
57 + public function build($form, $extraCssClass = '', $instanceCssClass = '', $atts = [])
52 58 {
53 59 $this->form = $form;
54 60 $hasStepWrapper = isset($form->fields['stepsWrapper']) && $form->fields['stepsWrapper'];
55 -
56 - $labelPlacement = $form->settings['layout']['labelPlacement'];
57 61
62 + $labelPlacement = ArrayHelper::get($form->settings, 'layout.labelPlacement', 'top');
63 +
58 64 $formClass = "frm-fluent-form fluent_form_{$form->id} ff-el-form-{$labelPlacement}";
59 65
60 - if ($extraCssClass) $formClass .= " {$extraCssClass}";
66 + if ($extraCssClass) {
67 + $formClass .= " {$extraCssClass}";
68 + }
61 69
62 70 if ($hasStepWrapper) {
63 71 $formClass .= ' ff-form-has-steps';
64 72 }
@@ -66,37 +74,123 @@
66 74 if ($extraFormClass = Helper::formExtraCssClass($form)) {
67 75 $formClass .= ' ' . $extraFormClass;
68 76 }
69 77
78 + $themeStyle = ArrayHelper::get($atts, 'theme');
79 +
80 + if (!$themeStyle) {
81 + $selectedStyle = Helper::getFormMeta($form->id, '_ff_selected_style');
82 +
83 + $selectedStyle = $selectedStyle ? $selectedStyle : 'ffs_default';
84 +
85 + $themeStyle = $selectedStyle;
86 +
87 + $atts['theme'] = $selectedStyle;
88 + }
89 +
90 + $form->theme = $themeStyle;
91 +
70 92 $formBody = $this->buildFormBody($form);
71 93
72 - $formClass = apply_filters('fluentform_form_class', $formClass, $form);
94 + if (strpos($formBody, '{dynamic.')) {
95 + $formClass .= ' ff_has_dynamic_smartcode';
96 + wp_enqueue_script('fluentform-advanced');
97 + }
98 +
99 + $formClass = apply_filters_deprecated(
100 + 'fluentform_form_class',
101 + [
102 + $formClass,
103 + $form
104 + ],
105 + FLUENTFORM_FRAMEWORK_UPGRADE,
106 + 'fluentform/form_class',
107 + 'Use fluentform/form_class instead of fluentform_form_class.'
108 + );
73 109
110 + $formClass = apply_filters('fluentform/form_class', $formClass, $form);
111 +
74 112 if ($form->has_payment) {
75 113 $formClass .= ' fluentform_has_payment';
76 114 }
77 115
78 - $formAttributes = apply_filters('fluent_form_html_attributes', [
79 - 'data-form_id' => $form->id,
80 - 'id' => 'fluentform_'.$form->id,
81 - 'class' => $formClass,
82 - 'data-form_instance' => $instanceCssClass
83 - ], $form);
116 + if ($themeStyle) {
117 + $formClass .= ' ' . $themeStyle;
118 + }
84 119
120 + $data = [
121 + 'data-form_id' => $form->id,
122 + 'id' => 'fluentform_' . $form->id,
123 + 'class' => $formClass,
124 + 'data-form_instance' => $instanceCssClass,
125 + 'method' => 'POST',
126 + ];
127 +
128 + $data = apply_filters_deprecated(
129 + 'fluent_form_html_attributes',
130 + [
131 + $data,
132 + $form
133 + ],
134 + FLUENTFORM_FRAMEWORK_UPGRADE,
135 + 'fluentform/html_attributes',
136 + 'Use fluentform/html_attributes instead of fluent_form_html_attributes.'
137 + );
138 +
139 + $formAttributes = apply_filters('fluentform/html_attributes', $data, $form);
140 +
85 141 $formAtts = $this->buildAttributes($formAttributes);
142 +
86 143
144 + $wrapperClasses = trim('fluentform ff-default fluentform_wrapper_' . $form->id . ' ' . ArrayHelper::get($atts, 'css_classes'));
145 +
146 + if ($themeStyle === 'ffs_inherit_theme') {
147 + $wrapperClasses = str_replace("ff-default", "ff-inherit-theme-style", $wrapperClasses);
148 + } else if ($themeStyle) {
149 + $wrapperClasses .= ' ' . $themeStyle . '_wrap';
150 + }
151 +
152 + $wrapperClasses = apply_filters('fluentform/form_wrapper_classes', $wrapperClasses, $form);
87 153 ob_start();
154 +
155 + echo "<div class='" . esc_attr($wrapperClasses) . "'>";
156 +
157 + do_action_deprecated(
158 + 'fluentform_before_form_render',
159 + [
160 + $form
161 + ],
162 + FLUENTFORM_FRAMEWORK_UPGRADE,
163 + 'fluentform/before_form_render',
164 + 'Use fluentform/before_form_render instead of fluentform_before_form_render.'
165 + );
88 166
89 - echo "<div class='fluentform fluentform_wrapper_".$form->id."'>";
167 + do_action('fluentform/before_form_render', $form, $atts);
168 + echo '<form ' . $formAtts . '>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- $formAtts is escaped before being passed in.
169 +
170 + $isAccessible = apply_filters_deprecated(
171 + 'fluentform_disable_accessibility_fieldset',
172 + [
173 + true,
174 + $form
175 + ],
176 + FLUENTFORM_FRAMEWORK_UPGRADE,
177 + 'fluentform/disable_accessibility_fieldset',
178 + 'Use fluentform/disable_accessibility_fieldset instead of fluentform_disable_accessibility_fieldset.'
179 + );
180 + $isAccessible = apply_filters('fluentform/disable_accessibility_fieldset', true, $form);
181 +
182 + if ($isAccessible) {
183 + echo $this->fieldsetHtml($form); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- $form is escaped before being passed in.
184 + }
90 185
91 - do_action('fluentform_before_form_render', $form);
92 -
93 - echo "<form ".$formAtts.">";
94 -
186 + /* This hook is deprecated & will be removed soon */
95 187 do_action('fluentform_form_element_start', $form);
96 188
97 - echo "<input type='hidden' name='__fluent_form_embded_post_id' value='" . get_the_ID() . "' />";
98 -
189 + do_action('fluentform/form_element_start', $form);
190 +
191 + echo "<input type='hidden' name='__fluent_form_embded_post_id' value='" . esc_attr(get_the_ID()) . "' />";
192 +
99 193 wp_nonce_field(
100 194 'fluentform-submit-form',
101 195 '_fluentform_' . $form->id . '_fluentformnonce',
102 196 true,
@@ -101,40 +195,77 @@
101 195 '_fluentform_' . $form->id . '_fluentformnonce',
102 196 true,
103 197 true
104 198 );
105 -
106 - echo $formBody;
107 -
108 - echo "</form><div id='fluentform_" . $form->id . "_errors' class='ff-errors-in-stack ";
109 199
110 - echo $extraCssClass . "_errors " . $instanceCssClass . "_errors'></div></div>";
111 -
112 - do_action('fluentform_after_form_render', $form);
113 -
200 + echo $formBody; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- $formBody is escaped before being passed in.
201 +
202 + if ($isAccessible) {
203 + echo '</fieldset>';
204 + }
205 +
206 + echo "</form><div id='fluentform_" . (int) $form->id . "_errors' class='ff-errors-in-stack ";
207 +
208 + echo esc_attr($extraCssClass) . '_errors ' . esc_attr($instanceCssClass) . "_errors'></div></div>";
209 +
210 + do_action_deprecated(
211 + 'fluentform_after_form_render',
212 + [
213 + $form
214 + ],
215 + FLUENTFORM_FRAMEWORK_UPGRADE,
216 + 'fluentform/after_form_render',
217 + 'Use fluentform/after_form_render instead of fluentform_after_form_render.'
218 + );
219 + do_action('fluentform/after_form_render', $form);
220 +
114 221 return ob_get_clean();
115 222 }
116 223
117 -
224 + /**
225 + * @param \stdClass $form
226 + *
227 + * @return string form body
228 + */
118 229 public function buildFormBody($form)
119 230 {
120 231 $hasStepWrapper = isset($form->fields['stepsWrapper']) && $form->fields['stepsWrapper'];
121 -
232 +
122 233 ob_start();
123 -
234 +
124 235 $stepCounter = 1;
125 236
126 237 foreach ($form->fields['fields'] as $item) {
127 -
128 - if ($hasStepWrapper && $item['element'] == 'form_step') {
238 + if ($hasStepWrapper && 'form_step' == $item['element']) {
129 239 $stepCounter++;
130 240 }
131 241
132 242 $this->setUniqueIdentifier($item);
243 +
244 + $item = apply_filters_deprecated(
245 + 'fluentform_before_render_item',
246 + [
247 + $item,
248 + $form
249 + ],
250 + FLUENTFORM_FRAMEWORK_UPGRADE,
251 + 'fluentform/before_render_item',
252 + 'Use fluentform/before_render_item instead of fluentform_before_render_item.'
253 + );
254 + $item = apply_filters('fluentform/before_render_item', $item, $form);
133 255
134 - $item = apply_filters('fluentform_before_render_item', $item, $form);
256 + do_action_deprecated(
257 + 'fluentform_render_item_' . $item['element'],
258 + [
259 + $item,
260 + $form
261 + ],
262 + FLUENTFORM_FRAMEWORK_UPGRADE,
263 + 'fluentform/render_item_' . $item['element'],
264 + 'Use fluentform/render_item_' . $item['element'] . ' instead of fluentform_render_item_' . $item['element']
265 + );
135 266
136 - do_action('fluentform_render_item_' . $item['element'], $item, $form);
267 + do_action('fluentform/render_item_' . $item['element'], $item, $form);
137 268
138 269 $this->extractValidationRules($item);
139 270
140 271 $this->extractConditionalLogic($item);
@@ -140,11 +271,31 @@
140 271 $this->extractConditionalLogic($item);
141 272 }
142 273
143 274 if ($hasStepWrapper) {
144 - do_action('fluentform_render_item_step_end', $form->fields['stepsWrapper']['stepEnd'], $form);
275 + do_action_deprecated(
276 + 'fluentform_render_item_step_end',
277 + [
278 + $form->fields['stepsWrapper']['stepEnd'],
279 + $form
280 + ],
281 + FLUENTFORM_FRAMEWORK_UPGRADE,
282 + 'fluentform/render_item_step_end',
283 + 'Use fluentform/render_item_step_end instead of fluentform_render_item_step_end.'
284 + );
285 + do_action('fluentform/render_item_step_end', $form->fields['stepsWrapper']['stepEnd'], $form);
145 286 } else {
146 - do_action('fluentform_render_item_submit_button', $form->fields['submitButton'], $form);
287 + do_action_deprecated(
288 + 'fluentform_render_item_submit_button',
289 + [
290 + $form->fields['submitButton'],
291 + $form
292 + ],
293 + FLUENTFORM_FRAMEWORK_UPGRADE,
294 + 'fluentform/render_item_submit_button',
295 + 'Use fluentform/render_item_submit_button instead of fluentform_render_item_submit_button.'
296 + );
297 + do_action('fluentform/render_item_submit_button', $form->fields['submitButton'], $form);
147 298 }
148 299
149 300 $content = ob_get_clean();
150 301
@@ -149,11 +300,11 @@
149 300 $content = ob_get_clean();
150 301
151 302 if ($hasStepWrapper) {
152 303 $startElement = $form->fields['stepsWrapper']['stepStart'];
153 -
304 +
154 305 $steps = ArrayHelper::get($startElement, 'settings.step_titles');
155 -
306 +
156 307 // check if $stepCounter == count()
157 308 if ($stepCounter > count($steps)) {
158 309 $fillCount = $stepCounter - count($steps);
159 310 foreach (range(1, $fillCount) as $item) {
@@ -162,16 +313,26 @@
162 313 $startElement['settings']['step_titles'] = $steps;
163 314 }
164 315
165 316 $this->setUniqueIdentifier($startElement);
166 -
317 +
167 318 ob_start();
168 -
169 - do_action('fluentform_render_item_step_start', $startElement, $form);
170 -
319 +
320 + do_action_deprecated(
321 + 'fluentform_render_item_step_start',
322 + [
323 + $startElement,
324 + $form
325 + ],
326 + FLUENTFORM_FRAMEWORK_UPGRADE,
327 + 'fluentform/render_item_step_start',
328 + 'Use fluentform/render_item_step_start instead of fluentform_render_item_step_start.'
329 + );
330 + do_action('fluentform/render_item_step_start', $startElement, $form);
331 +
171 332 $stepStatrt = ob_get_clean();
172 -
173 - $content = $stepStatrt.$content;
333 +
334 + $content = $stepStatrt . $content;
174 335 }
175 336
176 337 return $content;
177 338 }
@@ -177,15 +338,17 @@
177 338 }
178 339
179 340 /**
180 341 * Set unique name/data-name for an element
342 + *
181 343 * @param array &$item
182 - * @return void
344 + *
345 + * @return void
183 346 */
184 347 protected function setUniqueIdentifier(&$item)
185 348 {
186 349 if (isset($item['columns'])) {
187 - $item['attributes']['data-name'] = 'ff_cn_id_'.$this->containerCounter;
350 + $item['attributes']['data-name'] = 'ff_cn_id_' . $this->containerCounter;
188 351 $this->containerCounter++;
189 352 foreach ($item['columns'] as &$column) {
190 353 foreach ($column['fields'] as &$field) {
191 354 $this->setUniqueIdentifier($field);
@@ -191,18 +354,18 @@
191 354 $this->setUniqueIdentifier($field);
192 355 }
193 356 }
194 357 } else {
195 - if (!isset($item['attributes']['name'])) {
196 - if($this->form) {
197 - if(empty($this->form->attr_name_index)) {
358 + if (! isset($item['attributes']['name'])) {
359 + if ($this->form) {
360 + if (empty($this->form->attr_name_index)) {
198 361 $this->form->attr_name_index = 1;
199 362 } else {
200 363 $this->form->attr_name_index += 1;
201 364 }
202 - $uniqueId = $this->form->id.'_'.$this->form->attr_name_index;
365 + $uniqueId = $this->form->id . '_' . $this->form->attr_name_index;
203 366 } else {
204 - $uniqueId = uniqid(rand(), true);
367 + $uniqueId = uniqid(wp_rand(), true);
205 368 }
206 369
207 370 $item['attributes']['name'] = $item['element'] . '-' . $uniqueId;
208 371 }
@@ -212,14 +375,16 @@
212 375 }
213 376
214 377 /**
215 378 * Recursively extract validation rules from a given element
379 + *
216 380 * @param array $item
381 + *
217 382 * @return void
218 383 */
219 384 protected function extractValidationRules($item)
220 385 {
221 - if (isset($item['columns'])) {
386 + if (isset($item['columns']) && 'repeater_container' !== $item['element']) {
222 387 foreach ($item['columns'] as $column) {
223 388 foreach ($column['fields'] as $field) {
224 389 $this->extractValidationRules($field);
225 390 }
@@ -226,14 +391,14 @@
226 391 }
227 392 } elseif (isset($item['fields'])) {
228 393 $rootName = $item['attributes']['name'];
229 394 foreach ($item['fields'] as $key => $innerItem) {
230 - if ($item['element'] == 'address' || $item['element'] == 'input_name') {
395 + if ('address' == $item['element'] || 'input_name' == $item['element']) {
231 396 $itemName = $innerItem['attributes']['name'];
232 397 $innerItem['attributes']['name'] = $rootName . '[' . $itemName . ']';
233 398 } else {
234 - if ($item['element'] == 'input_repeat' || $item['element'] == 'repeater_field') {
235 - if(!empty($innerItem['settings']['validation_rules']['email'])) {
399 + if ('input_repeat' == $item['element'] || 'repeater_field' == $item['element']) {
400 + if (empty($innerItem['settings']['validation_rules']['email'])) {
236 401 unset($innerItem['settings']['validation_rules']['email']);
237 402 }
238 403 $innerItem['attributes']['name'] = $rootName . '[' . $key . ']';
239 404 } else {
@@ -241,14 +406,15 @@
241 406 }
242 407 }
243 408 $this->extractValidationRule($innerItem);
244 409 }
245 - } elseif ($item['element'] == 'tabular_grid') {
410 + } elseif ('tabular_grid' == $item['element']) {
246 411 $gridName = $item['attributes']['name'];
247 412 $gridRows = $item['settings']['grid_rows'];
248 413 $gridType = $item['settings']['tabular_field_type'];
249 414 foreach ($gridRows as $rowKey => $rowValue) {
250 - if ($gridType == 'radio') {
415 + $rowKey = trim(sanitize_text_field($rowKey));
416 + if ('radio' == $gridType) {
251 417 $item['attributes']['name'] = $gridName . '[' . $rowKey . ']';
252 418 $this->extractValidationRule($item);
253 419 } else {
254 420 $item['attributes']['name'] = $gridName . '[' . $rowKey . ']';
@@ -254,14 +420,26 @@
254 420 $item['attributes']['name'] = $gridName . '[' . $rowKey . ']';
255 421 $this->extractValidationRule($item);
256 422 }
257 423 }
258 - } elseif ($item['element'] == 'chained_select') {
424 + } elseif ('chained_select' == $item['element']) {
259 425 $chainedSelectName = $item['attributes']['name'];
260 426 foreach ($item['settings']['data_source']['headers'] as $select) {
261 427 $item['attributes']['name'] = $chainedSelectName . '[' . $select . ']';
262 428 $this->extractValidationRule($item);
263 429 }
430 + } elseif ('repeater_container' == $item['element']) {
431 + $rootName = $item['attributes']['name'];
432 + $ruleIndex = 0;
433 + foreach ($item['columns'] as $key => $innerItem) {
434 + foreach ($innerItem['fields'] as &$innerField) {
435 + $innerField['attributes']['name'] = $rootName . '[' . $key . ']';
436 + $rules = ArrayHelper::get($innerField, 'settings.validation_rules', []);
437 + $innerField['settings']['validation_rules'] = $rules;
438 + $this->extractValidationRule($innerField, $rootName . '[' . $ruleIndex . ']');
439 + $ruleIndex++;
440 + }
441 + }
264 442 } else {
265 443 $this->extractValidationRule($item);
266 444 }
267 445 }
@@ -267,32 +445,77 @@
267 445 }
268 446
269 447 /**
270 448 * Extract validation rules from a given element
449 + *
271 450 * @param array $item
451 + *
272 452 * @return void
273 453 */
274 - protected function extractValidationRule($item)
454 + protected function extractValidationRule($item, $name = '')
275 455 {
276 456 if (isset($item['settings']['validation_rules'])) {
277 457 $rules = $item['settings']['validation_rules'];
278 458 foreach ($rules as $ruleName => $rule) {
279 - if(isset($rule['message'])) {
280 - $rules[$ruleName]['message'] = apply_filters('fluentform_validation_message_'.$ruleName, $rule['message'], $item);
281 - $rules[$ruleName]['message'] = apply_filters('fluentform_validation_message_'.$item['element'].'_'.$ruleName, $rule['message'], $item);
459 + if (isset($rule['message'])) {
460 + if (isset($rule['global']) && $rule['global']) {
461 + $rule['message'] = apply_filters('fluentform/get_global_message_' . $ruleName, $rule['message']);
462 + }
463 + // Shortcode parse on validation message
464 + $rule['message'] = Helper::shortCodeParseOnValidationMessage($rule['message'], $this->form, ArrayHelper::get($item, 'attributes.name'));
465 + $rules[$ruleName]['message'] = apply_filters_deprecated(
466 + 'fluentform_validation_message_' . $ruleName,
467 + [
468 + $rule['message'],
469 + $item
470 + ],
471 + FLUENTFORM_FRAMEWORK_UPGRADE,
472 + 'fluentform/validation_message_' . $ruleName,
473 + 'Use fluentform/validation_message_' . $ruleName . ' instead of fluentform_validation_message_' . $ruleName
474 + );
475 + $rules[$ruleName]['message'] = apply_filters('fluentform/validation_message_' . $ruleName, $rule['message'], $item);
476 +
477 + $rules[$ruleName]['message'] = apply_filters_deprecated(
478 + 'fluentform_validation_message_' . $item['element'] . '_' . $ruleName,
479 + [
480 + $rules[$ruleName]['message'],
481 + $item
482 + ],
483 + FLUENTFORM_FRAMEWORK_UPGRADE,
484 + 'fluentform/validation_message_' . $item['element'] . '_' . $ruleName,
485 + 'Use fluentform/validation_message_' . $item['element'] . '_' . $ruleName . ' instead of fluentform_validation_message_' . $item['element'] . '_' . $ruleName
486 + );
487 + $rules[$ruleName]['message'] = apply_filters('fluentform/validation_message_' . $item['element'] . '_' . $ruleName, $rules[$ruleName]['message'], $item);
282 488 }
283 489 }
284 - $rules = apply_filters('fluentform_item_rules_' . $item['element'], $rules, $item);
285 - $this->validationRules[ $item['attributes']['name'] ] = $rules;
490 +
491 + $rules = apply_filters_deprecated(
492 + 'fluentform_item_rules_' . $item['element'],
493 + [
494 + $rules,
495 + $item
496 + ],
497 + FLUENTFORM_FRAMEWORK_UPGRADE,
498 + 'fluentform/item_rules_' . $item['element'],
499 + 'Use fluentform/item_rules_' . $item['element'] . ' instead of fluentform_item_rules_' . $item['element']
500 + );
501 +
502 + $rules = apply_filters('fluentform/item_rules_' . $item['element'], $rules, $item);
503 + if (!$name) {
504 + $name = $item['attributes']['name'];
505 + }
506 + $this->validationRules[$name] = $rules;
286 507 }
287 508 }
288 509
289 510 /**
290 - * Extract conditipnal logic from a given element
511 + * Extract conditional logic from a given element
512 + *
291 513 * @param array $item
514 + *
292 515 * @return void
293 516 */
294 - protected function extractConditionalLogic($item)
517 + protected function extractConditionalLogic($item, $itemName = '')
295 518 {
296 519 // If container like element, then recurse
297 520 if (isset($item['columns'])) {
298 521 $containerConditions = false;
@@ -304,33 +527,43 @@
304 527 $this->conditions[$item['attributes']['data-name']] = $containerConditions;
305 528 }
306 529 }
307 530 }
531 + $parentName = ArrayHelper::get($item, 'attributes.name');
532 + $isRepeaterContainer = ArrayHelper::get($item, 'element') === 'repeater_container';
308 533
309 - foreach ($item['columns'] as $column) {
310 - foreach ($column['fields'] as $field) {
311 - if($containerConditions) {
534 + foreach ($item['columns'] as $colIndex => $column) {
535 + foreach ($column['fields'] as $fieldIndex => $field) {
536 + if ($containerConditions) {
312 537 $field['container_conditions'] = $containerConditions;
313 538 }
314 - $this->extractConditionalLogic($field);
539 + if ($isRepeaterContainer) {
540 + $conditionName = $parentName . '_condition_' . $colIndex . '_' . $fieldIndex;
541 + $this->extractConditionalLogic($field, $conditionName);
542 + } else {
543 + $this->extractConditionalLogic($field);
544 + }
315 545 }
316 546 }
317 547 } elseif (isset($item['settings']['conditional_logics'])) {
318 548 $conditionals = $item['settings']['conditional_logics'];
549 + if (!$itemName) {
550 + $itemName = $item['attributes']['data-name'];
551 + }
319 552 if (isset($conditionals['status'])) {
320 553 if ($conditionals['status'] && $conditionals['conditions']) {
321 - $this->conditions[$item['attributes']['data-name']] = $item['settings']['conditional_logics'];
554 + $this->conditions[$itemName] = $item['settings']['conditional_logics'];
322 555 }
323 556 }
324 - if(isset($item['container_conditions'])) {
325 - if(!isset($this->conditions[$item['attributes']['data-name']])) {
326 - $this->conditions[$item['attributes']['data-name']] = [
557 + if (isset($item['container_conditions'])) {
558 + if (! isset($this->conditions[$item['attributes']['data-name']])) {
559 + $this->conditions[$itemName] = [
327 560 'conditions' => [],
328 - 'status' => false,
329 - 'type' => 'any'
561 + 'status' => false,
562 + 'type' => 'any',
330 563 ];
331 564 }
332 - $this->conditions[$item['attributes']['data-name']]['container_condition'] = $item['container_conditions'];
565 + $this->conditions[$itemName]['container_condition'] = $item['container_conditions'];
333 566 }
334 567 }
335 568 }
336 569
@@ -335,9 +568,11 @@
335 568 }
336 569
337 570 /**
338 571 * Build attributes for any html element
339 - * @param array $attributes
572 + *
573 + * @param array $attributes
574 + *
340 575 * @return string [Compiled key='value' attributes]
341 576 */
342 577 protected function buildAttributes($attributes, $form = null)
343 578 {
@@ -342,12 +577,32 @@
342 577 protected function buildAttributes($attributes, $form = null)
343 578 {
344 579 $atts = '';
345 580 foreach ($attributes as $key => $value) {
346 - if ($value || $value === 0 || $value === '0') {
581 + // SECURITY (FINDING-06): drop event-handler attribute keys and escape the key name
582 + // (author-controlled attribute keys are not allowlisted at save).
583 + if (preg_match('/^on[a-z]/i', (string) $key)) {
584 + continue;
585 + }
586 + if ($value || 0 === $value || '0' === $value) {
347 587 $value = htmlspecialchars($value);
348 - $atts .= $key.'="'.$value.'" ';
588 + $atts .= esc_attr($key) . '="' . $value . '" ';
349 589 }
350 590 }
351 591 return $atts;
592 + }
593 +
594 + /**
595 + * Get hidden fieldset html
596 + *
597 + * @param $form
598 + *
599 + * @return string
600 + */
601 + private function fieldsetHtml($form)
602 + {
603 + return '<fieldset style="border: none!important;margin: 0!important;padding: 0!important;background-color: transparent!important;box-shadow: none!important;outline: none!important; min-inline-size: 100%;">
604 + <legend class="ff_screen_reader_title" style="display: block; margin: 0!important;padding: 0!important;height: 0!important;text-indent: -999999px;width: 0!important;overflow:hidden;">'
605 + .esc_html($form->title).
606 + '</legend>';
352 607 }
353 608 }