PluginProbe
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder / 6.2.11
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder v6.2.11
6.2.14 6.2.13 6.2.12 6.2.10 6.2.11 6.2.9 6.2.8 6.2.7 6.2.6 6.2.5 6.2.4 6.2.3 6.2.2 3.6.22 3.6.31 3.6.40 3.6.41 3.6.42 3.6.50 3.6.51 3.6.60 3.6.61 3.6.62 3.6.64 3.6.65 All 196 releases
fluentform / boot / globals.php

globals.php in Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder 6.2.11, at boot/globals.php

578 lines 16.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 defined('ABSPATH') or die;
4
5 use FluentForm\Framework\Helpers\ArrayHelper;
6 use FluentForm\App\Modules\Component\BaseComponent;
7 use FluentForm\App\Services\FormBuilder\EditorShortCode;
8
9 /**
10 ***** DO NOT CALL ANY FUNCTIONS DIRECTLY FROM THIS FILE ******
11 *
12 * This file will be loaded even before the framework is loaded
13 * so the $app is not available here, only declare functions here.
14 */
15
16 //if ('dev' == $app->config->get('app.env')) {
17 // $globalsDevFile = __DIR__ . '/globals_dev.php';
18 //
19 // is_readable($globalsDevFile) && include $globalsDevFile;
20 //}
21
22 if (!function_exists('dd')) {
23 // function dd()
24 // {
25 // foreach (func_get_args() as $arg) {
26 // echo '<pre>';
27 // print_r($arg); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- $value is only used for debugging in development.
28 // echo '</pre>';
29 // }
30 // exit();
31 // }
32 }
33
34 /**
35 * Get fluentform instance or other core modules
36 *
37 * @param string $key
38 *
39 * @return mixed
40 */
41 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound -- Global helper function, part of plugin API
42 function wpFluentForm($key = null)
43 {
44 return \FluentForm\App\App::make($key);
45 }
46
47 /**
48 * Generate URL for static assets
49 *
50 * @param string $path
51 *
52 * @return string
53 */
54 function fluentFormMix($path = '')
55 {
56 return wpFluentForm('url.assets') . ltrim($path, '/');
57 }
58
59 if (! function_exists('wpFluent')) {
60 /**
61 * @return \FluentForm\Framework\Database\Query\Builder|\FluentForm\Framework\Database\Query\WPDBConnection
62 */
63 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound -- Global helper function, part of plugin API
64 function wpFluent()
65 {
66 return wpFluentForm('db');
67 }
68 }
69
70
71 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound -- Global helper function, part of plugin API
72 function wpFluentFormAddComponent(BaseComponent $component)
73 {
74 return $component->_init();
75 }
76
77 /**
78 * Sanitize form inputs recursively.
79 *
80 * @param $input
81 *
82 * @return mixed $input
83 */
84 function fluentFormSanitizer($input, $attribute = null, $fields = [])
85 {
86 if (is_string($input)) {
87 $element = ArrayHelper::get($fields, $attribute . '.element');
88
89 if (in_array($element, ['post_content', 'rich_text_input'])) {
90 return wp_kses_post($input);
91 } elseif ('textarea' === $element) {
92 $input = sanitize_textarea_field($input);
93 } elseif ('input_email' === $element) {
94 $input = strtolower(sanitize_text_field($input));
95 } elseif ('input_url' === $element) {
96 $input = sanitize_url($input);
97 } elseif ('input_password' === $element) {
98 $input = trim($input);
99 } else {
100 $input = sanitize_text_field($input);
101 }
102 } elseif (is_array($input)) {
103 $sanitizedInput = [];
104
105 foreach ($input as $key => &$value) {
106 $key = fluentFormSanitizer($key);
107 // Local var: mutating $attribute here would collapse every sibling
108 // after the first onto a bare key, resolving nested inputs to the wrong element.
109 $childAttribute = $attribute ? $attribute . '[' . $key . ']' : $key;
110
111 $value = fluentFormSanitizer($value, $childAttribute, $fields);
112 $sanitizedInput[$key] = $value;
113 }
114
115 $input = $sanitizedInput;
116 }
117
118 return $input;
119 }
120
121 function fluentFormEditorShortCodes()
122 {
123 $generalShortCodes = [EditorShortCode::getGeneralShortCodes()];
124 /* This filter is deprecated, will be removed soon. */
125 $generalShortCodes = apply_filters('fluentform_editor_shortcodes', $generalShortCodes);
126
127 return apply_filters('fluentform/editor_shortcodes', $generalShortCodes);
128 }
129
130 function fluentFormGetAllEditorShortCodes($form)
131 {
132 $editorShortCodes = EditorShortCode::getShortCodes($form);
133 /* This filter is deprecated and will be removed soon */
134 $editorShortCodes = apply_filters(
135 'fluentform_all_editor_shortcodes',
136 $editorShortCodes,
137 $form
138 );
139 return apply_filters(
140 'fluentform/all_editor_shortcodes',
141 $editorShortCodes,
142 $form
143 );
144 }
145
146 /**
147 * Recursively implode a multi-dimentional array
148 *
149 * @param string $glue
150 * @param array $array
151 *
152 * @return string
153 */
154 function fluentImplodeRecursive($glue, array $array)
155 {
156 $fn = function ($glue, array $array) use (&$fn) {
157 $result = '';
158 foreach ($array as $item) {
159 if (is_array($item)) {
160 $result .= $fn($glue, $item);
161 } else {
162 $result .= $glue . $item;
163 }
164 }
165
166 return $result;
167 };
168
169 return ltrim($fn($glue, $array), $glue);
170 }
171
172 function fluentform_get_active_theme_slug()
173 {
174 $ins = get_option('_ff_ins_by');
175
176 if ($ins) {
177 return sanitize_text_field($ins);
178 }
179
180 if (defined('TEMPLATELY_FILE')) {
181 return 'templately';
182 }
183
184 return get_option('template');
185 }
186
187 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound -- Global helper function, part of plugin API
188 function getFluentFormCountryList()
189 {
190 static $countries = null;
191
192 if (is_null($countries)) {
193 $countries = fluentformLoadFile('/Services/FormBuilder/CountryNames.php');
194 }
195
196 return $countries;
197 }
198
199 function fluentFormWasSubmitted($action = 'fluentform_submit')
200 {
201 return wpFluentForm('request')->get('action') == $action;
202 }
203
204 if (!function_exists('isWpAsyncRequest')) {
205 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound -- Global helper function, part of plugin API
206 function isWpAsyncRequest($action)
207 {
208 return false !== strpos(wpFluentForm('request')->get('action'), $action);
209 }
210 }
211
212 function fluentFormIsHandlingSubmission()
213 {
214 $status = fluentFormWasSubmitted() || isWpAsyncRequest('fluentform_async_request');
215
216 $status = apply_filters_deprecated(
217 'fluentform_is_handling_submission',
218 [
219 $status
220 ],
221 FLUENTFORM_FRAMEWORK_UPGRADE,
222 'fluentform/is_handling_submission',
223 'Use fluentform/is_handling_submission instead of fluentform_is_handling_submission'
224 );
225 return apply_filters('fluentform/is_handling_submission', $status);
226 }
227
228 function fluentform_mb_strpos($haystack, $needle)
229 {
230 if (function_exists('mb_strpos')) {
231 return mb_strpos($haystack, $needle);
232 }
233
234 return strpos($haystack, $needle);
235 }
236
237 function fluentFormHandleScheduledTasks()
238 {
239 $failedActions = wpFluent()->table('ff_scheduled_actions')->where('status', 'failed')->where('retry_count', '<', 4)->get();
240
241 if (count($failedActions)) {
242 $scheduler = wpFluentForm('fluentFormAsyncRequest');
243
244 foreach ($failedActions as $action) {
245 $scheduler->process($action);
246 }
247 }
248
249 $rand = wp_rand(1, 10);
250 if ($rand >= 5) {
251 do_action('fluentform/maybe_scheduled_jobs');
252 }
253 }
254
255 function fluentFormHandleScheduledEmailReport()
256 {
257 \FluentForm\App\Services\Scheduler\Scheduler::processEmailReport();
258 }
259
260 function fluentform_upgrade_url($utmContent = '')
261 {
262 return \FluentForm\App\Helpers\Helper::utmUrl('https://fluentforms.com/pricing/', $utmContent);
263 }
264
265 function fluentform_integrations_url($utmContent = '')
266 {
267 return \FluentForm\App\Helpers\Helper::utmUrl('https://fluentforms.com/integration/', $utmContent);
268 }
269
270 function fluentFormApi($module = 'forms')
271 {
272 if ('forms' == $module) {
273 return new \FluentForm\App\Api\Form();
274 } elseif ('submissions' == $module) {
275 return new \FluentForm\App\Api\Submission();
276 }
277
278 throw new \Exception(esc_html('No Module found with name ' . $module));
279 }
280
281 function fluentFormGetRandomPhoto()
282 {
283 $photos = [
284 'demo_1.jpg',
285 'demo_2.jpg',
286 'demo_3.jpg',
287 'demo_4.jpg',
288 'demo_5.jpg',
289 ];
290
291 $selected = array_rand($photos, 1);
292
293 $photoName = $photos[$selected];
294
295 return fluentformMix('img/conversational/' . $photoName);
296 }
297
298 function fluentFormRender($atts)
299 {
300 $shortcodeDefaults = [
301 'id' => null,
302 'title' => null,
303 'css_classes' => '',
304 'permission' => '',
305 'type' => 'classic',
306 'permission_message' => __('Sorry, You do not have permission to view this form', 'fluentform'),
307 ];
308 $atts = shortcode_atts($shortcodeDefaults, $atts);
309
310 return (new \FluentForm\App\Modules\Component\Component(wpFluentForm()))->renderForm($atts);
311 }
312
313 /**
314 * Print internal content (not user input) without escaping.
315 */
316 function fluentFormPrintUnescapedInternalString($string)
317 {
318 echo $string; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- deprecated function, should remove it later.
319 }
320
321 function fluentform_options_sanitize($options)
322 {
323 return \FluentForm\App\Helpers\Helper::sanitizeAdvancedOptions($options);
324 }
325
326 function fluentform_iframe_srcdoc_sanitize($value)
327 {
328 $tags = wp_kses_allowed_html('post');
329 $tags['style'] = [
330 'types' => [],
331 ];
332 // Check if decoding is necessary
333 if (strpos($value, '&') !== false) {
334 // Decode HTML entities
335 $value = html_entity_decode($value, ENT_QUOTES | ENT_HTML5, 'UTF-8');
336 $value = stripslashes($value);
337 }
338 return wp_kses($value, $tags);
339 }
340
341
342 function fluentform_sanitize_html($html)
343 {
344 if (!$html) {
345 return $html;
346 }
347
348 // Remove event handlers (e.g., onerror, onclick, onmouseover)
349 $html = preg_replace('/\s+on[a-z]+\s*=\s*([\'"])[^\'"]*\1/i', '', $html);
350
351 // Remove JavaScript protocol (e.g., `href="javascript:alert(1)"`)
352 $html = preg_replace('/\bjavascript\s*:/i', '', $html);
353
354 $tags = wp_kses_allowed_html('post');
355 $tags['style'] = [
356 'types' => [],
357 ];
358 // iframe
359 $tags['iframe'] = [
360 'width' => [],
361 'height' => [],
362 'src' => [],
363 'srcdoc' => [
364 'value_callback' => 'fluentform_iframe_srcdoc_sanitize'
365 ],
366 'title' => [],
367 'frameborder' => [],
368 'allow' => [],
369 'class' => [],
370 'id' => [],
371 'allowfullscreen' => [],
372 'style' => [],
373 ];
374
375 //svg
376 if (empty($tags['svg'])) {
377 $svg_args = [
378 'svg' => [
379 'class' => true,
380 'aria-hidden' => true,
381 'aria-labelledby' => true,
382 'role' => true,
383 'xmlns' => true,
384 'width' => true,
385 'height' => true,
386 'viewbox' => true,
387 'fill' => true,
388 'stroke' => true,
389 'stroke-width' => true,
390 'stroke-linecap' => true,
391 'stroke-linejoin' => true
392 ],
393 'g' => ['fill' => true],
394 'title' => ['title' => true],
395 'path' => [
396 'd' => true,
397 'fill' => true,
398 'transform' => true,
399 ],
400 'polyline' => [
401 'points' => true
402 ]
403 ];
404 $tags = array_merge($tags, $svg_args);
405 }
406
407 $tags = apply_filters_deprecated(
408 'fluentform_allowed_html_tags',
409 [
410 $tags
411 ],
412 FLUENTFORM_FRAMEWORK_UPGRADE,
413 'fluentform/allowed_html_tags',
414 'Use fluentform/allowed_html_tags instead of fluentform_allowed_html_tags'
415 );
416
417 $tags = apply_filters('fluentform/allowed_html_tags', $tags);
418
419 // Event-handler attributes are executable JavaScript and must not be re-enabled by filters.
420 foreach ($tags as $tagName => $attributes) {
421 if (!is_array($attributes)) {
422 continue;
423 }
424
425 foreach (array_keys($attributes) as $attribute) {
426 if (preg_match('/^on[a-z]+/i', $attribute)) {
427 unset($tags[$tagName][$attribute]);
428 }
429 }
430 }
431
432 return wp_kses($html, $tags);
433 }
434
435 function fluentform_kses_js($content)
436 {
437 if (!$content) {
438 return '';
439 }
440
441 return preg_replace('/<\/?script[^>]*>/is', '', $content);
442 }
443
444 function fluentform_sanitize_json_object($value)
445 {
446 return \FluentForm\App\Services\FormBuilder\DateConfigNormalizer::sanitize($value);
447 }
448
449 function fluentform_date_config_to_js($json)
450 {
451 return \FluentForm\App\Services\FormBuilder\DateConfigNormalizer::toJs($json);
452 }
453
454 /**
455 * Sanitize inputs recursively.
456 *
457 * @param array $input
458 * @param array $sanitizeMap
459 *
460 * @return array $input
461 */
462 function fluentform_backend_sanitizer($inputs, $sanitizeMap = [])
463 {
464 $originalValues = $inputs;
465 foreach ($inputs as $key => &$value) {
466 if (is_array($value)) {
467 $value = fluentform_backend_sanitizer($value, $sanitizeMap);
468 } else {
469 $method = ArrayHelper::get($sanitizeMap, $key);
470 if (is_callable($method)) {
471 $value = call_user_func($method, $value);
472 }
473 }
474 }
475
476 return apply_filters('fluentform/backend_sanitized_values', $inputs, $originalValues);
477 }
478
479 /**
480 * Sanitizes CSS.
481 *
482 * @return mixed $css
483 */
484 function fluentformSanitizeCSS($css)
485 {
486 if ($css === null || $css === '') {
487 return '';
488 }
489
490 // Convert to string if not already
491 if (!is_string($css)) {
492 $css = (string) $css;
493 }
494
495 return preg_match('#</?\w+#', $css) ? '' : $css;
496 }
497
498 function fluentformCanUnfilteredHTML()
499 {
500 return current_user_can('unfiltered_html') || apply_filters('fluentform/disable_fields_sanitize', false);
501 }
502
503 function fluentformLoadFile($path)
504 {
505 return require wpFluentForm('path.app') . '/' . ltrim($path, '/');
506 }
507
508 if (!function_exists('fluentValidator')) {
509 function fluentValidator($data = [], $rules = [], $messages = [])
510 {
511 return wpFluentForm('validator')->make($data, $rules, $messages);
512 }
513 }
514
515 function fluentformGetPages()
516 {
517 $pages = get_pages();
518 $formattedPages = [];
519
520 foreach ($pages as $page) {
521 $formattedPages[] = [
522 'ID' => $page->ID,
523 'post_title' => $page->post_title,
524 'guid' => $page->guid,
525 ];
526 }
527
528 return $formattedPages;
529 }
530
531 function fluentform_maybe_disable_contaminated_pro()
532 {
533 $unsafeProFile = WP_PLUGIN_DIR . '/fluentformpro/libs/class-license-sync.php';
534
535 if (! is_file($unsafeProFile)) {
536 return;
537 }
538
539 require_once ABSPATH . 'wp-admin/includes/plugin.php';
540
541 deactivate_plugins(
542 'fluentformpro/fluentformpro.php',
543 true
544 );
545
546 $message = sprintf(
547 __('<strong>Fluent Forms Pro has been deactivated for security reasons.</strong> Delete the existing plugin and install a fresh copy from your %1$sWPManageNinja dashboard%2$s. Your Fluent Forms data will remain intact. We recommend %3$sopening a support ticket%4$s so we can help clean up your site. Read the %5$sincident report%6$s for details.', 'fluentform'),
548 '<a href="' . esc_url(add_query_arg('ff_deactivation_error', '1', 'https://wpmanageninja.com/account/downloads')) . '" target="_blank" rel="noopener noreferrer">',
549 '</a>',
550 '<a href="' . esc_url(add_query_arg('ff_deactivation_error', '1', 'https://wpmanageninja.com/account/support-tickets/submit-ticket/')) . '" target="_blank" rel="noopener noreferrer">',
551 '</a>',
552 '<a href="' . esc_url(add_query_arg('ff_deactivation_error', '1', 'https://wpmanageninja.com/security-incident-on-31-july-2026/')) . '" target="_blank" rel="noopener noreferrer">',
553 '</a>'
554 );
555
556 add_action('admin_init', function () use ($message) {
557 $renderNotice = function () use ($message) {
558 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Admin notice with HTML links
559 printf('<div class="fluentform-admin-notice notice notice-error"><div style="padding: 15px 10px;">%1$s</div></div>', $message);
560 };
561 add_action('fluentform/global_menu', $renderNotice);
562 add_action('fluentform/after_form_menu', $renderNotice);
563 });
564
565 add_action('admin_notices', function () use ($message) {
566 if (! current_user_can('activate_plugins')) {
567 return;
568 }
569 ?>
570 <div class="notice notice-error">
571 <p>
572 <?php echo $message; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Admin notice with HTML links ?>
573 </p>
574 </div>
575 <?php
576 });
577 }
578