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 +335 -85 3.6.61 → 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,42 +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 - if(strpos($formBody, '{dynamic.')) {
94 + if (strpos($formBody, '{dynamic.')) {
73 95 $formClass .= ' ff_has_dynamic_smartcode';
74 96 wp_enqueue_script('fluentform-advanced');
75 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 + );
76 109
77 - $formClass = apply_filters('fluentform_form_class', $formClass, $form);
110 + $formClass = apply_filters('fluentform/form_class', $formClass, $form);
78 111
79 112 if ($form->has_payment) {
80 113 $formClass .= ' fluentform_has_payment';
81 114 }
82 115
83 - $formAttributes = apply_filters('fluent_form_html_attributes', [
84 - 'data-form_id' => $form->id,
85 - 'id' => 'fluentform_'.$form->id,
86 - 'class' => $formClass,
87 - 'data-form_instance' => $instanceCssClass
88 - ], $form);
116 + if ($themeStyle) {
117 + $formClass .= ' ' . $themeStyle;
118 + }
89 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 +
90 141 $formAtts = $this->buildAttributes($formAttributes);
142 +
91 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);
92 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 + );
93 166
94 - 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 + }
95 185
96 - do_action('fluentform_before_form_render', $form);
97 -
98 - echo "<form ".$formAtts.">";
99 -
186 + /* This hook is deprecated & will be removed soon */
100 187 do_action('fluentform_form_element_start', $form);
101 188
102 - echo "<input type='hidden' name='__fluent_form_embded_post_id' value='" . get_the_ID() . "' />";
103 -
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 +
104 193 wp_nonce_field(
105 194 'fluentform-submit-form',
106 195 '_fluentform_' . $form->id . '_fluentformnonce',
107 196 true,
@@ -106,40 +195,77 @@
106 195 '_fluentform_' . $form->id . '_fluentformnonce',
107 196 true,
108 197 true
109 198 );
110 -
111 - echo $formBody;
112 -
113 - echo "</form><div id='fluentform_" . $form->id . "_errors' class='ff-errors-in-stack ";
114 199
115 - echo $extraCssClass . "_errors " . $instanceCssClass . "_errors'></div></div>";
116 -
117 - do_action('fluentform_after_form_render', $form);
118 -
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 +
119 221 return ob_get_clean();
120 222 }
121 223
122 -
224 + /**
225 + * @param \stdClass $form
226 + *
227 + * @return string form body
228 + */
123 229 public function buildFormBody($form)
124 230 {
125 231 $hasStepWrapper = isset($form->fields['stepsWrapper']) && $form->fields['stepsWrapper'];
126 -
232 +
127 233 ob_start();
128 -
234 +
129 235 $stepCounter = 1;
130 236
131 237 foreach ($form->fields['fields'] as $item) {
132 -
133 - if ($hasStepWrapper && $item['element'] == 'form_step') {
238 + if ($hasStepWrapper && 'form_step' == $item['element']) {
134 239 $stepCounter++;
135 240 }
136 241
137 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);
138 255
139 - $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 + );
140 266
141 - do_action('fluentform_render_item_' . $item['element'], $item, $form);
267 + do_action('fluentform/render_item_' . $item['element'], $item, $form);
142 268
143 269 $this->extractValidationRules($item);
144 270
145 271 $this->extractConditionalLogic($item);
@@ -145,11 +271,31 @@
145 271 $this->extractConditionalLogic($item);
146 272 }
147 273
148 274 if ($hasStepWrapper) {
149 - 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);
150 286 } else {
151 - 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);
152 298 }
153 299
154 300 $content = ob_get_clean();
155 301
@@ -154,11 +300,11 @@
154 300 $content = ob_get_clean();
155 301
156 302 if ($hasStepWrapper) {
157 303 $startElement = $form->fields['stepsWrapper']['stepStart'];
158 -
304 +
159 305 $steps = ArrayHelper::get($startElement, 'settings.step_titles');
160 -
306 +
161 307 // check if $stepCounter == count()
162 308 if ($stepCounter > count($steps)) {
163 309 $fillCount = $stepCounter - count($steps);
164 310 foreach (range(1, $fillCount) as $item) {
@@ -167,16 +313,26 @@
167 313 $startElement['settings']['step_titles'] = $steps;
168 314 }
169 315
170 316 $this->setUniqueIdentifier($startElement);
171 -
317 +
172 318 ob_start();
173 -
174 - do_action('fluentform_render_item_step_start', $startElement, $form);
175 -
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 +
176 332 $stepStatrt = ob_get_clean();
177 -
178 - $content = $stepStatrt.$content;
333 +
334 + $content = $stepStatrt . $content;
179 335 }
180 336
181 337 return $content;
182 338 }
@@ -182,15 +338,17 @@
182 338 }
183 339
184 340 /**
185 341 * Set unique name/data-name for an element
342 + *
186 343 * @param array &$item
187 - * @return void
344 + *
345 + * @return void
188 346 */
189 347 protected function setUniqueIdentifier(&$item)
190 348 {
191 349 if (isset($item['columns'])) {
192 - $item['attributes']['data-name'] = 'ff_cn_id_'.$this->containerCounter;
350 + $item['attributes']['data-name'] = 'ff_cn_id_' . $this->containerCounter;
193 351 $this->containerCounter++;
194 352 foreach ($item['columns'] as &$column) {
195 353 foreach ($column['fields'] as &$field) {
196 354 $this->setUniqueIdentifier($field);
@@ -196,18 +354,18 @@
196 354 $this->setUniqueIdentifier($field);
197 355 }
198 356 }
199 357 } else {
200 - if (!isset($item['attributes']['name'])) {
201 - if($this->form) {
202 - 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)) {
203 361 $this->form->attr_name_index = 1;
204 362 } else {
205 363 $this->form->attr_name_index += 1;
206 364 }
207 - $uniqueId = $this->form->id.'_'.$this->form->attr_name_index;
365 + $uniqueId = $this->form->id . '_' . $this->form->attr_name_index;
208 366 } else {
209 - $uniqueId = uniqid(rand(), true);
367 + $uniqueId = uniqid(wp_rand(), true);
210 368 }
211 369
212 370 $item['attributes']['name'] = $item['element'] . '-' . $uniqueId;
213 371 }
@@ -217,14 +375,16 @@
217 375 }
218 376
219 377 /**
220 378 * Recursively extract validation rules from a given element
379 + *
221 380 * @param array $item
381 + *
222 382 * @return void
223 383 */
224 384 protected function extractValidationRules($item)
225 385 {
226 - if (isset($item['columns'])) {
386 + if (isset($item['columns']) && 'repeater_container' !== $item['element']) {
227 387 foreach ($item['columns'] as $column) {
228 388 foreach ($column['fields'] as $field) {
229 389 $this->extractValidationRules($field);
230 390 }
@@ -231,14 +391,14 @@
231 391 }
232 392 } elseif (isset($item['fields'])) {
233 393 $rootName = $item['attributes']['name'];
234 394 foreach ($item['fields'] as $key => $innerItem) {
235 - if ($item['element'] == 'address' || $item['element'] == 'input_name') {
395 + if ('address' == $item['element'] || 'input_name' == $item['element']) {
236 396 $itemName = $innerItem['attributes']['name'];
237 397 $innerItem['attributes']['name'] = $rootName . '[' . $itemName . ']';
238 398 } else {
239 - if ($item['element'] == 'input_repeat' || $item['element'] == 'repeater_field') {
240 - 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'])) {
241 401 unset($innerItem['settings']['validation_rules']['email']);
242 402 }
243 403 $innerItem['attributes']['name'] = $rootName . '[' . $key . ']';
244 404 } else {
@@ -246,14 +406,15 @@
246 406 }
247 407 }
248 408 $this->extractValidationRule($innerItem);
249 409 }
250 - } elseif ($item['element'] == 'tabular_grid') {
410 + } elseif ('tabular_grid' == $item['element']) {
251 411 $gridName = $item['attributes']['name'];
252 412 $gridRows = $item['settings']['grid_rows'];
253 413 $gridType = $item['settings']['tabular_field_type'];
254 414 foreach ($gridRows as $rowKey => $rowValue) {
255 - if ($gridType == 'radio') {
415 + $rowKey = trim(sanitize_text_field($rowKey));
416 + if ('radio' == $gridType) {
256 417 $item['attributes']['name'] = $gridName . '[' . $rowKey . ']';
257 418 $this->extractValidationRule($item);
258 419 } else {
259 420 $item['attributes']['name'] = $gridName . '[' . $rowKey . ']';
@@ -259,14 +420,26 @@
259 420 $item['attributes']['name'] = $gridName . '[' . $rowKey . ']';
260 421 $this->extractValidationRule($item);
261 422 }
262 423 }
263 - } elseif ($item['element'] == 'chained_select') {
424 + } elseif ('chained_select' == $item['element']) {
264 425 $chainedSelectName = $item['attributes']['name'];
265 426 foreach ($item['settings']['data_source']['headers'] as $select) {
266 427 $item['attributes']['name'] = $chainedSelectName . '[' . $select . ']';
267 428 $this->extractValidationRule($item);
268 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 + }
269 442 } else {
270 443 $this->extractValidationRule($item);
271 444 }
272 445 }
@@ -272,32 +445,77 @@
272 445 }
273 446
274 447 /**
275 448 * Extract validation rules from a given element
449 + *
276 450 * @param array $item
451 + *
277 452 * @return void
278 453 */
279 - protected function extractValidationRule($item)
454 + protected function extractValidationRule($item, $name = '')
280 455 {
281 456 if (isset($item['settings']['validation_rules'])) {
282 457 $rules = $item['settings']['validation_rules'];
283 458 foreach ($rules as $ruleName => $rule) {
284 - if(isset($rule['message'])) {
285 - $rules[$ruleName]['message'] = apply_filters('fluentform_validation_message_'.$ruleName, $rule['message'], $item);
286 - $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);
287 488 }
288 489 }
289 - $rules = apply_filters('fluentform_item_rules_' . $item['element'], $rules, $item);
290 - $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;
291 507 }
292 508 }
293 509
294 510 /**
295 - * Extract conditipnal logic from a given element
511 + * Extract conditional logic from a given element
512 + *
296 513 * @param array $item
514 + *
297 515 * @return void
298 516 */
299 - protected function extractConditionalLogic($item)
517 + protected function extractConditionalLogic($item, $itemName = '')
300 518 {
301 519 // If container like element, then recurse
302 520 if (isset($item['columns'])) {
303 521 $containerConditions = false;
@@ -309,33 +527,43 @@
309 527 $this->conditions[$item['attributes']['data-name']] = $containerConditions;
310 528 }
311 529 }
312 530 }
531 + $parentName = ArrayHelper::get($item, 'attributes.name');
532 + $isRepeaterContainer = ArrayHelper::get($item, 'element') === 'repeater_container';
313 533
314 - foreach ($item['columns'] as $column) {
315 - foreach ($column['fields'] as $field) {
316 - if($containerConditions) {
534 + foreach ($item['columns'] as $colIndex => $column) {
535 + foreach ($column['fields'] as $fieldIndex => $field) {
536 + if ($containerConditions) {
317 537 $field['container_conditions'] = $containerConditions;
318 538 }
319 - $this->extractConditionalLogic($field);
539 + if ($isRepeaterContainer) {
540 + $conditionName = $parentName . '_condition_' . $colIndex . '_' . $fieldIndex;
541 + $this->extractConditionalLogic($field, $conditionName);
542 + } else {
543 + $this->extractConditionalLogic($field);
544 + }
320 545 }
321 546 }
322 547 } elseif (isset($item['settings']['conditional_logics'])) {
323 548 $conditionals = $item['settings']['conditional_logics'];
549 + if (!$itemName) {
550 + $itemName = $item['attributes']['data-name'];
551 + }
324 552 if (isset($conditionals['status'])) {
325 553 if ($conditionals['status'] && $conditionals['conditions']) {
326 - $this->conditions[$item['attributes']['data-name']] = $item['settings']['conditional_logics'];
554 + $this->conditions[$itemName] = $item['settings']['conditional_logics'];
327 555 }
328 556 }
329 - if(isset($item['container_conditions'])) {
330 - if(!isset($this->conditions[$item['attributes']['data-name']])) {
331 - $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] = [
332 560 'conditions' => [],
333 - 'status' => false,
334 - 'type' => 'any'
561 + 'status' => false,
562 + 'type' => 'any',
335 563 ];
336 564 }
337 - $this->conditions[$item['attributes']['data-name']]['container_condition'] = $item['container_conditions'];
565 + $this->conditions[$itemName]['container_condition'] = $item['container_conditions'];
338 566 }
339 567 }
340 568 }
341 569
@@ -340,9 +568,11 @@
340 568 }
341 569
342 570 /**
343 571 * Build attributes for any html element
344 - * @param array $attributes
572 + *
573 + * @param array $attributes
574 + *
345 575 * @return string [Compiled key='value' attributes]
346 576 */
347 577 protected function buildAttributes($attributes, $form = null)
348 578 {
@@ -347,12 +577,32 @@
347 577 protected function buildAttributes($attributes, $form = null)
348 578 {
349 579 $atts = '';
350 580 foreach ($attributes as $key => $value) {
351 - 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) {
352 587 $value = htmlspecialchars($value);
353 - $atts .= $key.'="'.$value.'" ';
588 + $atts .= esc_attr($key) . '="' . $value . '" ';
354 589 }
355 590 }
356 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>';
357 607 }
358 608 }