PluginProbe
Bit Form – Contact Form, Payment Forms, Multi Step Forms, Calculator & Custom Form Builder / V3.3.2
Bit Form – Contact Form, Payment Forms, Multi Step Forms, Calculator & Custom Form Builder vV3.3.2
V3.3.2 3.3.1 V-3.3.0 3.2.2 3.2.1 3.2.0 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 V3.0.3 V3.0.2 -3.0.1 V_3.0.0 1.1.1 1.1.8 1.2 1.3 1.4 1.4.18 1.5.2 1.9 2.0 2.10.0 All 139 releases
← All changes | includes/Admin/Form/Helpers.php +71 -10 3.1.0 → V3.3.2 View file →
@@ -5,8 +5,9 @@
5 5 use BitCode\BitForm\Core\Cryptography\Cryptography;
6 6 use BitCode\BitForm\Core\Database\FormEntryModel;
7 7 use BitCode\BitForm\Core\Util\FileHandler;
8 8 use BitCode\BitForm\Core\Util\Log;
9 +use BitCode\BitForm\Core\WorkFlow\WorkflowExecutor;
9 10 use Exception;
10 11 use WP_Error;
11 12
12 13 class Helpers
@@ -86,16 +87,19 @@
86 87 {
87 88 if ('' === trim($input)) {
88 89 return $input;
89 90 }
91 + // Line-boundary whitespace only. The previous regexes also rewrote the
92 + // inside of string and template literals, corrupting generated config and
93 + // custom JS. Inputs are already terser-minified, so the aggressive pass
94 + // saved ~0.1% anyway.
90 95 return preg_replace(
91 96 [
92 - '/ {2,}/',
93 - '/\s*=\s*/',
94 - '/\s*,\s*/',
95 - '/\s+(?=\(|\{|\:|\?)|\t|(?:\r?\n[ \t]*)+/s'
97 + '/^[ \t]+/m', // leading indentation
98 + '/[ \t]+$/m', // trailing whitespace
99 + '/(?:\r?\n){3,}/', // 3+ consecutive newlines -> 2
96 100 ],
97 - [' ', '=', ',', ''],
101 + ['', '', "\n\n"],
98 102 $input
99 103 );
100 104 }
101 105
@@ -414,10 +418,17 @@
414 418
415 419 // Validate trigger token from transient
416 420 $transientData = get_transient("bitform_trigger_transient_{$entryID}");
417 421
422 + // Object caches (W3TC, SG Optimizer, Redis) can drop the transient before the
423 + // browser trigger arrives; the queue log row holds the same payload durably.
418 424 if (empty($transientData)) {
419 - Log::debug_log('Trigger token transient missing for entryID=' . $entryID . ', logID=' . $logID);
425 + $queueLogId = isset($request->cronNotOk[2]) && is_numeric($request->cronNotOk[2]) ? absint($request->cronNotOk[2]) : 0;
426 + $transientData = WorkflowExecutor::loadTriggerDataFromLog($queueLogId);
427 + Log::debug_log('Trigger token transient missing for entryID=' . $entryID . ', logID=' . $logID . '; durable copy ' . (empty($transientData) ? 'not found' : 'used'));
428 + }
429 +
430 + if (empty($transientData)) {
420 431 return [
421 432 'valid' => false,
422 433 'error' => 'Trigger token expired or missing',
423 434 'triggerData' => null,
@@ -424,12 +435,12 @@
424 435 'isAdminBypass' => false
425 436 ];
426 437 }
427 438
428 - $triggerData = is_string($transientData) ? json_decode($transientData) : $transientData;
439 + $triggerData = is_string($transientData) ? json_decode($transientData, true) : (array) $transientData;
429 440 // Verify token matches and belongs to this entry/log
430 441 if (
431 - !isset($triggerData['trigger_token'])
442 + !isset($triggerData['trigger_token'], $triggerData['entryID'], $triggerData['logID'])
432 443 || !hash_equals($triggerData['trigger_token'], $submittedToken)
433 444 || (int)$triggerData['entryID'] !== $entryID
434 445 || (int)$triggerData['logID'] !== $logID
435 446 ) {
@@ -700,10 +711,10 @@
700 711 public static function replaceShortcodeInErrorMsg($msg, $field)
701 712 {
702 713 $shortcodes = [
703 714 '${field.label}' => isset($field->lbl) ? $field->lbl : '',
704 - '${field.minimum}' => isset($field->mn) ? $field->mn : '',
705 - '${field.maximum}' => isset($field->mx) ? $field->mx : '',
715 + '${field.minimum}' => isset($field->mn) ? self::readableRangeValue($field->mn, isset($field->typ) ? $field->typ : '') : '',
716 + '${field.maximum}' => isset($field->mx) ? self::readableRangeValue($field->mx, isset($field->typ) ? $field->typ : '') : '',
706 717 '${field.minimum_file}' => isset($field->config->minFile) ? $field->config->minFile : '',
707 718 '${field.maximum_file}' => isset($field->config->maxFile) ? $field->config->maxFile : '',
708 719 '${field.maximum_size}' => isset($field->config->maxSize) ? $field->config->maxSize : '',
709 720 '${field.minimum_amount}' => isset($field->config->minValue) ? $field->config->minValue : '',
@@ -710,8 +721,58 @@
710 721 '${field.maximum_amount}' => isset($field->config->maxValue) ? $field->config->maxValue : '',
711 722 ];
712 723 $msg = str_replace(array_keys($shortcodes), array_values($shortcodes), $msg);
713 724 return $msg;
725 + }
726 +
727 + /**
728 + * Date-like min/max are stored in the input's wire format (2026-10-01T09:00, 2026-W40); show
729 + * them to visitors in the site's date/time format instead. Anything else is returned as is.
730 + *
731 + * @param mixed $value field mn/mx
732 + * @param string $type field type
733 + *
734 + * @return mixed
735 + */
736 + public static function readableRangeValue($value, $type)
737 + {
738 + if (!is_string($value) || '' === $value) {
739 + return $value;
740 + }
741 + $dateFormat = (string) get_option('date_format', 'F j, Y');
742 + $timeFormat = (string) get_option('time_format', 'g:i a');
743 + $utc = new \DateTimeZone('UTC');
744 + $formatTimestamp = function ($format, $timestamp) use ($utc) {
745 + return function_exists('wp_date') ? wp_date($format, $timestamp, $utc) : gmdate($format, $timestamp);
746 + };
747 +
748 + switch ($type) {
749 + case 'date':
750 + $date = \DateTime::createFromFormat('!Y-m-d', $value, $utc);
751 + return $date ? $formatTimestamp($dateFormat, $date->getTimestamp()) : $value;
752 +
753 + case 'datetime-local':
754 + $date = \DateTime::createFromFormat('!Y-m-d\TH:i', substr($value, 0, 16), $utc);
755 + return $date ? $formatTimestamp($dateFormat . ' ' . $timeFormat, $date->getTimestamp()) : $value;
756 +
757 + case 'time':
758 + $date = \DateTime::createFromFormat('!H:i', substr($value, 0, 5), $utc);
759 + return $date ? $formatTimestamp($timeFormat, $date->getTimestamp()) : $value;
760 +
761 + case 'month':
762 + $date = \DateTime::createFromFormat('!Y-m', $value, $utc);
763 + return $date ? $formatTimestamp('F Y', $date->getTimestamp()) : $value;
764 +
765 + case 'week':
766 + if (1 === preg_match('/^(\d{4})-W(\d{1,2})$/i', $value, $match)) {
767 + // translators: 1: ISO week number, 2: year
768 + return sprintf(__('week %1$d of %2$d', 'bit-form'), (int) $match[2], (int) $match[1]);
769 + }
770 + return $value;
771 +
772 + default:
773 + return $value;
774 + }
714 775 }
715 776
716 777 public static function getDefaultGlobalMessages()
717 778 {