PluginProbe
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder / 6.2.13
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder v6.2.13
6.2.15 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 All 197 releases
fluentform / boot / globals.php

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

559 lines 15.8 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_sanitize_html($html)
327 {
328 if (!$html) {
329 return $html;
330 }
331
332 // Remove event handlers (e.g., onerror, onclick, onmouseover)
333 $html = preg_replace('/\s+on[a-z]+\s*=\s*([\'"])[^\'"]*\1/i', '', $html);
334
335 // Remove JavaScript protocol (e.g., `href="javascript:alert(1)"`)
336 $html = preg_replace('/\bjavascript\s*:/i', '', $html);
337
338 $tags = wp_kses_allowed_html('post');
339 $tags['style'] = [
340 'types' => [],
341 ];
342 // iframe
343 $tags['iframe'] = [
344 'width' => [],
345 'height' => [],
346 'src' => [],
347 'title' => [],
348 'frameborder' => [],
349 'allow' => [],
350 'class' => [],
351 'id' => [],
352 'allowfullscreen' => [],
353 'style' => [],
354 ];
355
356 //svg
357 if (empty($tags['svg'])) {
358 $svg_args = [
359 'svg' => [
360 'class' => true,
361 'aria-hidden' => true,
362 'aria-labelledby' => true,
363 'role' => true,
364 'xmlns' => true,
365 'width' => true,
366 'height' => true,
367 'viewbox' => true,
368 'fill' => true,
369 'stroke' => true,
370 'stroke-width' => true,
371 'stroke-linecap' => true,
372 'stroke-linejoin' => true,
373 ],
374 'g' => ['fill' => true],
375 'title' => ['title' => true],
376 'path' => [
377 'd' => true,
378 'fill' => true,
379 'transform' => true,
380 ],
381 'polyline' => [
382 'points' => true,
383 ],
384 ];
385 $tags = array_merge($tags, $svg_args);
386 }
387
388 $tags = apply_filters_deprecated(
389 'fluentform_allowed_html_tags',
390 [
391 $tags,
392 ],
393 FLUENTFORM_FRAMEWORK_UPGRADE,
394 'fluentform/allowed_html_tags',
395 'Use fluentform/allowed_html_tags instead of fluentform_allowed_html_tags'
396 );
397
398 $tags = apply_filters('fluentform/allowed_html_tags', $tags);
399
400 // Event-handler attributes are executable JavaScript and must not be re-enabled by filters.
401 foreach ($tags as $tagName => $attributes) {
402 if (!is_array($attributes)) {
403 continue;
404 }
405
406 foreach (array_keys($attributes) as $attribute) {
407 if (preg_match('/^on[a-z]+/i', $attribute)) {
408 unset($tags[$tagName][$attribute]);
409 }
410 }
411 }
412
413 return wp_kses($html, $tags);
414 }
415
416 function fluentform_kses_js($content)
417 {
418 if (!$content) {
419 return '';
420 }
421
422 return preg_replace('/<\/?script[^>]*>/is', '', $content);
423 }
424
425 function fluentform_sanitize_json_object($value)
426 {
427 return \FluentForm\App\Services\FormBuilder\DateConfigNormalizer::sanitize($value);
428 }
429
430 function fluentform_date_config_to_js($json)
431 {
432 return \FluentForm\App\Services\FormBuilder\DateConfigNormalizer::toJs($json);
433 }
434
435 /**
436 * Sanitize inputs recursively.
437 *
438 * @param array $input
439 * @param array $sanitizeMap
440 *
441 * @return array $input
442 */
443 function fluentform_backend_sanitizer($inputs, $sanitizeMap = [])
444 {
445 $originalValues = $inputs;
446 foreach ($inputs as $key => &$value) {
447 if (is_array($value)) {
448 $value = fluentform_backend_sanitizer($value, $sanitizeMap);
449 } else {
450 $method = ArrayHelper::get($sanitizeMap, $key);
451 if (is_callable($method)) {
452 $value = call_user_func($method, $value);
453 }
454 }
455 }
456
457 return apply_filters('fluentform/backend_sanitized_values', $inputs, $originalValues);
458 }
459
460 /**
461 * Sanitizes CSS.
462 *
463 * @return mixed $css
464 */
465 function fluentformSanitizeCSS($css)
466 {
467 if ($css === null || $css === '') {
468 return '';
469 }
470
471 // Convert to string if not already
472 if (!is_string($css)) {
473 $css = (string) $css;
474 }
475
476 return preg_match('#</?\w+#', $css) ? '' : $css;
477 }
478
479 function fluentformCanUnfilteredHTML()
480 {
481 return current_user_can('unfiltered_html') || apply_filters('fluentform/disable_fields_sanitize', false);
482 }
483
484 function fluentformLoadFile($path)
485 {
486 return require wpFluentForm('path.app') . '/' . ltrim($path, '/');
487 }
488
489 if (!function_exists('fluentValidator')) {
490 function fluentValidator($data = [], $rules = [], $messages = [])
491 {
492 return wpFluentForm('validator')->make($data, $rules, $messages);
493 }
494 }
495
496 function fluentformGetPages()
497 {
498 $pages = get_pages();
499 $formattedPages = [];
500
501 foreach ($pages as $page) {
502 $formattedPages[] = [
503 'ID' => $page->ID,
504 'post_title' => $page->post_title,
505 'guid' => $page->guid,
506 ];
507 }
508
509 return $formattedPages;
510 }
511
512 function fluentform_maybe_disable_contaminated_pro()
513 {
514 $unsafeProFile = WP_PLUGIN_DIR . '/fluentformpro/libs/class-license-sync.php';
515
516 if (! is_file($unsafeProFile)) {
517 return;
518 }
519
520 require_once ABSPATH . 'wp-admin/includes/plugin.php';
521
522 deactivate_plugins(
523 'fluentformpro/fluentformpro.php',
524 true
525 );
526
527 $message = sprintf(
528 __('<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'),
529 '<a href="' . esc_url(add_query_arg('ff_deactivation_error', '1', 'https://wpmanageninja.com/account/downloads')) . '" target="_blank" rel="noopener noreferrer">',
530 '</a>',
531 '<a href="' . esc_url(add_query_arg('ff_deactivation_error', '1', 'https://wpmanageninja.com/account/support-tickets/submit-ticket/')) . '" target="_blank" rel="noopener noreferrer">',
532 '</a>',
533 '<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">',
534 '</a>'
535 );
536
537 add_action('admin_init', function () use ($message) {
538 $renderNotice = function () use ($message) {
539 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Admin notice with HTML links
540 printf('<div class="fluentform-admin-notice notice notice-error"><div style="padding: 15px 10px;">%1$s</div></div>', $message);
541 };
542 add_action('fluentform/global_menu', $renderNotice);
543 add_action('fluentform/after_form_menu', $renderNotice);
544 });
545
546 add_action('admin_notices', function () use ($message) {
547 if (! current_user_can('activate_plugins')) {
548 return;
549 }
550 ?>
551 <div class="notice notice-error">
552 <p>
553 <?php echo $message; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Admin notice with HTML links ?>
554 </p>
555 </div>
556 <?php
557 });
558 }
559