Diff: STRATO-apps/wordpress_03/app/wp-content/plugins/fluentform/app/Helpers/Helper.php

Keine Baseline-Datei – Diff nur gegen leer.
Zur Liste
1 -
1 + <?php
2 +
3 + namespace FluentForm\App\Helpers;
4 +
5 + use FluentForm\App\Models\EntryDetails;
6 + use FluentForm\App\Models\Form;
7 + use FluentForm\App\Models\FormMeta;
8 + use FluentForm\App\Models\Submission;
9 + use FluentForm\App\Models\SubmissionMeta;
10 + use FluentForm\App\Services\FormBuilder\Components\SelectCountry;
11 + use FluentForm\App\Services\FormBuilder\ShortCodeParser;
12 + use FluentForm\Framework\Helpers\ArrayHelper;
13 + use FluentForm\App\Helpers\Traits\GlobalDefaultMessages;
14 + use FluentForm\Framework\Support\Arr;
15 +
16 + class Helper
17 + {
18 + use GlobalDefaultMessages;
19 +
20 + public static $tabIndex = 0;
21 +
22 + public static $formInstance = 0;
23 +
24 + public static $loadedForms = [];
25 +
26 + public static $tabIndexStatus = 'na';
27 +
28 + protected static $formMetaCache = [];
29 +
30 +
31 + /**
32 + * Sanitize form inputs recursively.
33 + *
34 + * @param $input
35 + *
36 + * @return string $input
37 + */
38 + public static function sanitizer($input, $attribute = null, $fields = [])
39 + {
40 + if (is_string($input)) {
41 + if ('textarea' === ArrayHelper::get($fields, $attribute . '.element')) {
42 + $input = sanitize_textarea_field($input);
43 + } else {
44 + $input = sanitize_text_field($input);
45 + }
46 + } elseif (is_array($input)) {
47 + foreach ($input as $key => &$value) {
48 + $attribute = $attribute ? $attribute . '[' . $key . ']' : $key;
49 +
50 + $value = static::sanitizer($value, $attribute, $fields);
51 +
52 + $attribute = null;
53 + }
54 + }
55 +
56 + return $input;
57 + }
58 +
59 + public static function makeMenuUrl($page = 'fluent_forms_settings', $component = null)
60 + {
61 + $baseUrl = admin_url('admin.php?page=' . $page);
62 +
63 + $hash = ArrayHelper::get($component, 'hash', '');
64 + if ($hash) {
65 + $baseUrl = $baseUrl . '#' . $hash;
66 + }
67 +
68 + $query = ArrayHelper::get($component, 'query');
69 +
70 + if ($query) {
71 + $paramString = http_build_query($query);
72 + if ($hash) {
73 + $baseUrl .= '?' . $paramString;
74 + } else {
75 + $baseUrl .= '&' . $paramString;
76 + }
77 + }
78 +
79 + return $baseUrl;
80 + }
81 +
82 + public static function getHtmlElementClass($value1, $value2, $class = 'active', $default = '')
83 + {
84 + return $value1 === $value2 ? $class : $default;
85 + }
86 +
87 + /**
88 + * Determines if the given string is a valid json.
89 + *
90 + * @param $string
91 + *
92 + * @return bool
93 + */
94 + public static function isJson($string)
95 + {
96 + json_decode($string);
97 +
98 + return JSON_ERROR_NONE === json_last_error();
99 + }
100 +
101 + public static function isSlackEnabled()
102 + {
103 + $globalModules = get_option('fluentform_global_modules_status');
104 +
105 + return $globalModules && isset($globalModules['slack']) && 'yes' == $globalModules['slack'];
106 + }
107 +
108 + public static function getEntryStatuses($form_id = false)
109 + {
110 + $statuses = [
111 + 'unread' => __('Unread', 'fluentform'),
112 + 'read' => __('Read', 'fluentform'),
113 + 'favorites' => __('Favorites', 'fluentform'),
114 + ];
115 +
116 + $statuses = apply_filters_deprecated(
117 + 'fluentform_entry_statuses_core',
118 + [
119 + $statuses,
120 + $form_id
121 + ],
122 + FLUENTFORM_FRAMEWORK_UPGRADE,
123 + 'fluentform/entry_statuses_core',
124 + 'Use fluentform/entry_statuses_core instead of fluentform_entry_statuses_core.'
125 + );
126 +
127 + $statuses = apply_filters('fluentform/entry_statuses_core', $statuses, $form_id);
128 +
129 + $statuses['trashed'] = 'Trashed';
130 +
131 + return $statuses;
132 + }
133 +
134 + public static function getReportableInputs()
135 + {
136 + $data = [
137 + 'select',
138 + 'input_radio',
139 + 'input_checkbox',
140 + 'ratings',
141 + 'net_promoter',
142 + 'select_country',
143 + 'net_promoter_score',
144 + ];
145 +
146 + $data = apply_filters_deprecated(
147 + 'fluentform_reportable_inputs',
148 + [
149 + $data
150 + ],
151 + FLUENTFORM_FRAMEWORK_UPGRADE,
152 + 'fluentform/reportable_inputs',
153 + 'Use fluentform/reportable_inputs instead of fluentform_reportable_inputs.'
154 + );
155 +
156 + return apply_filters('fluentform/reportable_inputs', $data);
157 + }
158 +
159 + public static function getSubFieldReportableInputs()
160 + {
161 + $grid = apply_filters_deprecated(
162 + 'fluentform_subfield_reportable_inputs',
163 + [
164 + ['tabular_grid']
165 + ],
166 + FLUENTFORM_FRAMEWORK_UPGRADE,
167 + 'fluentform/subfield_reportable_inputs',
168 + 'Use fluentform/subfield_reportable_inputs instead of fluentform_subfield_reportable_inputs.'
169 + );
170 +
171 + return apply_filters('fluentform/subfield_reportable_inputs', $grid);
172 + }
173 +
174 + public static function getFormMeta($formId, $metaKey, $default = '', $forced = false)
175 + {
176 + $formattedValues = self::$formMetaCache[$formId] ?? [];
177 +
178 + if (!isset(self::$formMetaCache[$formId]) || $forced) {
179 + $formMetas = FormMeta::where('form_id', $formId)
180 + ->get();
181 +
182 + $formattedValues = [];
183 + foreach ($formMetas as $formMeta) {
184 + $value = $formMeta->value;
185 +
186 + $decoded = json_decode($value ?? '', true);
187 + if (is_array($decoded)) {
188 + $value = $decoded;
189 + }
190 +
191 + $formattedValues[$formMeta->meta_key] = $value;
192 + }
193 + self::$formMetaCache[$formId] = $formattedValues;
194 + }
195 +
196 + return Arr::get($formattedValues, $metaKey, $default);
197 + }
198 +
199 +
200 + public static function setFormMeta($formId, $metaKey, $value)
201 + {
202 + if ($meta = FormMeta::persist($formId, $metaKey, $value)) {
203 + // Update the cache with the new value
204 + if (!isset(self::$formMetaCache[$formId])) {
205 + self::$formMetaCache[$formId] = [];
206 + }
207 + self::$formMetaCache[$formId][$metaKey] = $value;
208 +
209 + return $meta->id;
210 + }
211 + return null;
212 + }
213 +
214 + public static function deleteFormMeta($formId, $metaKey)
215 + {
216 + try {
217 + FormMeta::remove($formId, $metaKey);
218 + return true;
219 + } catch (\Exception $ex) {
220 + return null;
221 + }
222 + }
223 +
224 + public static function getSubmissionMeta($submissionId, $metaKey, $default = false)
225 + {
226 + return SubmissionMeta::retrieve($metaKey, $submissionId, $default);
227 + }
228 +
229 + public static function setSubmissionMeta($submissionId, $metaKey, $value, $formId = false)
230 + {
231 + if ($meta = SubmissionMeta::persist($submissionId, $metaKey, $value, $formId)) {
232 + return $meta->id;
233 + }
234 + return null;
235 + }
236 +
237 + public static function setSubmissionMetaAsArrayPush($submissionId, $metaKey, $value, $formId = false)
238 + {
239 + if ($meta = SubmissionMeta::persistArray($submissionId, $metaKey, $value, $formId)) {
240 + return $meta->id;
241 + }
242 + return null;
243 + }
244 +
245 + public static function isEntryAutoDeleteEnabled($formId)
246 + {
247 + if (
248 + 'yes' == ArrayHelper::get(static::getFormMeta($formId, 'formSettings', []), 'delete_entry_on_submission',
249 + '')
250 + ) {
251 + return true;
252 + }
253 + return false;
254 + }
255 +
256 + public static function formExtraCssClass($form)
257 + {
258 + if (!$form->settings) {
259 + $formSettings = static::getFormMeta($form->id, 'formSettings');
260 + } else {
261 + $formSettings = $form->settings;
262 + }
263 +
264 + if (!$formSettings) {
265 + return '';
266 + }
267 +
268 + if ($extraClass = ArrayHelper::get($formSettings, 'form_extra_css_class')) {
269 + return esc_attr($extraClass);
270 + }
271 +
272 + return '';
273 + }
274 +
275 + public static function getNextTabIndex($increment = 1)
276 + {
277 + if (static::isTabIndexEnabled()) {
278 + static::$tabIndex += $increment;
279 +
280 + return static::$tabIndex;
281 + }
282 +
283 + return '';
284 + }
285 +
286 + public static function getFormInstaceClass($formId)
287 + {
288 + static::$formInstance += 1;
289 +
290 + return 'ff_form_instance_' . $formId . '_' . static::$formInstance;
291 + }
292 +
293 + public static function resetTabIndex()
294 + {
295 + static::$tabIndex = 0;
296 + }
297 +
298 + public static function isFluentAdminPage()
299 + {
300 + $fluentPages = [
301 + 'fluent_forms',
302 + 'fluent_forms_all_entries',
303 + 'fluent_forms_transfer',
304 + 'fluent_forms_settings',
305 + 'fluent_forms_add_ons',
306 + 'fluent_forms_docs',
307 + 'fluent_forms_payment_entries',
308 + 'fluent_forms_smtp',
309 + 'fluent_forms_reports'
310 + ];
311 +
312 + $status = true;
313 +
314 + $page = wpFluentForm('request')->get('page');
315 +
316 + if (!$page || !in_array($page, $fluentPages)) {
317 + $status = false;
318 + }
319 +
320 + $status = apply_filters_deprecated(
321 + 'fluentform_is_admin_page',
322 + [
323 + $status
324 + ],
325 + FLUENTFORM_FRAMEWORK_UPGRADE,
326 + 'fluentform/is_admin_page',
327 + 'Use fluentform/is_admin_page instead of fluentform_is_admin_page.'
328 + );
329 +
330 + return apply_filters('fluentform/is_admin_page', $status);
331 + }
332 +
333 + public static function getShortCodeIds($content, $tag = 'fluentform', $selector = 'id')
334 + {
335 + if (false === strpos($content, '[')) {
336 + return [];
337 + }
338 +
339 + preg_match_all('/' . get_shortcode_regex() . '/', $content, $matches, PREG_SET_ORDER);
340 + if (empty($matches)) {
341 + return [];
342 + }
343 +
344 + $ids = [];
345 + $attributes = [];
346 +
347 + foreach ($matches as $shortcode) {
348 + if (count($shortcode) >= 2 && $tag === $shortcode[2]) {
349 + // Replace braces with empty string.
350 + $parsedCode = str_replace(['[', ']', '&#91;', '&#93;'], '', $shortcode[0]);
351 +
352 + $result = shortcode_parse_atts($parsedCode);
353 +
354 + if (!empty($result[$selector])) {
355 + if ($tag == 'fluentform' && !empty($result['type']) && $result['type'] == 'conversational') {
356 + continue;
357 + }
358 +
359 + $ids[$result[$selector]] = $result[$selector];
360 +
361 + $theme = ArrayHelper::get($result, 'theme');
362 +
363 + if ($theme) {
364 + $attributes[] = [
365 + 'formId' => $result[$selector],
366 + 'theme' => $theme
367 + ];
368 + }
369 + }
370 + }
371 + }
372 +
373 + if ($attributes) {
374 + $ids['attributes'] = $attributes;
375 + }
376 +
377 + return $ids;
378 + }
379 +
380 + public static function getFormsIdsFromBlocks($content)
381 + {
382 + $ids = [];
383 + $attributes = [];
384 +
385 + if (!function_exists('parse_blocks')) {
386 + return $ids;
387 + }
388 +
389 + $has_block = false !== strpos($content, '<!-- wp:fluentfom/guten-block' . ' ');
390 +
391 + if (!$has_block) {
392 + return $ids;
393 + }
394 +
395 + $parsedBlocks = parse_blocks($content);
396 + foreach ($parsedBlocks as $block) {
397 + if (!ArrayHelper::exists($block, 'blockName') || !ArrayHelper::get($block, 'attrs.formId')) {
398 + continue;
399 + }
400 +
401 + $hasBlock = strpos($block['blockName'], 'fluentfom/guten-block') === 0;
402 + if ($hasBlock) {
403 + $formId = (int)$block['attrs']['formId'];
404 +
405 + $ids[] = $formId;
406 +
407 + $theme = ArrayHelper::get($block, 'attrs.themeStyle');
408 +
409 + if ($theme) {
410 + $attributes[] = [
411 + 'formId' => $formId,
412 + 'theme' => $theme
413 + ];
414 + }
415 + }
416 + }
417 +
418 + if ($attributes) {
419 + $ids['attributes'] = $attributes;
420 + }
421 +
422 + return $ids;
423 + }
424 +
425 + public static function isTabIndexEnabled()
426 + {
427 + if ('na' == static::$tabIndexStatus) {
428 + $globalSettings = get_option('_fluentform_global_form_settings');
429 + static::$tabIndexStatus = 'yes' == ArrayHelper::get($globalSettings, 'misc.tabIndex');
430 + }
431 +
432 + return static::$tabIndexStatus;
433 + }
434 +
435 + public static function isMultiStepForm($formOrId)
436 + {
437 + // Accept both form object and form ID to avoid re-querying
438 + if (is_object($formOrId)) {
439 + $form = $formOrId;
440 + } else {
441 + $form = Form::find($formOrId);
442 + }
443 +
444 + if (!$form) {
445 + return false;
446 + }
447 +
448 + $fieldsJson = (string)($form->form_fields ?? '');
449 + if ($fieldsJson === '') {
450 + return false;
451 + }
452 +
453 + $fields = json_decode($fieldsJson, true);
454 + if (!is_array($fields)) {
455 + return false;
456 + }
457 +
458 + return (bool)ArrayHelper::get($fields, 'stepsWrapper');
459 + }
460 +
461 + public static function hasFormElement($formId, $elementName)
462 + {
463 + $form = Form::find($formId);
464 + $fieldsJson = $form->form_fields;
465 +
466 + return false != strpos($fieldsJson, '"element":"' . $elementName . '"');
467 + }
468 +
469 + public static function isUniqueValidation($validation, $field, $formData, $fields, $form)
470 + {
471 + if ('yes' == ArrayHelper::get($field, 'raw.settings.is_unique')) {
472 + $fieldName = ArrayHelper::get($field, 'name');
473 + if ($inputValue = ArrayHelper::get($formData, $fieldName)) {
474 + $exist = EntryDetails::where('form_id', $form->id)
475 + ->where('field_name', $fieldName)
476 + ->where('field_value', $inputValue)
477 + ->exists();
478 +
479 + // if form has pending payment then the value doesn't exist in EntryDetails table
480 + // further checking on Submission table if the value exists
481 + if (!$exist && $form->has_payment) {
482 + $allSubmission = Submission::where('form_id', $form->id)->get()->toArray();
483 +
484 + foreach ($allSubmission as $submission) {
485 + $response = json_decode(ArrayHelper::get($submission, 'response'), true);
486 + $exist = $inputValue == ArrayHelper::get($response, $fieldName);
487 + }
488 + }
489 +
490 + if ($exist) {
491 + $typeName = ArrayHelper::get($field, 'element', 'input_text');
492 + return [
493 + 'unique' => apply_filters('fluentform/validation_message_unique_' . $typeName,
494 + ArrayHelper::get($field, 'raw.settings.unique_validation_message'), $field),
495 + ];
496 + }
497 + }
498 + }
499 +
500 + return $validation;
501 + }
502 +
503 +
504 + public static function hasPartialEntries($formId)
505 + {
506 + static $cache = [];
507 + if (isset($cache[$formId])) {
508 + return $cache[$formId];
509 + }
510 +
511 + $cache[$formId] = 'yes' == static::getFormMeta($formId, 'form_save_state_status');
512 +
513 + return $cache[$formId];
514 + }
515 +
516 + public static function getNumericFormatters()
517 + {
518 + $data = [
519 + 'none' => [
520 + 'value' => '',
521 + 'label' => 'None',
522 + ],
523 + 'comma_dot_style' => [
524 + 'value' => 'comma_dot_style',
525 + 'label' => __('US Style with Decimal (EX: 123,456.00)', 'fluentform'),
526 + 'settings' => [
527 + 'decimal' => '.',
528 + 'separator' => ',',
529 + 'precision' => 2,
530 + 'symbol' => '',
531 + ],
532 + ],
533 + 'dot_comma_style_zero' => [
534 + 'value' => 'dot_comma_style_zero',
535 + 'label' => __('US Style without Decimal (Ex: 123,456,789)', 'fluentform'),
536 + 'settings' => [
537 + 'decimal' => '.',
538 + 'separator' => ',',
539 + 'precision' => 0,
540 + 'symbol' => '',
541 + ],
542 + ],
543 + 'dot_comma_style' => [
544 + 'value' => 'dot_comma_style',
545 + 'label' => __('EU Style with Decimal (Ex: 123.456,00)', 'fluentform'),
546 + 'settings' => [
547 + 'decimal' => ',',
548 + 'separator' => '.',
549 + 'precision' => 2,
550 + 'symbol' => '',
551 + ],
552 + ],
553 + 'comma_dot_style_zero' => [
554 + 'value' => 'comma_dot_style_zero',
555 + 'label' => __('EU Style without Decimal (EX: 123.456.789)', 'fluentform'),
556 + 'settings' => [
557 + 'decimal' => ',',
558 + 'separator' => '.',
559 + 'precision' => 0,
560 + 'symbol' => '',
561 + ],
562 + ],
563 + ];
564 +
565 + $data = apply_filters_deprecated(
566 + 'fluentform_numeric_styles',
567 + [
568 + $data
569 + ],
570 + FLUENTFORM_FRAMEWORK_UPGRADE,
571 + 'fluentform/numeric_styles',
572 + 'Use fluentform/numeric_styles instead of fluentform_numeric_styles.'
573 + );
574 +
575 + return apply_filters('fluentform/numeric_styles', $data);
576 + }
577 +
578 + public static function getNumericValue($input, $formatterName)
579 + {
580 + $formatters = static::getNumericFormatters();
581 + if (empty($formatters[$formatterName]['settings'])) {
582 + return $input;
583 + }
584 + $settings = $formatters[$formatterName]['settings'];
585 + $number = floatval(str_replace($settings['decimal'], '.',
586 + preg_replace('/[^-?\d' . preg_quote($settings['decimal']) . ']/', '', $input)));
587 +
588 + return number_format($number, $settings['precision'], '.', '');
589 + }
590 +
591 + public static function getNumericFormatted($input, $formatterName)
592 + {
593 + if (!is_numeric($input)) {
594 + return $input;
595 + }
596 + $formatters = static::getNumericFormatters();
597 + if (empty($formatters[$formatterName]['settings'])) {
598 + return $input;
599 + }
600 + $settings = $formatters[$formatterName]['settings'];
601 +
602 + return number_format($input, $settings['precision'], $settings['decimal'], $settings['separator']);
603 + }
604 +
605 + public static function getDuplicateFieldNames($fields)
606 + {
607 + $fields = json_decode($fields, true);
608 + $items = $fields['fields'];
609 + $inputNames = static::getFieldNamesStatuses($items);
610 + $uniqueNames = array_unique($inputNames);
611 +
612 + if (count($inputNames) == count($uniqueNames)) {
613 + return [];
614 + }
615 +
616 + return array_diff_assoc($inputNames, $uniqueNames);
617 + }
618 +
619 + protected static function getFieldNamesStatuses($fields)
620 + {
621 + $names = [];
622 +
623 + foreach ($fields as $field) {
624 + if ('container' == ArrayHelper::get($field, 'element')) {
625 + $columns = ArrayHelper::get($field, 'columns', []);
626 + foreach ($columns as $column) {
627 + $columnInputs = static::getFieldNamesStatuses(ArrayHelper::get($column, 'fields', []));
628 + $names = array_merge($names, $columnInputs);
629 + }
630 + } else {
631 + if ($name = ArrayHelper::get($field, 'attributes.name')) {
632 + $names[] = $name;
633 + }
634 + }
635 + }
636 +
637 + return $names;
638 + }
639 +
640 + public static function isConversionForm($formId)
641 + {
642 + static $cache = [];
643 + if (isset($cache[$formId])) {
644 + return $cache[$formId];
645 + }
646 +
647 + $cache[$formId] = 'yes' == static::getFormMeta($formId, 'is_conversion_form');
648 +
649 + return $cache[$formId];
650 + }
651 +
652 + public static function getPreviewUrl($formId, $type = '')
653 + {
654 + if ('conversational' == $type) {
655 + return static::getConversionUrl($formId);
656 + } elseif ('classic' == $type) {
657 + return site_url('?fluent_forms_pages=1&design_mode=1&preview_id=' . $formId) . '#ff_preview';
658 + } else {
659 + if (static::isConversionForm($formId)) {
660 + return static::getConversionUrl($formId);
661 + }
662 + }
663 +
664 + return site_url('?fluent_forms_pages=1&design_mode=1&preview_id=' . $formId) . '#ff_preview';
665 + }
666 +
667 + public static function getFormAdminPermalink($route, $form)
668 + {
669 + $baseUrl = admin_url('admin.php?page=fluent_forms');
670 +
671 + return $baseUrl . '&route=' . $route . '&form_id=' . $form->id;
672 + }
673 +
674 + public static function getFormSettingsUrl($form)
675 + {
676 + $baseUrl = admin_url('admin.php?page=fluent_forms');
677 +
678 + return $baseUrl . '&form_id=' . $form->id . '&route=settings&sub_route=form_settings#basic_settings';
679 + }
680 +
681 + private static function getConversionUrl($formId)
682 + {
683 + $meta = static::getFormMeta($formId, 'ffc_form_settings_meta', []);
684 + $key = ArrayHelper::get($meta, 'share_key', '');
685 +
686 + $slug = apply_filters_deprecated(
687 + 'fluentform_conversational_url_slug',
688 + [
689 + 'fluent-form'
690 + ],
691 + FLUENTFORM_FRAMEWORK_UPGRADE,
692 + 'fluentform/conversational_url_slug',
693 + 'Use fluentform/conversational_url_slug instead of fluentform_conversational_url_slug.'
694 + );
695 +
696 + $paramKey = apply_filters('fluentform/conversational_url_slug', $slug);
697 +
698 + if ('form' == $paramKey) {
699 + $paramKey = 'fluent-form';
700 + }
701 + if ($key) {
702 + return static::getFrontendFacingUrl('?' . $paramKey . '=' . $formId . '&form=' . $key);
703 + }
704 + return static::getFrontendFacingUrl('?' . $paramKey . '=' . $formId);
705 + }
706 +
707 + public static function fileUploadLocations()
708 + {
709 + $locations = [
710 + [
711 + 'value' => 'default',
712 + 'label' => __('Fluent Forms Default', 'fluentform'),
713 + ],
714 + [
715 + 'value' => 'wp_media',
716 + 'label' => __('Media Library', 'fluentform'),
717 + ],
718 + ];
719 +
720 + $locations = apply_filters_deprecated(
721 + 'fluentform_file_upload_options',
722 + [
723 + $locations
724 + ],
725 + FLUENTFORM_FRAMEWORK_UPGRADE,
726 + 'fluentform/file_upload_options',
727 + 'Use fluentform/file_upload_options instead of fluentform_file_upload_options'
728 + );
729 +
730 + return apply_filters('fluentform/file_upload_options', $locations);
731 + }
732 +
733 + public static function unreadCount($formId)
734 + {
735 + return Submission::where('status', 'unread')
736 + ->where('form_id', $formId)
737 + ->count();
738 + }
739 +
740 + public static function getForms()
741 + {
742 + $ff_list = Form::select(['id', 'title'])->orderBy('id', 'DESC')->get();
743 + $forms = [];
744 +
745 + if ($ff_list) {
746 + $forms[0] = esc_html__('Select a Fluent Forms', 'fluentform');
747 + foreach ($ff_list as $form) {
748 + $forms[$form->id] = esc_html($form->title) . ' (' . $form->id . ')';
749 + }
750 + } else {
751 + $forms[0] = esc_html__('Create a Form First', 'fluentform');
752 + }
753 +
754 + return $forms;
755 + }
756 +
757 + public static function replaceBrTag($content, $with = '')
758 + {
759 + if (is_array($content)) {
760 + foreach ($content as $key => $value) {
761 + $content[$key] = static::replaceBrTag($value, $with);
762 + }
763 + } elseif (static::hasBrTag($content)) {
764 + $content = str_replace('<br />', $with, $content);
765 + }
766 +
767 + return $content;
768 + }
769 +
770 + public static function hasBrTag($content)
771 + {
772 + return is_string($content) && false !== strpos($content, '<br />');
773 + }
774 +
775 + public static function sanitizeForCSV($content)
776 + {
777 + $formulas = ['=', '-', '+', '@', "\t", "\r"];
778 +
779 + $formulas = apply_filters('fluentform/csv_sanitize_formulas', $formulas);
780 +
781 + if (Str::startsWith($content, $formulas)) {
782 + $content = "'" . $content;
783 + }
784 +
785 + return $content;
786 + }
787 +
788 + public static function sanitizeOrderValue($orderType = '')
789 + {
790 + $orderBys = ['ASC', 'DESC'];
791 +
792 + $orderType = trim(strtoupper($orderType));
793 +
794 + return in_array($orderType, $orderBys) ? $orderType : 'DESC';
795 + }
796 +
797 + public static function getForm($id)
798 + {
799 + return Form::where('id', $id)->first();
800 + }
801 +
802 + public static function shouldHidePassword($formId)
803 + {
804 + $isTruncate = apply_filters_deprecated(
805 + 'fluentform_truncate_password_values',
806 + [
807 + true,
808 + $formId
809 + ],
810 + FLUENTFORM_FRAMEWORK_UPGRADE,
811 + 'fluentform/truncate_password_values',
812 + 'Use fluentform/truncate_password_values instead of fluentform_truncate_password_values.'
813 + );
814 +
815 + return apply_filters('fluentform/truncate_password_values', $isTruncate, $formId) &&
816 + (
817 + (defined('FLUENTFORM_RENDERING_ENTRIES') && FLUENTFORM_RENDERING_ENTRIES) ||
818 + (defined('FLUENTFORM_RENDERING_ENTRY') && FLUENTFORM_RENDERING_ENTRY) ||
819 + (defined('FLUENTFORM_EXPORTING_ENTRIES') && FLUENTFORM_EXPORTING_ENTRIES)
820 + );
821 + }
822 +
823 + // make tabular-grid value markdown format
824 + public static function getTabularGridFormatValue(
825 + $girdData,
826 + $field,
827 + $rowJoiner = '<br />',
828 + $colJoiner = ', ',
829 + $type = ''
830 + )
831 + {
832 + if (!$girdData || !$field) {
833 + return '';
834 + }
835 + $girdRows = ArrayHelper::get($field, 'raw.settings.grid_rows', []);
836 + $girdRows = fluentFormSanitizer($girdRows);
837 + $girdCols = ArrayHelper::get($field, 'raw.settings.grid_columns', []);
838 + $girdCols = fluentFormSanitizer($girdCols);
839 +
840 + $value = '';
841 + $lastRow = key(array_slice($girdData, -1, 1, true));
842 + foreach ($girdData as $row => $column) {
843 + $_row = $row;
844 + if ($girdRows && isset($girdRows[$row])) {
845 + $row = $girdRows[$row];
846 + }
847 + if ('markdown' === $type) {
848 + $value .= '- *' . $row . '* : ';
849 + } else {
850 + $value .= $row . ': ';
851 + }
852 + if (is_array($column)) {
853 + foreach ($column as $index => $item) {
854 + $_colJoiner = $colJoiner;
855 + if ($girdCols && isset($girdCols[$item])) {
856 + $item = $girdCols[$item];
857 + }
858 + if ($index == (count($column) - 1)) {
859 + $_colJoiner = '';
860 + }
861 + $value .= $item . $_colJoiner;
862 + }
863 + } else {
864 + if ($girdCols && isset($girdCols[$column])) {
865 + $column = $girdCols[$column];
866 + }
867 + $value .= $column;
868 + }
869 + if ($_row != $lastRow) {
870 + $value .= $rowJoiner;
871 + }
872 + }
873 +
874 + return $value;
875 + }
876 +
877 + public static function getInputNameFromShortCode($value)
878 + {
879 + preg_match('/{+(.*?)}/', $value, $matches);
880 + if ($matches && false !== strpos($matches[1], 'inputs.')) {
881 + return substr($matches[1], strlen('inputs.'));
882 + }
883 +
884 + return '';
885 + }
886 +
887 + public static function getRestInfo()
888 + {
889 + $config = wpFluentForm('config');
890 +
891 + $namespace = $config->get('app.rest_namespace');
892 + $version = $config->get('app.rest_version');
893 + $restUrl = rest_url($namespace . '/' . $version);
894 + $restUrl = rtrim($restUrl, '/\\');
895 +
896 + return [
897 + 'base_url' => esc_url_raw(rest_url()),
898 + 'url' => $restUrl,
899 + 'nonce' => wp_create_nonce('wp_rest'),
900 + 'namespace' => $namespace,
901 + 'version' => $version,
902 + ];
903 + }
904 +
905 + public static function getLogInitiator($action, $type = 'log')
906 + {
907 + if ('log' === $type) {
908 + $title = ucwords(implode(' ', preg_split('/(?=[A-Z])/', $action)));
909 + } else {
910 + $title = ucwords(
911 + str_replace(
912 + ['fluentform/integration_notify_', 'fluentform_', '_notification_feed', '_'],
913 + ['', '', '', ' '],
914 + $action
915 + )
916 + );
917 + }
918 +
919 + return $title;
920 + }
921 +
922 + public static function getIpinfo()
923 + {
924 + return ArrayHelper::get(get_option('_fluentform_global_form_settings'), 'misc.geo_provider_token');
925 + }
926 +
927 + public static function isAutoloadCaptchaEnabled()
928 + {
929 + return ArrayHelper::get(get_option('_fluentform_global_form_settings'), 'misc.autoload_captcha');
930 + }
931 +
932 + public static function isAutosaveEnabled()
933 + {
934 + $autosaveEnabled = ArrayHelper::get(get_option('_fluentform_global_form_settings'), 'misc.autosave_enabled', 'no');
935 + return $autosaveEnabled === 'yes';
936 + }
937 +
938 + public static function maybeDecryptUrl($url)
939 + {
940 + $uploadDir = str_replace('/', '\/', FLUENTFORM_UPLOAD_DIR . '/temp');
941 + $pattern = "/(?<={$uploadDir}\/).*$/";
942 + preg_match($pattern, $url, $match);
943 + if (!empty($match)) {
944 + $url = str_replace($match[0], Protector::decrypt($match[0]), $url);
945 + }
946 + return $url;
947 + }
948 +
949 + public static function arrayFilterRecursive($arrayItems)
950 + {
951 + foreach ($arrayItems as $key => $item) {
952 + is_array($item) && $arrayItems[$key] = self::arrayFilterRecursive($item);
953 + if (empty($arrayItems[$key])) {
954 + unset($arrayItems[$key]);
955 + }
956 + }
957 + return $arrayItems;
958 + }
959 +
960 + public static function isBlockEditor()
961 + {
962 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Checking REST API context
963 + return defined('REST_REQUEST') && REST_REQUEST && !empty($_REQUEST['context']) && $_REQUEST['context'] === 'edit';
964 + }
965 +
966 + public static function resolveValidationRulesGlobalOption(&$field)
967 + {
968 + if (isset($field['fields']) && is_array($field['fields'])) {
969 + foreach ($field['fields'] as &$subField) {
970 + static::resolveValidationRulesGlobalOption($subField);
971 + }
972 + } else {
973 + if (ArrayHelper::get($field, 'settings.validation_rules')) {
974 + foreach ($field['settings']['validation_rules'] as $key => &$rule) {
975 + if (!isset($rule['global'])) {
976 + $rule['global'] = false;
977 + }
978 + $rule['global_message'] = static::getGlobalDefaultMessage($key);
979 + }
980 + }
981 + }
982 + }
983 +
984 + /**
985 + * Validate form input value against database values
986 + *
987 + * @param $field array Form Field
988 + * @param $formData array From Data
989 + * @param $form object From
990 + * @param $fieldName string optional
991 + * @param $inputValue mixed optional
992 + *
993 + * @return string
994 + * Return Error message on fail. Otherwise, return empty string
995 + */
996 + public static function validateInput($field, $formData, $form, $fieldName = '', $inputValue = [])
997 + {
998 + $error = '';
999 + if (!$fieldName) {
1000 + $fieldName = ArrayHelper::get($field, 'name');
1001 + }
1002 + if (!$fieldName) {
1003 + return $error;
1004 + }
1005 + if (!$inputValue) {
1006 + $inputValue = ArrayHelper::get($formData, $fieldName);
1007 + }
1008 + if ($inputValue) {
1009 + $rawField = ArrayHelper::get($field, 'raw');
1010 + if (!$rawField) {
1011 + $rawField = $field;
1012 + }
1013 + $fieldType = ArrayHelper::get($rawField, 'element');
1014 + $rawField = apply_filters('fluentform/rendering_field_data_' . $fieldType, $rawField, $form);
1015 + $options = [];
1016 + if ("net_promoter_score" === $fieldType) {
1017 + $options = array_flip(ArrayHelper::get($rawField, 'options', []));
1018 + } elseif ('ratings' == $fieldType) {
1019 + $options = array_keys(ArrayHelper::get($rawField, 'options', []));
1020 + } elseif ('gdpr_agreement' == $fieldType) {
1021 + $options = ['on'];
1022 + } elseif ('terms_and_condition' == $fieldType) {
1023 + $options = ['on', 'off'];
1024 + } elseif (in_array($fieldType, ['input_radio', 'select', 'input_checkbox'])) {
1025 + if (ArrayHelper::isTrue($rawField, 'attributes.multiple')) {
1026 + $fieldType = 'multi_select';
1027 + }
1028 + $options = array_column(
1029 + ArrayHelper::get($rawField, 'settings.advanced_options', []),
1030 + 'value'
1031 + );
1032 +
1033 + // Add field-specific __ff_other__ to options if "Other" option is enabled
1034 + if (in_array($fieldType, ['input_checkbox', 'input_radio']) &&
1035 + ArrayHelper::get($rawField, 'settings.enable_other_option') === 'yes') {
1036 + $fieldName = sanitize_key(str_replace(['[', ']'], '', ArrayHelper::get($rawField, 'attributes.name', '')));
1037 + $options[] = '__ff_other_' . $fieldName . '__';
1038 + }
1039 + } elseif ("dynamic_field" == $fieldType) {
1040 + $dynamicFetchValue = 'yes' == ArrayHelper::get($rawField, 'settings.dynamic_fetch');
1041 + if ($dynamicFetchValue) {
1042 + $rawField = apply_filters('fluentform/dynamic_field_re_fetch_result_and_resolve_value', $rawField);
1043 + }
1044 + $dfElementType = ArrayHelper::get($rawField, 'attributes.type');
1045 + if (in_array($dfElementType, ['radio', 'select', 'checkbox'])) {
1046 + $fieldType = 'dynamic_field_options';
1047 + $options = array_column(
1048 + ArrayHelper::get($rawField, 'settings.advanced_options', []),
1049 + 'value'
1050 + );
1051 + }
1052 + }
1053 +
1054 + if ($options) {
1055 + $options = array_map('sanitize_text_field', $options);
1056 + }
1057 +
1058 + $isValid = true;
1059 + switch ($fieldType) {
1060 + case 'input_radio':
1061 + case 'select':
1062 + case 'net_promoter_score':
1063 + case 'ratings':
1064 + case 'gdpr_agreement':
1065 + case 'terms_and_condition':
1066 + case 'input_checkbox':
1067 + case 'multi_select':
1068 + case 'dynamic_field_options':
1069 +
1070 + $skipValidationInputsWithOptions = apply_filters('fluentform/skip_validation_inputs_with_options', false, $fieldType, $form, $formData);
1071 + if ($skipValidationInputsWithOptions) {
1072 + break;
1073 + }
1074 + if (is_array($inputValue)) {
1075 + // Handle field-specific "Other" options for checkboxes
1076 + $filteredValues = array_filter($inputValue, function($value) {
1077 + // Skip field-specific other values and processed other values
1078 + return !preg_match('/^__ff_other_.*__$/', $value) &&
1079 + !preg_match('/^Other:\s/', $value);
1080 + });
1081 + $isValid = array_diff($filteredValues, $options);
1082 + $isValid = empty($isValid);
1083 + } else {
1084 + // Handle field-specific "Other" option for single values
1085 + if (preg_match('/^__ff_other_.*__$/', $inputValue) ||
1086 + preg_match('/^Other:\s/', $inputValue)) {
1087 + $isValid = true;
1088 + } else {
1089 + $isValid = in_array($inputValue, $options);
1090 + }
1091 + }
1092 + break;
1093 + case 'input_number':
1094 + if (is_array($inputValue)) {
1095 + $hasNonNumricValue = in_array(false, array_map('is_numeric', $inputValue));
1096 + if ($hasNonNumricValue) {
1097 + $isValid = false;
1098 + }
1099 + } else {
1100 + $isValid = is_numeric($inputValue);
1101 + }
1102 + break;
1103 + case 'select_country':
1104 + $fieldData = ArrayHelper::get($field, 'raw');
1105 + $data = (new SelectCountry())->loadCountries($fieldData);
1106 + $validCountries = ArrayHelper::get($fieldData, 'settings.country_list.priority_based', []);
1107 + $validCountries = array_merge($validCountries, array_keys(ArrayHelper::get($data, 'options')));
1108 + $isValid = in_array($inputValue, $validCountries);
1109 + break;
1110 + case 'repeater_field':
1111 + case 'repeater_container':
1112 + foreach (ArrayHelper::get($rawField, 'fields', []) as $index => $repeaterField) {
1113 + $repeaterFieldValue = array_filter(array_column($inputValue, $index));
1114 + if ($repeaterFieldValue && $error = static::validateInput($repeaterField, $formData, $form,
1115 + $fieldName, $repeaterFieldValue)) {
1116 + $isValid = false;
1117 + break;
1118 + }
1119 + }
1120 + break;
1121 + case 'tabular_grid':
1122 + $rows = array_keys(ArrayHelper::get($rawField, 'settings.grid_rows', []));
1123 + $rows = array_map(function ($row) {
1124 + return trim(sanitize_text_field($row));
1125 + }, $rows);
1126 +
1127 + $submittedRows = array_keys(ArrayHelper::get($formData, $fieldName, []));
1128 + $submittedRows = array_map('trim', $submittedRows);
1129 +
1130 + $rowDiff = array_diff($submittedRows, $rows);
1131 +
1132 + $isValid = empty($rowDiff);
1133 + if ($isValid) {
1134 + $columns = array_keys(ArrayHelper::get($rawField, 'settings.grid_columns', []));
1135 + $columns = array_map(function ($column) {
1136 + return trim(sanitize_text_field($column));
1137 + }, $columns);
1138 + $submittedCols = ArrayHelper::flatten(ArrayHelper::get($formData, $fieldName, []));
1139 + $submittedCols = array_map('trim', $submittedCols);
1140 + $colDiff = array_diff($submittedCols, $columns);
1141 + $isValid = empty($colDiff);
1142 + }
1143 + break;
1144 + default:
1145 + break;
1146 + }
1147 + if (!$isValid) {
1148 + $error = __('The given data was invalid', 'fluentform');
1149 + }
1150 + }
1151 + return $error;
1152 + }
1153 +
1154 + public static function getWhiteListedFields($formId)
1155 + {
1156 + $whiteListedFields = [
1157 + '__fluent_form_embded_post_id',
1158 + '_fluentform_' . $formId . '_fluentformnonce',
1159 + '_wp_http_referer',
1160 + 'g-recaptcha-response',
1161 + 'h-captcha-response',
1162 + 'cf-turnstile-response',
1163 + '__stripe_payment_method_id',
1164 + '__ff_all_applied_coupons',
1165 + '__entry_intermediate_hash',
1166 + '__square_payment_method_id',
1167 + '__square_verify_buyer_id',
1168 + 'ct_bot_detector_event_token',
1169 + 'ff_ct_form_load_time'
1170 + ];
1171 +
1172 + return apply_filters('fluentform/white_listed_fields', $whiteListedFields, $formId);
1173 + }
1174 +
1175 + /**
1176 + * Shortcode parse on validation message
1177 + * @param string $message
1178 + * @param object $form
1179 + * @param string $fieldName
1180 + * @return string
1181 + */
1182 + public static function shortCodeParseOnValidationMessage($message, $form, $fieldName)
1183 + {
1184 + // Return early if form is null to prevent errors
1185 + if ($form === null) {
1186 + return $message;
1187 + }
1188 +
1189 + // For validation message there is no entry & form data
1190 + // Add 'current_field' name as data array to resolve {labels.current_field} shortcode if it has
1191 + return ShortCodeParser::parse(
1192 + $message,
1193 + (object)['response' => "", 'form_id' => $form->id],
1194 + ['current_field' => $fieldName],
1195 + $form
1196 + );
1197 + }
1198 +
1199 + public static function getAjaxUrl()
1200 + {
1201 + return apply_filters('fluentform/ajax_url', admin_url('admin-ajax.php'));
1202 + }
1203 +
1204 + public static function getDefaultDateTimeFormatForMoment()
1205 + {
1206 + $phpFormat = get_option('date_format') . ' ' . get_option('time_format');
1207 +
1208 + $replacements = [
1209 + 'A' => 'A', // for the sake of escaping below
1210 + 'a' => 'a', // for the sake of escaping below
1211 + 'B' => '', // Swatch internet time (.beats), no equivalent
1212 + 'c' => 'YYYY-MM-DD[T]HH:mm:ssZ', // ISO 8601
1213 + 'D' => 'ddd',
1214 + 'd' => 'DD',
1215 + 'e' => 'zz', // deprecated since version 1.6.0 of moment.js
1216 + 'F' => 'MMMM',
1217 + 'G' => 'H',
1218 + 'g' => 'h',
1219 + 'H' => 'HH',
1220 + 'h' => 'hh',
1221 + 'I' => '', // Daylight Saving Time? => moment().isDST();
1222 + 'i' => 'mm',
1223 + 'j' => 'D',
1224 + 'L' => '', // Leap year? => moment().isLeapYear();
1225 + 'l' => 'dddd',
1226 + 'M' => 'MMM',
1227 + 'm' => 'MM',
1228 + 'N' => 'E',
1229 + 'n' => 'M',
1230 + 'O' => 'ZZ',
1231 + 'o' => 'YYYY',
1232 + 'P' => 'Z',
1233 + 'r' => 'ddd, DD MMM YYYY HH:mm:ss ZZ', // RFC 2822
1234 + 'S' => 'o',
1235 + 's' => 'ss',
1236 + 'T' => 'z', // deprecated since version 1.6.0 of moment.js
1237 + 't' => '', // days in the month => moment().daysInMonth();
1238 + 'U' => 'X',
1239 + 'u' => 'SSSSSS', // microseconds
1240 + 'v' => 'SSS', // milliseconds (from PHP 7.0.0)
1241 + 'W' => 'W', // for the sake of escaping below
1242 + 'w' => 'e',
1243 + 'Y' => 'YYYY',
1244 + 'y' => 'YY',
1245 + 'Z' => '', // time zone offset in minutes => moment().zone();
1246 + 'z' => 'DDD',
1247 + ];
1248 +
1249 + // Converts escaped characters.
1250 + foreach ($replacements as $from => $to) {
1251 + $replacements['\\' . $from] = '[' . $from . ']';
1252 + }
1253 +
1254 + $format = strtr($phpFormat, $replacements);
1255 +
1256 + return apply_filters('fluentform/moment_date_time_format', $format);
1257 + }
1258 +
1259 + public static function isDefaultWPDateEnabled()
1260 + {
1261 + $globalSettings = get_option('_fluentform_global_form_settings');
1262 + return 'wp_default' === ArrayHelper::get($globalSettings, 'misc.default_admin_date_time');
1263 + }
1264 +
1265 + public static function isPaymentCompatible()
1266 + {
1267 + if (!self::hasPro()) {
1268 + return true;
1269 + } else {
1270 + return version_compare(FLUENTFORMPRO_VERSION, FLUENTFORM_MINIMUM_PRO_VERSION, '>=');
1271 + }
1272 + }
1273 +
1274 + /**
1275 + * Determine pro payment script is compatible or not
1276 + * Script is compatible if pro version is greater than or equal to 6.0.4
1277 + *
1278 + * @return bool
1279 + */
1280 + public static function isProPaymentScriptCompatible()
1281 + {
1282 + if (self::hasPro()) {
1283 + return version_compare(FLUENTFORMPRO_VERSION, '6.0.4', '>=');
1284 + }
1285 + return false;
1286 + }
1287 +
1288 + public static function hasPro()
1289 + {
1290 + return defined('FLUENTFORMPRO');
1291 + }
1292 +
1293 + public static function getLandingPageEnabledForms()
1294 + {
1295 + if (class_exists(\FluentFormPro\classes\SharePage\SharePage::class)) {
1296 + if (method_exists(\FluentFormPro\classes\SharePage\SharePage::class, 'getLandingPageFormIds')) {
1297 + $sharePage = new \FluentFormPro\classes\SharePage\SharePage();
1298 + return $sharePage->getLandingPageFormIds();
1299 + }
1300 + }
1301 + return [];
1302 + }
1303 +
1304 + public static function sanitizeArrayKeysAndValues($values)
1305 + {
1306 + if (is_array($values)) {
1307 + $sanitized = [];
1308 + foreach ($values as $key => $value) {
1309 + $trimmedKey = sanitize_text_field(trim($key));
1310 + $trimmedValue = sanitize_text_field(trim($value));
1311 + $sanitized[$trimmedKey] = $trimmedValue;
1312 + }
1313 + return $sanitized;
1314 + }
1315 + return sanitize_text_field(trim($values));
1316 + }
1317 + public static function getFrontendFacingUrl($args = '')
1318 + {
1319 + return home_url($args);
1320 + }
1321 +
1322 + public static function getCountryCodeFromHeaders()
1323 + {
1324 + $headers = [
1325 + // Cloudflare (most common)
1326 + 'HTTP_CF_IPCOUNTRY',
1327 + 'CF-IPCountry',
1328 +
1329 + // AWS CloudFront (widely used)
1330 + 'HTTP_CLOUDFRONT_VIEWER_COUNTRY',
1331 + 'CloudFront-Viewer-Country',
1332 +
1333 + // Common standard headers
1334 + 'HTTP_X_COUNTRY_CODE',
1335 + 'X-Country-Code',
1336 + 'HTTP_X_FORWARDED_COUNTRY',
1337 + 'X-Forwarded-Country',
1338 +
1339 + // GeoIP (used by many systems)
1340 + 'HTTP_GEOIP_COUNTRY_CODE',
1341 + 'GEOIP_COUNTRY_CODE',
1342 + 'HTTP_X_GEOIP_COUNTRY',
1343 + 'X-GeoIP-Country',
1344 +
1345 + // General purpose country headers
1346 + 'HTTP_X_COUNTRY',
1347 + 'X-Country',
1348 + 'HTTP_X_COUNTRY_ISO',
1349 + 'X-Country-ISO'
1350 + ];
1351 +
1352 + foreach ($headers as $header) {
1353 + // Try directly from $_SERVER
1354 + if (isset($_SERVER[$header])) {
1355 + // phpcs:ignore WordPress.Security.ValidatedSanitizedInput -- Country code from CDN/proxy header, validated below
1356 + $code = trim(sanitize_text_field(wp_unslash($_SERVER[$header])));
1357 + } // Try with HTTP_ prefix if not already present
1358 + elseif (strpos($header, 'HTTP_') !== 0) {
1359 + $httpHeader = 'HTTP_' . str_replace('-', '_', strtoupper($header));
1360 + if (isset($_SERVER[$httpHeader])) {
1361 + // phpcs:ignore WordPress.Security.ValidatedSanitizedInput -- Country code from CDN/proxy header, validated below
1362 + $code = trim(sanitize_text_field(wp_unslash($_SERVER[$httpHeader])));
1363 + } else {
1364 + continue;
1365 + }
1366 + } else {
1367 + continue;
1368 + }
1369 +
1370 + // Basic validation - should be 2-letter country code
1371 + if (!empty($code) && is_string($code) && strlen($code) === 2 && ctype_alpha($code) && $code !== 'XX') {
1372 + return strtoupper($code);
1373 + }
1374 + }
1375 +
1376 + return null;
1377 + }
1378 +
1379 + /**
1380 + * Fixes PHP Object Injection Vulnerability
1381 + * @param $data
1382 + * @return mixed
1383 + */
1384 + public static function safeUnserialize($data)
1385 + {
1386 + if (is_serialized($data)) { // Don't attempt to unserialize data that wasn't serialized going in.
1387 + return @unserialize(trim($data), ['allowed_classes' => false]);
1388 + }
1389 + return $data;
1390 + }
1391 +
1392 + /**
1393 + * If elementor editor is open
1394 + * @return bool
1395 + */
1396 + public static function isElementorEditor()
1397 + {
1398 + return defined('ELEMENTOR_VERSION') &&
1399 + class_exists('\Elementor\Plugin') &&
1400 + isset(\Elementor\Plugin::$instance) &&
1401 + \Elementor\Plugin::$instance->editor->is_edit_mode();
1402 + }
1403 +
1404 + /**
1405 + * Check if we're in block editor context (Site Editor, Template Editor, or Post/Page Editor)
1406 + * Covers all Gutenberg block editor contexts including mobile/tablet preview iframes
1407 + * @return bool
1408 + */
1409 + public static function isSiteEditor()
1410 + {
1411 + if (!is_admin() || !function_exists('get_current_screen')) {
1412 + return false;
1413 + }
1414 +
1415 + $screen = get_current_screen();
1416 +
1417 + // Check for Site Editor and Template Editor contexts
1418 + if ($screen && in_array($screen->base, ['site-editor', 'edit-site', 'appearance_page_gutenberg-edit-site'], true )) {
1419 + return true;
1420 + }
1421 +
1422 + // Check for Post/Page block editor contexts
1423 + if ($screen && in_array($screen->base, ['post', 'page'], true) && $screen->is_block_editor()) {
1424 + return true;
1425 + }
1426 +
1427 + // Check for custom post types with block editor
1428 + if ($screen && $screen->is_block_editor()) {
1429 + return true;
1430 + }
1431 +
1432 + // Fallback checks for various block editor contexts
1433 + // phpcs:ignore WordPress.Security.ValidatedSanitizedInput -- REQUEST_URI used for string comparison only
1434 + $request_uri = isset($_SERVER['REQUEST_URI']) ? sanitize_text_field(wp_unslash($_SERVER['REQUEST_URI'])) : '';
1435 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Checking block editor context
1436 + return isset( $_GET['_wp-find-template'] ) ||
1437 + strpos( $request_uri, 'site-editor.php' ) !== false ||
1438 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Checking REST API context
1439 + (defined('REST_REQUEST') && REST_REQUEST && !empty($_REQUEST['context']) && $_REQUEST['context'] === 'edit');
1440 + }
1441 + }
1442 +