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 | views/conversational-form.php +232 -39 2.10.0 → V3.3.2 View file →
@@ -1,57 +1,250 @@
1 +<?php
2 +
3 +// This file is included via Render::view() using extract(); all variables below are in the calling method's local scope, not global namespace.
4 +
5 +use BitCode\BitForm\Core\Util\EscapingHelper;
6 +use BitCode\BitForm\Core\Util\FrontendHelpers;
7 +
8 +if (!defined('ABSPATH')) {
9 + exit;
10 +}
11 +if (!defined('BITFORMS_ASSET_URI')) {
12 + exit;
13 +}
14 +
15 +$formUpdateVersion = get_option('bitform_form_update_version');
16 +$formIdSafe = sanitize_key((string) $formID);
17 +
18 +$baseCSSPath = "/form-styles/bitform-{$formID}.css";
19 +$baseConversationalCSSPath = "/form-styles/bitform-conversational-{$formID}.css";
20 +$customCSSPath = "/form-styles/bitform-custom-{$formID}.css";
21 +$standaloneCSSPath = "/form-styles/bitform-standalone-{$formID}.css";
22 +
23 +wp_register_style('bitform-conversational-base-' . $formIdSafe, FrontendHelpers::styleSrc($baseCSSPath), [], $formUpdateVersion);
24 +wp_register_style('bitform-conversational-' . $formIdSafe, FrontendHelpers::styleSrc($baseConversationalCSSPath), [], $formUpdateVersion);
25 +wp_enqueue_style('bitform-conversational-base-' . $formIdSafe);
26 +wp_enqueue_style('bitform-conversational-' . $formIdSafe);
27 +
28 +if (file_exists(BITFORMS_CONTENT_DIR . $customCSSPath)) {
29 + wp_register_style('bitform-conversational-custom-' . $formIdSafe, FrontendHelpers::styleSrc($customCSSPath), [], $formUpdateVersion);
30 + wp_enqueue_style('bitform-conversational-custom-' . $formIdSafe);
31 +}
32 +
33 +if (file_exists(BITFORMS_CONTENT_DIR . $standaloneCSSPath)) {
34 + wp_register_style('bitform-conversational-standalone-' . $formIdSafe, FrontendHelpers::styleSrc($standaloneCSSPath), [], $formUpdateVersion);
35 + wp_enqueue_style('bitform-conversational-standalone-' . $formIdSafe);
36 +}
37 +
38 +if (isset($font) && '' !== $font) {
39 + wp_register_style('bitform-conversational-font-' . $formIdSafe, $font, [], $formUpdateVersion);
40 + wp_enqueue_style('bitform-conversational-font-' . $formIdSafe);
41 +}
42 +
43 +$conversationalJsPath = BITFORMS_UPLOAD_BASE_URL . '/form-scripts/bitform-conversational-' . $formID . '.js';
44 +wp_register_script('bitform-conversational-' . $formIdSafe, $conversationalJsPath, [], $formUpdateVersion, true);
45 +wp_enqueue_script('bitform-conversational-' . $formIdSafe);
46 +if (isset($bfGlobals) && '' !== $bfGlobals) {
47 + wp_add_inline_script('bitform-conversational-' . $formIdSafe, (string) $bfGlobals, 'before');
48 +}
49 +?>
50 +
1 51 <!DOCTYPE html>
2 52 <html lang="en">
53 +
3 54 <head>
4 55 <meta charset="UTF-8">
5 56 <meta name="viewport" content="width=device-width, initial-scale=1.0">
6 - <title><?= isset($title) ? $title : 'Conversational Form'; ?></title>
57 + <title><?php echo isset($title) ? esc_html($title) : 'Conversational Form'; ?></title>
7 58 <style>
8 - * {
9 - padding: 0;
10 - margin: 0;
11 - box-sizing: border-box;
12 - }
59 + * {
60 + padding: 0;
61 + margin: 0;
62 + box-sizing: border-box;
63 + }
13 64
14 - body.bit-conversational-form {
15 - height: 100vh;
16 - overflow: hidden;
17 - }
65 + body.bit-conversational-form {
66 + height: 100vh;
67 + overflow: hidden;
68 + }
18 69
19 - @media (max-width: 575.98px) {
20 - .standalone-form-wrapper {
21 - width: 100%;
22 - }
70 + @media (max-width: 575.98px) {
71 + .standalone-form-wrapper {
72 + width: 100%;
23 73 }
74 + }
75 + </style>
76 + <?php if (isset($font) && '' !== $font) : ?>
77 + <link rel="preconnect" href="https://fonts.googleapis.com">
78 + <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
79 + <?php endif; ?>
80 + <?php
81 + wp_enqueue_emoji_styles();
82 + wp_print_styles();
83 + ?>
84 +</head>
24 85
25 - </style>
86 +<body class="bit-conversational-form">
26 87 <?php
27 - $baseCSSPath = "/form-styles/bitform-{$formID}.css";
28 - $baseConversationalCSSPath = "/form-styles/bitform-conversational-{$formID}.css";
29 - $customCSSPath = "/form-styles/bitform-custom-{$formID}.css";
30 - $standaloneCSSPath = "/form-styles/bitform-standalone-{$formID}.css";
88 + // Fallback config for when an optimizer defers or drops the inline script.
89 + // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- built by buildFormConfigTag(), JSON_HEX_* escaped.
90 + echo isset($configTag) ? $configTag : '';
31 91 ?>
32 - <link rel="stylesheet" href="<?= BITFORMS_UPLOAD_BASE_URL . $baseCSSPath ?>" />
33 - <link rel="stylesheet" href="<?= BITFORMS_UPLOAD_BASE_URL . $baseConversationalCSSPath ?>" />
34 -
35 - <?php if (file_exists(BITFORMS_CONTENT_DIR . $customCSSPath)) : ?>
36 - <link rel="stylesheet" href="<?= BITFORMS_UPLOAD_BASE_URL . $customCSSPath ?>" />
92 + <?php echo wp_kses($formHTML, EscapingHelper::getFormAllowedHtml(isset($formContent) ? $formContent : null)); ?>
93 + <?php if (!empty($isPreview)) : ?>
94 + <style>.bc-live-hidden { display: none !important; }</style>
95 + <script>window.bf_preview_mode = true;</script>
37 96 <?php endif; ?>
97 + <?php wp_print_scripts(); ?>
98 + <?php if (!empty($isPreview)) : ?>
99 + <script>
100 + (function() {
101 + var FID = <?php echo (int) $formID; ?>;
102 + var pfx = 'bc' + FID + '-';
38 103
39 - <?php if (file_exists(BITFORMS_CONTENT_DIR . $standaloneCSSPath)) : ?>
40 - <link rel="stylesheet" href="<?= BITFORMS_UPLOAD_BASE_URL . $standaloneCSSPath ?>" />
41 - <?php endif; ?>
104 + function q(sel) { return document.querySelector('.' + pfx + sel); }
105 + function qa(sel) { return document.querySelectorAll('.' + pfx + sel); }
106 + function toggle(el, show) { if (el) el.classList.toggle('bc-live-hidden', !show); }
107 + function setTxt(el, val) { if (el && val !== undefined && val !== null) el.textContent = val; }
42 108
43 - <?php if (isset($font) && '' !== $font) : ?>
44 - <link rel="preconnect" href="https://fonts.googleapis.com">
45 - <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
46 - <link rel="stylesheet" href="<?= $font ?>" />
47 - <?php endif; ?>
109 + var LAYOUT_CLASSES = ['normal-layout', 'compact-left-layout', 'compact-right-layout', 'padding-left-layout', 'padding-right-layout', 'centered-card-layout'];
48 110
49 -</head>
50 -<body class="bit-conversational-form">
51 - <?=$formHTML?>
52 - <script>
53 - <?= $bfGlobals ?>;
111 + function applyLiveSettings(settings) {
112 + var nav = settings.navigationSettings || {};
113 + var stl = settings.stepListObject || {};
114 + var all = stl.allSteps || {};
115 +
116 + // Visibility toggles
117 + toggle(q('nav-wrpr'), nav.show !== false);
118 + toggle(q('progress-lbl-wrpr'), !!nav.showProgressLabel);
119 + toggle(q('progress-bar-wrpr'), !!nav.showProgressBar);
120 + toggle(q('branding-wrpr'), nav.showBranding !== false);
121 + toggle(q('nav-btn-wrpr'), !!nav.showNavigateBtn);
122 +
123 + // Welcome page text content
124 + var wp = stl.welcomePage || {};
125 + var titleEl = document.querySelector('.' + pfx + 'welcome-title h2');
126 + setTxt(titleEl, wp.title);
127 + // Welcome page rich content (everything between title and button wrapper)
128 + var welcomeContentEl = q('welcome-content');
129 + if (welcomeContentEl && wp.content !== undefined) {
130 + // Find the text node area — insert content after title, before button wrapper
131 + var btnWrpr = welcomeContentEl.querySelector('.' + pfx + 'step-btn-wrpr');
132 + var titleWrpr = welcomeContentEl.querySelector('.' + pfx + 'welcome-title');
133 + // Remove existing text nodes / content nodes between title and button
134 + var children = Array.from(welcomeContentEl.childNodes);
135 + children.forEach(function(node) {
136 + if (node !== titleWrpr && node !== btnWrpr) {
137 + welcomeContentEl.removeChild(node);
138 + }
139 + });
140 + var tempDiv = document.createElement('div');
141 + tempDiv.innerHTML = wp.content || '';
142 + var frag = document.createDocumentFragment();
143 + while (tempDiv.firstChild) frag.appendChild(tempDiv.firstChild);
144 + welcomeContentEl.insertBefore(frag, btnWrpr);
145 + }
146 +
147 + // Per-step: button text, hints, layout, image, background
148 + var wrappers = qa('step-wrapper');
149 + var fieldKeys = Object.keys(stl).filter(function(k) { return k !== 'allSteps' && k !== 'welcomePage'; });
150 + var welcomeOffset = (wp.enable) ? 1 : 0;
151 +
152 + Array.prototype.forEach.call(wrappers, function(wrapper, idx) {
153 + var isWelcome = wrapper.classList.contains(pfx + 'welcome');
154 + var cfg = isWelcome ? wp : (stl[fieldKeys[idx - welcomeOffset]] || {});
155 +
156 + // Button text (start button on welcome, ok button on steps)
157 + if (isWelcome) {
158 + var startBtn = wrapper.querySelector('.' + pfx + 'start-btn');
159 + if (startBtn) {
160 + // preserve icon elements, update only text node
161 + var textNode = Array.from(startBtn.childNodes).find(function(n) { return n.nodeType === 3 && n.textContent.trim(); });
162 + if (textNode) textNode.textContent = '\n ' + (cfg.btnTxt || all.btnTxt || 'Start') + '\n ';
163 + }
164 + } else {
165 + var btnEl = wrapper.querySelector('.' + pfx + 'btn-ok');
166 + if (btnEl) {
167 + var textNode = Array.from(btnEl.childNodes).find(function(n) { return n.nodeType === 3 && n.textContent.trim(); });
168 + if (textNode) textNode.textContent = '\n ' + (cfg.btnTxt || all.btnTxt || 'OK') + '\n ';
169 + }
170 + }
171 +
172 + // Step hints — rendered as HTML (same as PHP frontend output).
173 + var hintsEl = wrapper.querySelector('.' + pfx + 'step-hints');
174 + var hintsVal = cfg.stepHints !== undefined ? cfg.stepHints : all.stepHints;
175 + if (hintsEl && hintsVal !== undefined && hintsVal !== null) hintsEl.innerHTML = hintsVal;
176 +
177 + // Layout class
178 + var layout = cfg.layout || all.layout || 'normal-layout';
179 + LAYOUT_CLASSES.forEach(function(c) { wrapper.classList.remove(c); });
180 + wrapper.classList.add(layout);
181 +
182 + // Layout image
183 + var imgEl = wrapper.querySelector('.' + pfx + 'step-img');
184 + if (imgEl) imgEl.src = cfg.layoutImage || all.layoutImage || '';
185 +
186 + // Show/hide image container based on layout
187 + var imgCntnr = wrapper.querySelector('.' + pfx + 'step-img-cntnr');
188 + if (imgCntnr) imgCntnr.style.display = (layout === 'normal-layout' || layout === 'centered-card-layout') ? 'none' : '';
189 +
190 + // Step background — Floating Card redirects to card element; others apply to wrapper.
191 + var bg = cfg.background || all.background || '';
192 + var bgColor = typeof bg === 'object' ? (bg['background-color'] || '') : bg;
193 + var cardEl = wrapper.querySelector('.' + pfx + 'step-content');
194 + var isRealColor = bgColor && bgColor !== 'transparent';
195 + if (layout === 'centered-card-layout') {
196 + wrapper.style.removeProperty('background');
197 + wrapper.style.removeProperty('background-color');
198 + if (cardEl) {
199 + // Only override CSS white fallback when user has a real color set.
200 + if (isRealColor) cardEl.style.setProperty('background-color', bgColor, 'important');
201 + else cardEl.style.removeProperty('background-color');
202 + }
203 + } else {
204 + if (cardEl) cardEl.style.removeProperty('background-color');
205 + if (isRealColor) wrapper.style.setProperty('background-color', bgColor, 'important');
206 + else wrapper.style.removeProperty('background-color');
207 + }
208 + });
209 + }
210 +
211 + var BF_ALLOWED_ORIGIN = <?php
212 + $bfParsed = wp_parse_url(get_site_url());
213 + $bfOrigin = $bfParsed['scheme'] . '://' . $bfParsed['host'];
214 + if (!empty($bfParsed['port'])) $bfOrigin .= ':' . $bfParsed['port'];
215 + echo wp_json_encode($bfOrigin);
216 + ?>;
217 + window.addEventListener('message', function(e) {
218 + if (!e.origin || e.origin !== BF_ALLOWED_ORIGIN) return;
219 + var d = e.data;
220 + if (!d || !d.__bf) return;
221 +
222 + if (d.type === 'bf:css') {
223 + var el = document.getElementById('bf-live-preview-css');
224 + if (!el) {
225 + el = document.createElement('style');
226 + el.id = 'bf-live-preview-css';
227 + document.head.appendChild(el);
228 + }
229 + el.textContent = d.css;
230 + }
231 +
232 + if (d.type === 'bf:settings') {
233 + applyLiveSettings(d.settings);
234 + }
235 +
236 + if (d.type === 'bf:navigate') {
237 + var contentIds = Object.keys(window.bf_globals || {});
238 + for (var i = 0; i < contentIds.length; i++) {
239 + var g = window.bf_globals[contentIds[i]];
240 + var inst = g && g.inits && g.inits.conversational_form;
241 + if (inst && typeof inst.goToStep === 'function') { inst.goToStep(d.stepIndex); break; }
242 + }
243 + }
244 + });
245 + })();
54 246 </script>
55 - <script src="<?= BITFORMS_UPLOAD_BASE_URL ?>/form-scripts/bitform-conversational-<?= $formID ?>.js"></script>
247 + <?php endif; ?>
56 248 </body>
57 -</html>
249 +
250 +</html>