Diff: STRATO-apps/wordpress_03/app/wp-content/plugins/fluentform/app/Helpers/Helper.php
Keine Baseline-Datei – Diff nur gegen leer.
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(['[', ']', '[', ']'], '', $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
+