PluginProbe
FireBox – WooCommerce Popup Builder, Exit Intent Popup, Email Optin & Cart Abandonment / 2.0.16
FireBox – WooCommerce Popup Builder, Exit Intent Popup, Email Optin & Cart Abandonment v2.0.16
3.1.13 3.1.12 3.1.11 3.1.10 3.1.9 3.1.8 3.1.7 trunk 1.0.0 1.0.1 1.0.10 1.0.11 1.0.12 1.0.13 1.0.14 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 All 122 releases
firebox / Inc / Core / Helpers / Form / Form.php

Form.php in FireBox – WooCommerce Popup Builder, Exit Intent Popup, Email Optin & Cart Abandonment 2.0.16, at Inc/Core/Helpers/Form/Form.php

639 lines 14.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @package FireBox
4 * @version 2.0.16 Free
5 *
6 * @author FirePlugins <info@fireplugins.com>
7 * @link https://www.fireplugins.com
8 * @copyright Copyright © 2023 FirePlugins All Rights Reserved
9 * @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
10 */
11
12 namespace FireBox\Core\Helpers\Form;
13
14 if (!defined('ABSPATH'))
15 {
16 exit; // Exit if accessed directly.
17 }
18
19 use \FireBox\Core\Helpers\BoxHelper;
20 use \FPFramework\Helpers\Plugins\FireBox\Form as FrameworkFireBoxForm;
21
22 class Form
23 {
24 /**
25 * Checks whether a form is valid given its ID.
26 *
27 * @param string $form_id
28 *
29 * @return string
30 */
31 public static function isValid($form_id = null)
32 {
33 if (!$form_id)
34 {
35 return false;
36 }
37
38 // Validate Form ID
39 // Get all popups
40 $popups = BoxHelper::getAllBoxes(['publish', 'draft']);
41 $popups = BoxHelper::produceKeyValueBoxes($popups->posts);
42
43 // Whether the Form ID is valid
44 $valid_form_id = false;
45
46 if (!$forms = self::getForms())
47 {
48 return false;
49 }
50
51 foreach ($forms as $key => $form)
52 {
53 if ('form-' . $form['id'] !== $form_id)
54 {
55 continue;
56 }
57
58 return $form;
59 }
60
61 return;
62 }
63
64 /**
65 * Returns a list of forms with form id => form title key,value pair.
66 *
67 * @return array
68 */
69 public static function getParsedForms()
70 {
71 // cache key
72 $hash = md5('FireBox\Core\Belpers\Form::getParsedForms');
73
74 // check cache
75 if ($forms = wp_cache_get($hash))
76 {
77 return;
78 }
79
80 $forms = self::getForms();
81
82 $parsed = [];
83
84 foreach ($forms as $key => $value)
85 {
86 $parsed[$value['id']] = $value['name'];
87 }
88
89 // set cache
90 wp_cache_set($hash, $parsed, $hash);
91
92 return $parsed;
93 }
94
95 /**
96 * Gets all forms.
97 *
98 * @return array
99 */
100 public static function getForms()
101 {
102 // Get all popups
103 $popups_data = BoxHelper::getAllBoxes(['publish', 'draft']);
104 $popups = BoxHelper::produceKeyValueBoxes($popups_data->posts);
105
106 $forms = [];
107
108 // Find forms
109 foreach ($popups as $id => $title)
110 {
111 if (!has_block('firebox/form', $id))
112 {
113 continue;
114 }
115
116 $blocks = parse_blocks(get_the_content(null, false, $id));
117
118 $popup_data = self::findPopupByID($id, $popups_data->posts);
119
120 foreach ($blocks as $key => $block)
121 {
122 if (isset($block['innerBlocks']))
123 {
124 foreach ($block['innerBlocks'] as $innerBlock)
125 {
126 // Find form block
127 if (!$form_block = FrameworkFireBoxForm::findRecursiveForm($innerBlock))
128 {
129 continue;
130 }
131
132 $atts = isset($form_block['attrs']) ? $form_block['attrs'] : false;
133 if (!$atts)
134 {
135 continue;
136 }
137
138 $block_unique_id = isset($atts['uniqueId']) ? $atts['uniqueId'] : false;
139 if (!$block_unique_id)
140 {
141 continue;
142 }
143
144 $forms[] = [
145 'id' => $block_unique_id,
146 'block' => $form_block,
147 'created_at' => $popup_data->post_modified_gmt ? $popup_data->post_modified_gmt : $popup_data->post_date_gmt,
148 'state' => $popup_data->post_status === 'publish' ? '1' : '0',
149 'name' => isset($form_block['attrs']['formName']) ? $form_block['attrs']['formName'] : firebox()->_('FB_UNTITLED_FORM'),
150 'fields' => self::getFormFields($form_block)
151 ];
152 }
153 }
154
155 if ($block['blockName'] !== 'firebox/form')
156 {
157 continue;
158 }
159
160 $atts = isset($block['attrs']) ? $block['attrs'] : false;
161 if (!$atts)
162 {
163 continue;
164 }
165
166 $block_unique_id = isset($atts['uniqueId']) ? $atts['uniqueId'] : false;
167 if (!$block_unique_id)
168 {
169 continue;
170 }
171
172 $forms[] = [
173 'id' => $block_unique_id,
174 'block' => $block,
175 'created_at' => $popup_data->post_modified_gmt ? $popup_data->post_modified_gmt : $popup_data->post_date_gmt,
176 'state' => $popup_data->post_status === 'publish' ? '1' : '0',
177 'name' => isset($block['attrs']['formName']) ? $block['attrs']['formName'] : firebox()->_('FB_UNTITLED_FORM'),
178 'fields' => self::getFormFields($block)
179 ];
180 }
181 }
182
183 return $forms;
184 }
185
186 public static function findPopupByID($id = null, $popups = [])
187 {
188 if (!$id || !$popups)
189 {
190 return;
191 }
192
193 foreach ($popups as $key => $popup)
194 {
195 if ($popup->ID !== $id)
196 {
197 continue;
198 }
199
200 return $popup;
201 }
202
203 return false;
204 }
205
206 /**
207 * Validates the form.
208 *
209 * @param array $form_fields
210 * @param array $fields_values
211 *
212 * @return array
213 */
214 public static function validate($form_fields = [], &$fields_values = [])
215 {
216 if (!$form_fields || !$fields_values)
217 {
218 return false;
219 }
220
221 $validation = [];
222
223 // Remove honeypot field
224 unset($fields_values['hnpt']);
225
226 // Check honeypot
227 if (isset($fields_values['hnpt']) && !empty($fields_values['hnpt']))
228 {
229 return [
230 'error' => true,
231 'message' => firebox()->_('FB_HONEYPOT_FIELD_TRIGGERED')
232 ];
233 }
234
235 // Ensure the fields values are based on valid form fields
236 foreach ($fields_values as $field_name => $field_value)
237 {
238 $valid_value = count(array_filter($form_fields, function($field) use ($field_name) {
239 return $field_name === $field->getOptionValue('name');
240 }));
241
242 if (!$valid_value)
243 {
244 unset($fields_values[$field_name]);
245 }
246 }
247
248 $error_msgs = [];
249
250 // Validate fields
251 foreach ($form_fields as $field)
252 {
253 $field_name = $field->getOptionValue('name');
254
255 // Whether this is an array that contains a "value" key that stores the value or if its the whole value of the key $field_name
256 $field_value = isset($fields_values[$field_name]['value']) ? $fields_values[$field_name]['value'] : $fields_values[$field_name];
257
258 // Validate class
259 if (!$field->validate($field_value))
260 {
261 $validation_message = $field->getValidationMessage();
262 $error_msgs[] = $field->getLabel() . ': ' . $validation_message;
263
264 $validation[] = [
265 'name' => $field_name,
266 'label' => $field->getLabel(),
267 'type' => $field->getOptionValue('type'),
268 'validation_message' => $validation_message
269 ];
270 }
271
272 // Update field value after validation
273 if (isset($fields_values[$field_name]['value']))
274 {
275 $fields_values[$field_name]['value'] = $field_value;
276 }
277 else
278 {
279 $fields_values[$field_name] = $field_value;
280 }
281 }
282
283 return $validation ? ['error' => $validation, 'message' => implode('<br />', $error_msgs)] : $form_fields;
284 }
285
286 /**
287 * Finds all supported blocks recursively.
288 *
289 * @param array $block
290 * @param array $supported_blocks
291 *
292 * @return array
293 */
294 private static function findRecursiveBlocks($block, $supported_blocks)
295 {
296 $matching_blocks = [];
297
298 if (in_array($block['blockName'], $supported_blocks))
299 {
300 $matching_blocks[] = $block;
301 }
302
303 if (!empty($block['innerBlocks']))
304 {
305 foreach ($block['innerBlocks'] as $innerBlockItem)
306 {
307 $innerBlocks = self::findRecursiveBlocks($innerBlockItem, $supported_blocks);
308
309 if (!empty($innerBlocks))
310 {
311 $matching_blocks = array_merge($matching_blocks, $innerBlocks);
312 }
313 }
314 }
315
316 return $matching_blocks;
317 }
318
319 /**
320 * Return the form fields.
321 *
322 * @param array $form
323 *
324 * @return array
325 */
326 public static function getFormFields($form)
327 {
328 // Find all supported fields
329 $supported_blocks = self::getSupportedBlocks();
330
331 $form_fields = [];
332
333 // Find form blocks
334 foreach ($form['innerBlocks'] as $key => $block)
335 {
336 // Find supported block
337 if (!$found_blocks = self::findRecursiveBlocks($block, $supported_blocks))
338 {
339 continue;
340 }
341
342 foreach ($found_blocks as $_block)
343 {
344 $field_payload = [
345 'id' => $_block['attrs']['uniqueId'],
346 'label' => Field::getFieldLabel($_block),
347 'type' => Field::getFieldType($_block['blockName']),
348 'name' => Field::getFieldName($_block)
349 ];
350 $final_field_payload = array_merge($field_payload, $_block['attrs']);
351
352 // If the dropdown field doesn't have any custom choices, use the default ones
353 if ($final_field_payload['type'] === 'dropdown')
354 {
355 if (!isset($final_field_payload['choices']))
356 {
357 $final_field_payload['choices'] = [
358 [
359 'default' => false,
360 'value' => 1,
361 'label' => 'Choice 1',
362 'image' => ''
363 ],
364 [
365 'default' => false,
366 'value' => 2,
367 'label' => 'Choice 2',
368 'image' => ''
369 ],
370 [
371 'default' => false,
372 'value' => 3,
373 'label' => 'Choice 3',
374 'image' => ''
375 ]
376 ];
377 }
378 }
379
380 $form_fields[] = Field::getFieldClass($final_field_payload);
381 }
382 }
383
384 return $form_fields;
385 }
386
387 /**
388 * Returns the form given its ID.
389 *
390 * @param string $form_id
391 *
392 * @return array
393 */
394 public static function getFormByID($form_id = null)
395 {
396 $forms = self::getForms();
397
398 foreach ($forms as $form)
399 {
400 if ($form['id'] !== $form_id)
401 {
402 continue;
403 }
404
405 return $form;
406 }
407
408 return false;
409 }
410
411 /**
412 * Returns the supported blocks.
413 *
414 * @param bool $clean Whether to return only the name of the field without the prefix "firebox/"
415 *
416 * @return array
417 */
418 public static function getSupportedBlocks($clean = false)
419 {
420 $blocks = array_diff(scandir(FBOX_PLUGIN_DIR . 'Inc/Core/Form/Fields/Fields'), ['index.php', '.', '..', '.DS_Store']);
421
422 $data = [];
423
424 foreach ($blocks as $key => $name)
425 {
426 // Strip .php
427 $name = rtrim($name, '.php');
428
429 $data[] = (!$clean ? 'firebox/' : '') . strtolower($name);
430 }
431
432 return $data;
433 }
434
435 /**
436 * Store submission.
437 *
438 * @param string $form_id
439 * @param array $form_settings
440 * @param array $valid_fields
441 * @param array $fields_values
442 * @param bool $save
443 *
444 * @return array
445 */
446 public static function storeSubmission($form_id, $form_settings, $valid_fields, $fields_values, $save = true)
447 {
448 $submissionDefaultState = isset($form_settings['attrs']['submissionDefaultState']) ? $form_settings['attrs']['submissionDefaultState'] : 1;
449
450 if (!$submission_data = Submission::create($form_id, $submissionDefaultState, $save))
451 {
452 return false;
453 }
454
455 if (!$submission_meta_data = SubmissionMeta::create($submission_data['id'], $fields_values, $save))
456 {
457 return false;
458 }
459
460 return self::prepare($submission_data, $valid_fields, $fields_values);
461 }
462
463 /**
464 * Prepare fields.
465 *
466 * @param array $submission
467 * @param array $valid_fields
468 * @param array $fields_values
469 *
470 * @return array
471 */
472 private static function prepare($submission, $valid_fields, $fields_values)
473 {
474 $prepared_data = $submission;
475 $prepared_data['prepared_fields'] = [];
476
477 foreach ($valid_fields as $key => $field)
478 {
479 $field_name = $field->getOptionValue('name');
480 $submitted_value = $fields_values[$field_name];
481
482 $field->setValue($submitted_value['value']);
483
484 $prepared_data['prepared_fields'][$field_name] = [
485 'class' => $field,
486 'value' => $field->prepareValue($submitted_value['value']),
487 'value_html' => $field->prepareValueHTML($submitted_value['value']),
488 'value_raw' => $submitted_value['value']
489 ];
490 }
491
492 return $prepared_data;
493 }
494
495 /**
496 * Ensure the popup has unique Form IDs.
497 *
498 * @param string $content
499 *
500 * @return void
501 */
502 public static function ensureUniqueFormIDs(&$content)
503 {
504 // Get forms
505 $forms = self::getForms();
506
507 // Get form IDs in content
508 $pattern = '/wp:firebox\/form {"uniqueId":"(.*?)"/';
509
510 // Find matches
511 preg_match_all($pattern, $content, $matches);
512
513 // Ensure we have at least one form in the popup
514 if (!isset($matches[1]) || empty($matches[1]))
515 {
516 return;
517 }
518
519 $old_form_ids_in_popup = $matches[1];
520 $new_form_ids_in_popup = [];
521
522 // Find new IDs
523 foreach ($old_form_ids_in_popup as $key => $id)
524 {
525 while (true)
526 {
527 $form = array_filter($forms, function($form_item) use ($id) {
528 return $id === $form_item['id'];
529 });
530 $form_id = reset($form);
531
532 // Form ID is unique
533 if (!$form_id)
534 {
535 $new_form_ids_in_popup[] = $id;
536 break;
537 }
538
539 // Form ID is not unique, generate new
540 $id = md5(uniqid());
541 $id = substr($id, 0, 12);
542
543 // Add dash after 6th character
544 $id = substr_replace($id, '-', 6, 0);
545
546 // Add dash after 10th character
547 $id = substr_replace($id, '-', 11, 0);
548 }
549 }
550
551 if (count($old_form_ids_in_popup) !== count($new_form_ids_in_popup))
552 {
553 return;
554 }
555
556 // Replace old IDs with new IDs
557 foreach ($old_form_ids_in_popup as $index => $id)
558 {
559 // Replace unique ID
560 $content = str_replace('"uniqueId":"' . $id . '"', '"uniqueId":"' . $new_form_ids_in_popup[$index] . '"', $content);
561
562 // Replace all other instances
563 $content = str_replace('form-' . $id, 'form-' . $new_form_ids_in_popup[$index], $content);
564 }
565 }
566
567 /**
568 * Replaces Smart Tags.
569 *
570 * @param array $attrs
571 * @param array $fields_values
572 * @param array $submission
573 *
574 * @return void
575 */
576 public static function replaceSmartTags(&$attrs, $fields_values, $submission)
577 {
578 // Replace Smart Tags
579 $tags = new \FPFramework\Base\SmartTags\SmartTags();
580
581 // register FB Smart Tags
582 $tags->register('\FireBox\Core\Form\SmartTags', FBOX_BASE_FOLDER . '/Inc/Core/Form/SmartTags', [
583 'field_values' => $fields_values,
584 'submission' => $submission
585 ]);
586
587 $attrs = $tags->replace($attrs);
588 }
589
590 /**
591 * Returns the submission action.
592 *
593 * @param array $attrs
594 *
595 * @return array
596 */
597 public static function getSubmissionAction($attrs)
598 {
599 $action = isset($attrs['submissionAction']) ? $attrs['submissionAction'] : 'message';
600
601 $payload = [
602 'action' => $action,
603 'message' => $action === 'message' ? (isset($attrs['messageAfterSuccess']) ? $attrs['messageAfterSuccess'] : 'Thanks for contacting us! We will get in touch with you shortly.') : '',
604 'resetForm' => isset($attrs['resetForm']) ? $attrs['resetForm'] : true,
605 'hideForm' => isset($attrs['hideForm']) ? $attrs['hideForm'] : true
606 ];
607
608 if ($action === 'redirect')
609 {
610 $payload['redirectURL'] = isset($attrs['redirectURL']) ? $attrs['redirectURL'] : '';
611 }
612
613 return $payload;
614 }
615
616 public static function getSubmissions($form_id = null)
617 {
618 if (!$form_id)
619 {
620 return;
621 }
622
623 $data = [
624 'where' => [
625 'form_id' => " = '" . esc_sql($form_id) . "'"
626 ],
627 'limit' => 1000
628 ];
629
630 $submissions = firebox()->tables->submission->getResults($data, true);
631
632 foreach ($submissions as &$submission)
633 {
634 $submission->meta = SubmissionMeta::getMeta($submission->id);
635 }
636
637 return $submissions;
638 }
639 }