PluginProbe
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder / 6.2.15
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder v6.2.15
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
← All changes | boot/globals.php +67 -95 6.2.6 → 6.2.15 View file →
@@ -100,18 +100,19 @@
100 100 $input = sanitize_text_field($input);
101 101 }
102 102 } elseif (is_array($input)) {
103 103 $sanitizedInput = [];
104 -
104 +
105 105 foreach ($input as $key => &$value) {
106 106 $key = fluentFormSanitizer($key);
107 - $attribute = $attribute ? $attribute . '[' . $key . ']' : $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;
108 110
109 - $value = fluentFormSanitizer($value, $attribute, $fields);
110 - $attribute = null;
111 + $value = fluentFormSanitizer($value, $childAttribute, $fields);
111 112 $sanitizedInput[$key] = $value;
112 113 }
113 -
114 +
114 115 $input = $sanitizedInput;
115 116 }
116 117
117 118 return $input;
@@ -210,13 +211,13 @@
210 211
211 212 function fluentFormIsHandlingSubmission()
212 213 {
213 214 $status = fluentFormWasSubmitted() || isWpAsyncRequest('fluentform_async_request');
214 -
215 +
215 216 $status = apply_filters_deprecated(
216 217 'fluentform_is_handling_submission',
217 218 [
218 - $status
219 + $status,
219 220 ],
220 221 FLUENTFORM_FRAMEWORK_UPGRADE,
221 222 'fluentform/is_handling_submission',
222 223 'Use fluentform/is_handling_submission instead of fluentform_is_handling_submission'
@@ -255,16 +256,16 @@
255 256 {
256 257 \FluentForm\App\Services\Scheduler\Scheduler::processEmailReport();
257 258 }
258 259
259 -function fluentform_upgrade_url()
260 +function fluentform_upgrade_url($utmContent = '')
260 261 {
261 - return 'https://fluentforms.com/pricing/?utm_source=plugin&utm_medium=wp_install&utm_campaign=ff_upgrade&theme_style=' . fluentform_get_active_theme_slug();
262 + return \FluentForm\App\Helpers\Helper::utmUrl('https://fluentforms.com/pricing/', $utmContent);
262 263 }
263 264
264 -function fluentform_integrations_url()
265 +function fluentform_integrations_url($utmContent = '')
265 266 {
266 - return 'https://fluentforms.com/integration/?utm_source=plugin&utm_medium=wp_install&utm_campaign=ff_upgrade&theme_style=' . fluentform_get_active_theme_slug();
267 + return \FluentForm\App\Helpers\Helper::utmUrl('https://fluentforms.com/integration/', $utmContent);
267 268 }
268 269
269 270 function fluentFormApi($module = 'forms')
270 271 {
@@ -321,24 +322,8 @@
321 322 {
322 323 return \FluentForm\App\Helpers\Helper::sanitizeAdvancedOptions($options);
323 324 }
324 325
325 -function fluentform_iframe_srcdoc_sanitize($value)
326 -{
327 - $tags = wp_kses_allowed_html('post');
328 - $tags['style'] = [
329 - 'types' => [],
330 - ];
331 - // Check if decoding is necessary
332 - if (strpos($value, '&') !== false) {
333 - // Decode HTML entities
334 - $value = html_entity_decode($value, ENT_QUOTES | ENT_HTML5, 'UTF-8');
335 - $value = stripslashes($value);
336 - }
337 - return wp_kses($value, $tags);
338 -}
339 -
340 -
341 326 function fluentform_sanitize_html($html)
342 327 {
343 328 if (!$html) {
344 329 return $html;
@@ -358,11 +343,8 @@
358 343 $tags['iframe'] = [
359 344 'width' => [],
360 345 'height' => [],
361 346 'src' => [],
362 - 'srcdoc' => [
363 - 'value_callback' => 'fluentform_iframe_srcdoc_sanitize'
364 - ],
365 347 'title' => [],
366 348 'frameborder' => [],
367 349 'allow' => [],
368 350 'class' => [],
@@ -369,9 +351,9 @@
369 351 'id' => [],
370 352 'allowfullscreen' => [],
371 353 'style' => [],
372 354 ];
373 -
355 +
374 356 //svg
375 357 if (empty($tags['svg'])) {
376 358 $svg_args = [
377 359 'svg' => [
@@ -386,9 +368,9 @@
386 368 'fill' => true,
387 369 'stroke' => true,
388 370 'stroke-width' => true,
389 371 'stroke-linecap' => true,
390 - 'stroke-linejoin' => true
372 + 'stroke-linejoin' => true,
391 373 ],
392 374 'g' => ['fill' => true],
393 375 'title' => ['title' => true],
394 376 'path' => [
@@ -396,18 +378,18 @@
396 378 'fill' => true,
397 379 'transform' => true,
398 380 ],
399 381 'polyline' => [
400 - 'points' => true
401 - ]
382 + 'points' => true,
383 + ],
402 384 ];
403 385 $tags = array_merge($tags, $svg_args);
404 386 }
405 -
387 +
406 388 $tags = apply_filters_deprecated(
407 389 'fluentform_allowed_html_tags',
408 390 [
409 - $tags
391 + $tags,
410 392 ],
411 393 FLUENTFORM_FRAMEWORK_UPGRADE,
412 394 'fluentform/allowed_html_tags',
413 395 'Use fluentform/allowed_html_tags instead of fluentform_allowed_html_tags'
@@ -439,66 +421,8 @@
439 421
440 422 return preg_replace('/<\/?script[^>]*>/is', '', $content);
441 423 }
442 424
443 -function fluentform_sanitize_json_object($value)
444 -{
445 - if (!is_string($value) || '' === trim($value)) {
446 - return '';
447 - }
448 -
449 - $value = trim($value);
450 -
451 - $decoded = json_decode($value, true);
452 -
453 - // Best-effort recovery of a pure-data JS-object literal (unquoted keys,
454 - // single quotes, trailing commas) — the documented "JS object" format for
455 - // the Date/Time field's advanced config. json_decode below is the security
456 - // gate: any function or expression that survives normalisation is still not
457 - // valid JSON, so it is rejected. Normalisation can only recover data, never
458 - // execute or emit code.
459 - if (JSON_ERROR_NONE !== json_last_error() || !is_array($decoded)) {
460 - $decoded = json_decode(fluentform_js_object_to_json($value), true);
461 - }
462 -
463 - if (JSON_ERROR_NONE !== json_last_error() || !is_array($decoded)) {
464 - return '';
465 - }
466 -
467 - if ([] === $decoded) {
468 - return '{}';
469 - }
470 -
471 - // date_config must be an object; reject a top-level JSON array. Nested
472 - // arrays (e.g. flatpickr `disable: [...]`) are preserved by not forcing
473 - // JSON_FORCE_OBJECT recursively.
474 - if (array_keys($decoded) === range(0, count($decoded) - 1)) {
475 - return '';
476 - }
477 -
478 - return wp_json_encode($decoded);
479 -}
480 -
481 -function fluentform_js_object_to_json($value)
482 -{
483 - // Single-quoted strings -> double-quoted (respecting escapes).
484 - $value = preg_replace_callback(
485 - "/'((?:\\\\.|[^'\\\\])*)'/s",
486 - function ($m) {
487 - return '"' . str_replace(['\\\'', '"'], ['\'', '\\"'], $m[1]) . '"';
488 - },
489 - $value
490 - );
491 -
492 - // Quote unquoted object keys: `{ key:` / `, key:` -> `{ "key":`.
493 - $value = preg_replace('/([{,]\s*)([A-Za-z_$][A-Za-z0-9_$]*)(\s*:)/', '$1"$2"$3', $value);
494 -
495 - // Drop trailing commas before a closing brace/bracket.
496 - $value = preg_replace('/,\s*([}\]])/', '$1', $value);
497 -
498 - return $value;
499 -}
500 -
501 425 /**
502 426 * Sanitize inputs recursively.
503 427 *
504 428 * @param array $input
@@ -537,9 +461,9 @@
537 461 // Convert to string if not already
538 462 if (!is_string($css)) {
539 463 $css = (string) $css;
540 464 }
541 -
465 +
542 466 return preg_match('#</?\w+#', $css) ? '' : $css;
543 467 }
544 468
545 469 function fluentformCanUnfilteredHTML()
@@ -572,5 +496,53 @@
572 496 ];
573 497 }
574 498
575 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 + });
576 548 }