PluginProbe
FireBox – WooCommerce Popup Builder, Exit Intent Popup, Email Optin & Cart Abandonment / 2.0.6
FireBox – WooCommerce Popup Builder, Exit Intent Popup, Email Optin & Cart Abandonment v2.0.6
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.6, at Inc/Core/Helpers/Form/Form.php

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