PluginProbe
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder / 6.2.14
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder v6.2.14
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.14, at boot/globals.php

549 lines 15.5 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 /**
426 * Sanitize inputs recursively.
427 *
428 * @param array $input
429 * @param array $sanitizeMap
430 *
431 * @return array $input
432 */
433 function fluentform_backend_sanitizer($inputs, $sanitizeMap = [])
434 {
435 $originalValues = $inputs;
436 foreach ($inputs as $key => &$value) {
437 if (is_array($value)) {
438 $value = fluentform_backend_sanitizer($value, $sanitizeMap);
439 } else {
440 $method = ArrayHelper::get($sanitizeMap, $key);
441 if (is_callable($method)) {
442 $value = call_user_func($method, $value);
443 }
444 }
445 }
446
447 return apply_filters('fluentform/backend_sanitized_values', $inputs, $originalValues);
448 }
449
450 /**
451 * Sanitizes CSS.
452 *
453 * @return mixed $css
454 */
455 function fluentformSanitizeCSS($css)
456 {
457 if ($css === null || $css === '') {
458 return '';
459 }
460
461 // Convert to string if not already
462 if (!is_string($css)) {
463 $css = (string) $css;
464 }
465
466 return preg_match('#</?\w+#', $css) ? '' : $css;
467 }
468
469 function fluentformCanUnfilteredHTML()
470 {
471 return current_user_can('unfiltered_html') || apply_filters('fluentform/disable_fields_sanitize', false);
472 }
473
474 function fluentformLoadFile($path)
475 {
476 return require wpFluentForm('path.app') . '/' . ltrim($path, '/');
477 }
478
479 if (!function_exists('fluentValidator')) {
480 function fluentValidator($data = [], $rules = [], $messages = [])
481 {
482 return wpFluentForm('validator')->make($data, $rules, $messages);
483 }
484 }
485
486 function fluentformGetPages()
487 {
488 $pages = get_pages();
489 $formattedPages = [];
490
491 foreach ($pages as $page) {
492 $formattedPages[] = [
493 'ID' => $page->ID,
494 'post_title' => $page->post_title,
495 'guid' => $page->guid,
496 ];
497 }
498
499 return $formattedPages;
500 }
501
502 function fluentform_maybe_disable_contaminated_pro()
503 {
504 $unsafeProFile = WP_PLUGIN_DIR . '/fluentformpro/libs/class-license-sync.php';
505
506 if (! is_file($unsafeProFile)) {
507 return;
508 }
509
510 require_once ABSPATH . 'wp-admin/includes/plugin.php';
511
512 deactivate_plugins(
513 'fluentformpro/fluentformpro.php',
514 true
515 );
516
517 $message = sprintf(
518 __('<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'),
519 '<a href="' . esc_url(add_query_arg('ff_deactivation_error', '1', 'https://wpmanageninja.com/account/downloads')) . '" target="_blank" rel="noopener noreferrer">',
520 '</a>',
521 '<a href="' . esc_url(add_query_arg('ff_deactivation_error', '1', 'https://wpmanageninja.com/account/support-tickets/submit-ticket/')) . '" target="_blank" rel="noopener noreferrer">',
522 '</a>',
523 '<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">',
524 '</a>'
525 );
526
527 add_action('admin_init', function () use ($message) {
528 $renderNotice = function () use ($message) {
529 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Admin notice with HTML links
530 printf('<div class="fluentform-admin-notice notice notice-error"><div style="padding: 15px 10px;">%1$s</div></div>', $message);
531 };
532 add_action('fluentform/global_menu', $renderNotice);
533 add_action('fluentform/after_form_menu', $renderNotice);
534 });
535
536 add_action('admin_notices', function () use ($message) {
537 if (! current_user_can('activate_plugins')) {
538 return;
539 }
540 ?>
541 <div class="notice notice-error">
542 <p>
543 <?php echo $message; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Admin notice with HTML links ?>
544 </p>
545 </div>
546 <?php
547 });
548 }
549