PluginProbe
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder / 6.2.2
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder v6.2.2
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 / app / Services / FluentConversational / Classes / Form.php

Form.php in Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder 6.2.2, at app/Services/FluentConversational/Classes/Form.php

978 lines 41.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentForm\App\Services\FluentConversational\Classes;
4
5 defined('ABSPATH') or die;
6
7 use FluentForm\App\Helpers\Helper;
8 use FluentForm\App\Modules\Acl\Acl;
9 use FluentForm\App\Modules\Payments\PaymentHelper;
10 use FluentForm\App\Modules\Payments\PaymentMethods\Stripe\StripeSettings;
11 use FluentForm\Framework\Helpers\ArrayHelper;
12 use FluentForm\App\Modules\Form\Settings\FormCssJs;
13 use FluentForm\App\Services\FluentConversational\Classes\Converter\Converter;
14 use FluentForm\App\Services\FluentConversational\Classes\Elements\WelcomeScreen;
15
16 class Form
17 {
18 protected $addOnKey = 'conversational_forms';
19
20 protected $metaKey = 'ffc_form_settings';
21
22 public function boot()
23 {
24 add_action('wp', [$this, 'render'], 100);
25
26 add_filter('fluentform/editor_components', [$this, 'filterAcceptedFields'], 999, 2);
27
28 add_filter('fluentform/form_admin_menu', [$this, 'pushDesignTab'], 10, 2);
29
30 add_action('fluentform/form_application_view_conversational_design', [$this, 'renderDesignSettings'], 10, 1);
31
32 add_filter('fluentform/editor_element_settings_placement', [$this, 'maybeAlterPlacement'], 10, 2);
33
34 // elements
35 new WelcomeScreen();
36 }
37
38 public function pushDesignTab($menuItems, $formId)
39 {
40 if (!Helper::isConversionForm($formId)) {
41 return $menuItems;
42 }
43
44 $newItems = $menuItems;
45
46 if (Acl::hasPermission('fluentform_forms_manager')) {
47 $newItems = array_slice($menuItems, 0, 1, true) + [
48 'conversational_design' => [
49 'slug' => 'conversational_design',
50 'title' => __('Design', 'fluentform'),
51 'url' => admin_url('admin.php?page=fluent_forms&form_id=' . $formId . '&route=conversational_design'),
52 ],
53 ] + array_slice($menuItems, 1, count($menuItems) - 1, true);
54 }
55
56 return $newItems;
57 }
58
59 public function renderDesignSettings($formId)
60 {
61 if (!Helper::isConversionForm($formId)) {
62 echo 'Sorry! This is not a conversational form';
63 return;
64 }
65
66 if (function_exists('wp_enqueue_editor')) {
67 add_filter('user_can_richedit', '__return_true');
68 wp_enqueue_editor();
69 wp_enqueue_media();
70 }
71
72 wp_enqueue_script(
73 'fluent_forms_conversational_design',
74 fluentFormMix('js/conversational_design.js'),
75 ['jquery'],
76 FLUENTFORM_VERSION,
77 true
78 );
79
80 $slug = apply_filters_deprecated(
81 'fluentform_conversational_url_slug',
82 [
83 'fluent-form'
84 ],
85 FLUENTFORM_FRAMEWORK_UPGRADE,
86 'fluentform/conversational_url_slug',
87 'Use fluentform/conversational_url_slug instead of fluentform_conversational_url_slug.'
88 );
89
90 $paramKey = apply_filters('fluentform/conversational_url_slug', $slug);
91
92 if ('form' == $paramKey) {
93 $paramKey = 'fluent-form';
94 }
95
96 wp_localize_script('fluent_forms_conversational_design', 'ffc_conv_vars', [
97 'form_id' => $formId,
98 'preview_url' => Helper::getFrontendFacingUrl('?' . $paramKey . '=' . $formId),
99 'fonts' => Fonts::getFonts(),
100 'has_pro' => defined('FLUENTFORMPRO'),
101 ]);
102
103 wp_enqueue_style(
104 'fluent_forms_conversion_style',
105 fluentFormMix('css/conversational_design.css'),
106 [],
107 FLUENTFORM_VERSION
108 );
109
110 echo '<div id="ff_conversation_form_design_app"><design-skeleton><h1 style="text-align: center; margin: 60px 0px;">Loading App Please wait....</h1></design-skeleton><global-search></global-search></div>';
111 }
112
113 public function getDesignSettings($formId)
114 {
115 $settings = Helper::getFormMeta($formId, $this->metaKey . '_design', []);
116
117 $defaults = [
118 'background_color' => '#FFFFFF',
119 'question_color' => '#191919',
120 'answer_color' => '#0445AF',
121 'button_color' => '#0445AF',
122 'button_text_color' => '#FFFFFF',
123 'background_image' => '',
124 'background_brightness' => 0,
125 'disable_branding' => 'no',
126 'hide_media_on_mobile' => 'no',
127 'key_hint' => 'yes',
128 'enable_scroll_to_top' => 'no',
129 'asteriskPlacement' => $this->getAsteriskPlacement($formId)
130 ];
131
132 return wp_parse_args($settings, $defaults);
133 }
134
135 public function getMetaSettings($formId)
136 {
137 $settings = Helper::getFormMeta($formId, $this->metaKey . '_meta', []);
138 $defaults = [
139 'title' => '',
140 'description' => '',
141 'featured_image' => '',
142 'share_key' => '',
143 'google_font_href' => '',
144 'font_css' => '',
145 'i18n' => [
146 'skip_btn' => 'SKIP',
147 'confirm_btn' => 'OK',
148 'continue' => 'Continue',
149 'keyboard_instruction' => 'Press <b>Enter ↵</b>',
150 'multi_select_hint' => 'Choose as many as you like',
151 'single_select_hint' => 'Choose one option',
152 'progress_text' => '{percent}% completed',
153 'long_text_help' => '<b>Shift ⇧</b> + <b>Enter ↵</b> to make a line break.',
154 'invalid_prompt' => 'Please fill out the field correctly',
155 'errorMaxLength' => 'The maximum {maxLength} number of characters accept',
156 'default_placeholder' => 'Type Your answer here',
157 'key_hint_text' => 'Key',
158 'key_hint_tooltip' => 'Press the key to select',
159 'choose_file' => '<b>Choose file</b> or <b>drag here</b>',
160 'limit' => 'Size limit: '
161 ],
162 ];
163
164 if ($settings && !isset($settings['i18n']['key_hint_text'])) {
165 $settings['i18n']['key_hint_text'] = $defaults['i18n']['key_hint_text'];
166 $settings['i18n']['key_hint_tooltip'] = $defaults['i18n']['key_hint_tooltip'];
167 }
168
169 if (!$settings || empty($settings['title'])) {
170 $form = wpFluent()->table('fluentform_forms')->find($formId);
171 $settings['title'] = $form->title;
172 }
173
174 return wp_parse_args($settings, $defaults);
175 }
176
177 private function getGeneratedCss($formId)
178 {
179 $prefix = '.ff_conv_app_' . $formId;
180 if (defined('FLUENTFORMPRO')) {
181 $css = Helper::getFormMeta($formId, $this->metaKey . '_generated_css', '');
182 if ($css) {
183 return $css;
184 }
185 }
186
187 return $prefix . ' { background-color: #FFFFFF; }' . $prefix . ' .ffc-counter-div span { color: #0445AF; }' . $prefix . ' .ffc-counter-div .counter-icon-span svg { fill: #0445AF !important; }' . $prefix . ' .f-label-wrap, ' . $prefix . ' .f-answer { color: #0445AF !important; }' . $prefix . ' .f-label-wrap .f-key { border-color: #0445AF !important; }' . $prefix . ' .f-label-wrap .f-key-hint { border-color: #0445AF !important; }' . $prefix . ' .f-answer .f-radios-wrap ul li { background-color: rgba(4,69,175, 0.1) !important; border: 1px solid #0445AF; }' . $prefix . ' .f-answer .f-radios-wrap ul li:focus { background-color: rgba(4,69,175, 0.3) !important }' . $prefix . ' .f-answer .f-radios-wrap ul li:hover { background-color: rgba(4,69,175, 0.3) !important }' . $prefix . ' .f-answer .f-radios-wrap ul li.f-selected .f-key { background-color: #0445AF !important; color: white; }' . $prefix . ' .f-answer .f-radios-wrap ul li.f-selected .f-key-hint { background-color: #0445AF; }' . $prefix . ' .f-answer .f-radios-wrap ul li.f-selected svg { fill: #0445AF !important; }' . $prefix . ' .f-answer input, ' . $prefix . ' .f-answer textarea{ color: #0445AF !important; box-shadow: #0445AF 0px 1px; }' . $prefix . ' .f-answer input:focus, ' . $prefix . ' .f-answer textarea:focus { box-shadow: #0445AF 0px 2px !important; }' . $prefix . ' .f-answer textarea::placeholder, ' . $prefix . ' .f-answer input::placeholder { color: #0445AF !important; }' . $prefix . ' .text-success { color: #0445AF !important; }' . $prefix . ' .f-answer .f-matrix-table tbody td { background-color: rgba(4,69,175, 0.1); }' . $prefix . ' .f-answer .f-matrix-table input { border-color: rgba(4,69,175, 0.8); }' . $prefix . ' .f-answer .f-matrix-table input.f-radio-control:checked::after { background-color: #0445AF; }' . $prefix . ' .f-answer .f-matrix-table input:focus::before { border-color: #0445AF; }' . $prefix . ' .f-answer .f-matrix-table input.f-checkbox-control:checked { background-color: #0445AF; }' . $prefix . ' .f-answer .f-matrix-table tbody tr::after { border-right-color: #0445AF; }' . $prefix . ' .f-answer .f-matrix-table .f-table-cell.f-row-cell { box-shadow: rgba(4,69,175, 0.1) 0px 0px 0px 100vh inset; }' . $prefix . ' .f-answer .ff_file_upload_field_wrap { background-color: rgba(4,69,175, 0.1); border-color: rgba(4,69,175, 0.8); }' . $prefix . ' .f-answer .ff_file_upload_field_wrap:hover { background-color: rgba(4,69,175, 0.3);}' . $prefix . ' .f-answer .ff_file_upload_field_wrap:focus-within { background-color: rgba(4,69,175, 0.3); }' . $prefix . ' .f-answer .ff-upload-preview { border-color: rgba(4,69,175, 0.8); }' . $prefix . ' .f-answer .ff-upload-preview .ff-upload-thumb { background-color: rgba(4,69,175, 0.3); }' . $prefix . ' .f-answer .ff-upload-preview .ff-upload-details { border-left-color: rgba(4,69,175, 0.8); }' . $prefix . ' .f-answer .ff-upload-preview .ff-upload-details .ff-el-progress { border-left-color: rgba(4,69,175, 0.8); }' . $prefix . ' .f-answer .ff-upload-preview .ff-upload-details .ff-el-progress { background-color: rgba(4,69,175, 0.1); }' . $prefix . ' .f-answer .ff-upload-preview .ff-upload-details .ff-el-progress .ff-el-progress-bar { background-color: #0445AF; }' . $prefix . ' .f-answer .f-star-wrap .f-star-field-wrap::before { background-color: #0445AF; }' . $prefix . ' .f-answer .f-star-wrap .f-star-field-wrap .f-star-field .f-star-field-star .symbolOutline { fill: #0445AF; }' . $prefix . ' .f-answer .f-star-wrap .f-star-field-wrap .f-star-field .f-star-field-rating { color: #0445AF; }' . $prefix . ' .f-answer .f-star-wrap .f-star-field-wrap.is-hovered .symbolFill { fill: rgba(4,69,175, 0.1); }' . $prefix . ' .f-answer .f-star-wrap .f-star-field-wrap.is-selected .symbolFill { fill: #0445AF; }' . $prefix . ' .f-answer .f-payment-summary-wrap tbody td { background-color: rgba(4,69,175, 0.1); }' . $prefix . ' .f-answer .f-payment-summary-wrap tfoot th { background-color: rgba(4,69,175, 0.1); }' . $prefix . ' .f-answer .stripe-inline-holder { border-bottom: 1px solid #0445AF; }' . $prefix . ' .f-answer .StripeElement--focus { border-bottom: 2.5px solid #0445AF; }' . $prefix . ' .ff_conv_input .f-info { color: #0445AF; }' . $prefix . ' .fh2 .f-text { color: #191919; }' . $prefix . ' .fh2 .f-tagline, ' . $prefix . ' .f-sub .f-help { color: rgba(25,25,25, 0.70); }' . $prefix . ' .fh2 .stripe-inline-header { color: #191919; }' . $prefix . ' .q-inner .o-btn-action, ' . $prefix . ' .footer-inner-wrap .f-nav { background-color: #0445AF; }' . $prefix . ' .q-inner .o-btn-action span, ' . $prefix . ' .footer-inner-wrap .f-nav a { color: #FFFFFF; } ' . $prefix . ' .f-enter .f-enter-desc { color: #0445AF; }' . $prefix . ' .footer-inner-wrap .f-nav a svg { fill: #FFFFFF; }' . $prefix . ' .vff-footer .f-progress-bar { background-color: rgba(4,69,175, 0.3); }' . $prefix . ' .vff-footer .f-progress-bar-inner { background-color: #0445AF; }' . $prefix . ' .q-inner .o-btn-action:hover { background-color: #0445AFD6; }' . $prefix . ' .q-inner .o-btn-action:focus::after { border-radius: 6px; inset: -3px; box-shadow: #0445AF 0px 0px 0px 2px; }' . $prefix . ' .f-answer .f-radios-wrap ul li.f-selected .f-key { color: #FFFFFF; }';
188 }
189
190 public function render()
191 {
192 $slug = 'fluent-form';
193 $paramKey = apply_filters_deprecated(
194 'fluentform_conversational_url_slug',
195 [
196 $slug
197 ],
198 FLUENTFORM_FRAMEWORK_UPGRADE,
199 'fluentform/conversational_url_slug',
200 'Use fluentform/conversational_url_slug instead of fluentform_conversational_url_slug.'
201 );
202
203 $paramKey = apply_filters('fluentform/conversational_url_slug', $paramKey);
204
205 if ('form' == $paramKey) {
206 $paramKey = $slug;
207 }
208
209 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Public form display, no nonce needed
210 if(!isset($_REQUEST[$paramKey])) {
211 return;
212 }
213
214 $request = wpFluentForm('request')->get();
215
216 if ((isset($request[$paramKey])) && !wp_doing_ajax()) {
217 $formId = (int) ArrayHelper::get($request, $paramKey);
218 if (!Helper::isConversionForm($formId)) {
219 return;
220 }
221 $shareKey = ArrayHelper::get($request, 'form');
222 $this->renderFormHtml($formId, $shareKey);
223 }
224 }
225
226 public function isEnabled()
227 {
228 $globalModules = get_option('fluentform_global_modules_status');
229
230 $addOn = ArrayHelper::get($globalModules, $this->addOnKey);
231
232 if (!$addOn || 'yes' == $addOn) {
233 return true;
234 }
235
236 return false;
237 }
238
239 private function getSubmitBttnStyle($form)
240 {
241 $data = $form->submit_button;
242 $styles = '';
243
244 if ('' == ArrayHelper::get($data, 'settings.button_style')) {
245 // it's a custom button
246 $buttonActiveStyles = ArrayHelper::get($data, 'settings.normal_styles', []);
247 $buttonHoverStyles = ArrayHelper::get($data, 'settings.hover_styles', []);
248 $activeStates = '';
249 foreach ($buttonActiveStyles as $styleAtr => $styleValue) {
250 if ('0' != $styleValue && !$styleValue) {
251 continue;
252 }
253 if ('borderRadius' == $styleAtr) {
254 $styleValue .= 'px';
255 }
256 $activeStates .= ltrim(strtolower(preg_replace('/[A-Z]([A-Z](?![a-z]))*/', '-$0', $styleAtr)), '_') . ':' . $styleValue . ';';
257 }
258 if ($activeStates) {
259 $styles .= ' .ff-btn-submit { ' . $activeStates . ' }';
260 }
261 $hoverStates = '';
262 foreach ($buttonHoverStyles as $styleAtr => $styleValue) {
263 if ('0' != $styleValue && !$styleValue) {
264 continue;
265 }
266 if ('borderRadius' == $styleAtr) {
267 $styleValue .= 'px';
268 }
269 $hoverStates .= ltrim(strtolower(preg_replace('/[A-Z]([A-Z](?![a-z]))*/', '-$0', $styleAtr)), '-') . ':' . $styleValue . ';';
270 }
271 if ($hoverStates) {
272 $styles .= ' .wpf_has_custom_css.ff-btn-submit:hover { ' . $hoverStates . ' } ';
273 }
274 } else {
275 $styles .= ' .ff-btn-submit { background-color: ' . ArrayHelper::get($data, 'settings.background_color') . '; color: ' . ArrayHelper::get($data, 'settings.color') . '; }';
276 }
277
278 if (defined('FLUENTFORMPRO')) {
279 $customCssJsClass = new FormCssJs();
280 $customCss = $customCssJsClass->getCss($form->id);
281 $styles .= $customCss;
282 }
283
284 return $styles;
285 }
286
287 public function filterAcceptedFields($components, $formId)
288 {
289 if (!Helper::isConversionForm($formId)) {
290 return $components;
291 }
292
293 $generalFields = ArrayHelper::get($components, 'general', []);
294 $advancedFields = ArrayHelper::get($components, 'advanced', []);
295 $paymentFields = ArrayHelper::get($components, 'payments', []);
296
297 $acceptedFieldElements = [
298 'phone',
299 'select',
300 'select',
301 'ratings',
302 'textarea',
303 'address',
304 'input_name',
305 'input_url',
306 'input_text',
307 'input_date',
308 'input_file',
309 'input_email',
310 'input_radio',
311 'custom_html',
312 'input_image',
313 'input_hidden',
314 'input_number',
315 'tabular_grid',
316 'section_break',
317 'select_country',
318 'input_checkbox',
319 'input_password',
320 'terms_and_condition',
321 'gdpr_agreement',
322 'multi_payment_component',
323 'subscription_payment_component',
324 'custom_payment_component',
325 'item_quantity_component',
326 'payment_method',
327 'payment_summary_component',
328 'payment_coupon',
329 'recaptcha',
330 'hcaptcha',
331 'turnstile',
332 'quiz_score',
333 'save_progress_button',
334 'dynamic_field',
335 'rangeslider',
336 'net_promoter_score'
337 ];
338
339 if (defined('FLUENTFORM_SIGNATURE')) {
340 $acceptedFieldElements[] = 'signature';
341 }
342
343 $acceptedFieldElements = apply_filters(
344 'fluentform/conversational_accepted_field_elements',
345 $acceptedFieldElements,
346 $formId
347 );
348
349 $elements = [];
350
351 $allFields = [
352 'general' => $generalFields,
353 'advanced' => $advancedFields,
354 'payments' => $paymentFields,
355 ];
356
357 foreach ($allFields as $groupType => $group) {
358 foreach ($group as $field) {
359 $element = $field['element'];
360 if (in_array($element, $acceptedFieldElements)) {
361 $field['style_pref'] = [
362 'layout' => 'default',
363 'media' => fluentFormGetRandomPhoto(),
364 'brightness' => 0,
365 'alt_text' => '',
366 'media_x_position' => 50,
367 'media_y_position' => 50,
368 ];
369
370 if ('terms_and_condition' == $element || 'gdpr_agreement' == $element) {
371 $existingSettings = $field['settings'];
372 $existingSettings['tc_agree_text'] = __('I accept', 'fluentform');
373 if ('terms_and_condition' == $element) {
374 $existingSettings['tc_dis_agree_text'] = __('I don\'t accept', 'fluentform');
375 $existingSettings['hide_disagree'] = false;
376 }
377 $field['settings'] = $existingSettings;
378 }
379 //adding required settings for captcha in conversational form
380 if ('hcaptcha' == $element || 'recaptcha' == $element || 'turnstile' == $element) {
381 $existingSettings = $field['settings'];
382 if (empty($existingSettings['validation_rules'])) {
383 $existingSettings['validation_rules'] = [
384 'required' => [
385 'value' => true,
386 'message' => __('This field is required', 'fluentform'),
387 ],
388 ];
389 }
390 $field['settings'] = $existingSettings;
391 }
392
393 $elements[$groupType][] = $field;
394 }
395 }
396 }
397
398 $elements = apply_filters_deprecated(
399 'fluent_conversational_editor_elements',
400 [
401 $elements
402 ],
403 FLUENTFORM_FRAMEWORK_UPGRADE,
404 'fluentform/conversational_editor_elements',
405 'Use fluentform/conversational_editor_elements instead of fluent_conversational_editor_elements.'
406 );
407
408 $elements = apply_filters('fluentform/conversational_editor_elements', $elements, $formId);
409
410 return $elements;
411 }
412
413 public function printLoadedScripts()
414 {
415 $jsScripts = $this->getRegisteredScripts();
416 if ($jsScripts) {
417 add_action('fluentform/conversational_frame_footer', function () use ($jsScripts) {
418 foreach ($jsScripts as $handle => $jsScript) {
419 if (empty($jsScript->src)) {
420 continue;
421 }
422 if ($data = ArrayHelper::get($jsScript->extra, 'data')) {
423 printf("<script type='text/javascript' id='%s-js-extra'>\n", esc_attr($handle));
424 echo "$data\n"; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- $data is hardcoded localized data and escaped before being passed in.
425 echo "</script>\n";
426 }
427 $src = $jsScript->src;
428 $src = add_query_arg('ver', $jsScript->ver, $src);
429 echo "<script type='text/javascript' id='" . esc_attr($handle) . "' src='" . esc_url($src) . "'></script>\n";
430 }
431 }, 1);
432 }
433
434 $cssStyles = $this->getRegisteredStyles();
435 if ($cssStyles) {
436 add_action('fluentform/conversational_frame_head', function () use ($cssStyles) {
437 foreach ($cssStyles as $styleName => $cssStyle) {
438 if (empty($cssStyle->src)) {
439 continue;
440 }
441 $src = add_query_arg('ver', $cssStyle->ver, $cssStyle->src);
442 // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedStylesheet -- Completely a custom rendering page.
443 echo "<link rel='stylesheet' id='" . esc_attr($styleName) . "' href='" . esc_url($src) . "' type='text/css' media='all' />\n";
444 }
445 });
446 }
447 }
448
449 private function getRegisteredScripts()
450 {
451 global $wp_scripts;
452 if (!$wp_scripts) {
453 return [];
454 }
455
456 $jsScripts = [];
457
458 $pluginUrl = plugins_url() . '/fluentform';
459
460 foreach ($wp_scripts->queue as $script) {
461
462 if (!isset($wp_scripts->registered[$script])) {
463 continue;
464 }
465
466 $item = $wp_scripts->registered[$script];
467 $src = $wp_scripts->registered[$script]->src;
468
469 if (false === !strpos($src, $pluginUrl)) {
470 continue;
471 }
472
473 foreach ($item->deps as $dep) {
474 if (isset($wp_scripts->registered[$dep])) {
475 $child = $wp_scripts->registered[$dep];
476 if ($child->src) {
477 $jsScripts[$dep] = $child;
478 } else {
479 // this core file maybe
480 $childDependencies = $child->deps;
481 foreach ($childDependencies as $childDependency) {
482 $childX = $wp_scripts->registered[$childDependency];
483 if ($childX->src) {
484 $jsScripts[$childDependency] = $childX;
485 }
486 }
487 }
488 }
489 }
490 $jsScripts[$script] = $item;
491 }
492
493 return $jsScripts;
494 }
495
496 private function getRegisteredStyles()
497 {
498 $wp_styles = wp_styles();
499 if (!$wp_styles) {
500 return [];
501 }
502
503 $cssStyles = [];
504
505 $pluginUrl = plugins_url() . '/fluentform';
506
507 foreach ($wp_styles->queue as $style) {
508
509 if (!isset($wp_styles->registered[$style])) {
510 continue;
511 }
512
513 $item = $wp_styles->registered[$style];
514 $src = $wp_styles->registered[$style]->src;
515
516 if (false === !strpos($src, $pluginUrl)) {
517 continue;
518 }
519
520 if ($item->deps) {
521 foreach ($item->deps as $dep) {
522 if (isset($wp_styles->registered[$dep])) {
523 $child = $wp_styles->registered[$dep];
524 if ($child->src) {
525 $cssStyles[$dep] = $child;
526 } else {
527 // this core file maybe
528 $childDependencies = $child->deps;
529 if ($childDependencies && is_array($childDependencies)) {
530 foreach ($childDependencies as $childDependency) {
531 $childX = $wp_styles->registered[$childDependency];
532 if ($childX->src) {
533 $cssStyles[$childDependency] = $childX;
534 }
535 }
536 }
537 }
538 }
539 }
540 }
541
542 $cssStyles[$style] = $item;
543 }
544
545 return $cssStyles;
546 }
547
548 public function renderShortcode($form)
549 {
550 $formId = $form->id;
551 $form = Converter::convert($form);
552 $this->enqueueScripts();
553 $submitCss = $this->getSubmitBttnStyle($form);
554 $metaSettings = $this->getMetaSettings($formId);
555 $designSettings = $this->getDesignSettings($formId);
556 $instanceId = $form->instance_index;
557 $varName = 'fluent_forms_global_var_' . $instanceId;
558 wp_localize_script('fluent_forms_conversational_form', $varName, [
559 'fluent_forms_admin_nonce' => wp_create_nonce('fluent_forms_admin_nonce'),
560 'ajaxurl' => admin_url('admin-ajax.php'),
561 'nonce' => wp_create_nonce(),
562 'form' => $this->getLocalizedForm($form),
563 'assetBaseUrl' => FLUENT_CONVERSATIONAL_FORM_DIR_URL . 'public',
564 'i18n' => $metaSettings['i18n'],
565 'form_id' => $form->id,
566 'hasPro' => defined('FLUENTFORMPRO'),
567 'is_inline_form' => true,
568 'design' => $designSettings,
569 'extra_inputs' => $this->getExtraHiddenInputs($formId),
570 'uploading_txt' => __('Uploading', 'fluentform'),
571 'upload_completed_txt' => __('100% Completed', 'fluentform'),
572 'unknown_error_txt' => __('An unknown error occurred', 'fluentform'),
573 'request_error_txt' => __('An error occurred while processing your request', 'fluentform'),
574 'paymentConfig' => $this->getPaymentConfig($form),
575 'date_i18n' => \FluentForm\App\Modules\Component\Component::getDatei18n(),
576 'file_delete_nonce' => wp_create_nonce('fluentform_file_delete')
577 ]);
578
579 $hasSaveProgressButton = false;
580 $saveProgressButton = [];
581 foreach ($form->fields['fields'] as $item) {
582 if (isset($item['element']) && $item['element'] === 'save_progress_button') {
583 $hasSaveProgressButton = true;
584 $saveProgressButton = $item;
585 }
586 }
587
588 if ($hasSaveProgressButton && $saveProgressButton) {
589 $this->localizeSaveProgressButton($saveProgressButton, $formId);
590 }
591
592 /* This filter is deprecated and will be removed soon */
593 $disableAnalytics = apply_filters('fluentform-disabled_analytics', true);
594
595 if (!apply_filters('fluentform/disabled_analytics', $disableAnalytics)) {
596 if (!Acl::hasAnyFormPermission($form->id)) {
597 (new \FluentForm\App\Services\Analytics\AnalyticsService())->store($formId);
598 }
599 }
600
601 return wpFluentForm('view')->make('public.conversational-form-inline', [
602 'generated_css' => $this->getGeneratedCss($formId),
603 'design' => $designSettings,
604 'submit_css' => $submitCss,
605 'form_id' => $formId,
606 'meta' => $metaSettings,
607 'global_var_name' => $varName,
608 'instance_id' => $instanceId,
609 'is_inline' => 'yes',
610 ]);
611 }
612
613 public function maybeAlterPlacement($placements, $form)
614 {
615 if (!Helper::isConversionForm($form->id) || empty($placements['terms_and_condition']) || empty($placements['gdpr_agreement'])) {
616 return $placements;
617 }
618
619 $placements['terms_and_condition']['general'] = [
620 'admin_field_label',
621 'validation_rules',
622 'tnc_html',
623 'tc_agree_text',
624 'tc_dis_agree_text',
625 ];
626
627 $placements['terms_and_condition']['generalExtras'] = [
628 'tc_agree_text' => [
629 'template' => 'inputText',
630 'label' => 'Agree Button Text',
631 ],
632 'tc_dis_agree_text' => [
633 'template' => 'inputText',
634 'label' => 'Disagree Button Text',
635 ],
636 'hide_disagree' => [
637 'template' => 'inputCheckbox',
638 'options' => [
639 [
640 'value' => false,
641 'label' => __('Hide Disagree Button', 'fluentform'),
642 ],
643 ],
644 ],
645 ];
646
647 $placements['gdpr_agreement']['generalExtras'] = [
648 'tc_agree_text' => [
649 'template' => 'inputText',
650 'label' => 'Agree Option Text',
651 ],
652 ];
653
654 return $placements;
655 }
656
657 private function getExtraHiddenInputs($formId)
658 {
659 $inputs = [
660 '__fluent_form_embded_post_id' => get_the_ID(),
661 '_fluentform_' . $formId . '_fluentformnonce' => wp_create_nonce('fluentform-submit-form'),
662 '_wp_http_referer' => esc_attr(wp_unslash(wpFluentForm('request')->server('REQUEST_URI'))),
663 ];
664
665 return apply_filters('fluentform/conversational_extra_inputs', $inputs, $formId);
666 }
667
668 public function getRandomPhoto()
669 {
670 return fluentFormGetRandomPhoto();
671 }
672
673 private function renderFormHtml($formId, $providedKey = '')
674 {
675 $form = wpFluent()->table('fluentform_forms')->find($formId);
676
677 if (!$form) {
678 return '';
679 }
680
681 $formSettings = wpFluent()
682 ->table('fluentform_form_meta')
683 ->where('form_id', $formId)
684 ->where('meta_key', 'formSettings')
685 ->first();
686
687 if (!$formSettings) {
688 return '';
689 }
690
691 $form->fields = json_decode($form->form_fields, true);
692
693 if (!$form->fields['fields']) {
694 return '';
695 }
696
697 $form->settings = json_decode($formSettings->value, true);
698
699 if ($form->status == 'unpublished') {
700 global $wp_query;
701 $wp_query->set_404();
702 status_header(404);
703 nocache_headers();
704 include(get_query_template('404'));
705 exit();
706 }
707
708 $metaSettings = $this->getMetaSettings($formId);
709
710 $shareKey = ArrayHelper::get($metaSettings, 'share_key');
711 if ($shareKey) {
712 if ($providedKey != $shareKey && !Acl::hasAnyFormPermission($formId)) {
713 return '';
714 }
715 }
716
717 $isRenderable = apply_filters('fluentform/is_form_renderable', [
718 'status' => true,
719 'message' => '',
720 ], $form);
721
722 if (is_array($isRenderable) && !$isRenderable['status'] && !Acl::hasAnyFormPermission($formId)) {
723
724 echo wp_kses_post("<div style='text-align: center; font-size: 16px; margin: 100px 20px;' id='ff_form_{$form->id}' class='ff_form_not_render'>" . $isRenderable['message'] . "</div>");
725 exit(200);
726 }
727
728
729 /* This filter is deprecated and will be removed soon */
730 $form = wpFluentForm()->applyFilters('fluentform_rendering_form', $form);
731
732 $form = wpFluentForm()->applyFilters('fluentform/rendering_form', $form);
733 $form = Converter::convert($form);
734 $this->enqueueScripts();
735
736 $formSettings = wpFluent()
737 ->table('fluentform_form_meta')
738 ->where('form_id', $form->id)
739 ->where('meta_key', 'formSettings')
740 ->first();
741
742 if (!$formSettings) {
743 return '';
744 }
745
746 $form->settings = json_decode($formSettings->value, true);
747
748 $submitCss = $this->getSubmitBttnStyle($form);
749
750 $designSettings = $this->getDesignSettings($formId);
751
752 wp_localize_script('fluent_forms_conversational_form', 'fluent_forms_global_var', [
753 'fluent_forms_admin_nonce' => wp_create_nonce('fluent_forms_admin_nonce'),
754 'ajaxurl' => admin_url('admin-ajax.php'),
755 'nonce' => wp_create_nonce(),
756 'form' => $this->getLocalizedForm($form),
757 'form_id' => $form->id,
758 'assetBaseUrl' => FLUENT_CONVERSATIONAL_FORM_DIR_URL . 'public',
759 'i18n' => $metaSettings['i18n'],
760 'design' => $designSettings,
761 'hasPro' => defined('FLUENTFORMPRO'),
762 'extra_inputs' => $this->getExtraHiddenInputs($formId),
763 'uploading_txt' => __('Uploading', 'fluentform'),
764 'upload_completed_txt' => __('100% Completed', 'fluentform'),
765 'unknown_error_txt' => __('An unknown error occurred', 'fluentform'),
766 'request_error_txt' => __('An error occurred while processing your request', 'fluentform'),
767 'paymentConfig' => $this->getPaymentConfig($form),
768 'date_i18n' => \FluentForm\App\Modules\Component\Component::getDatei18n(),
769 'rest' => Helper::getRestInfo(),
770 'file_delete_nonce' => wp_create_nonce('fluentform_file_delete')
771 ]);
772
773 $hasSaveProgressButton = false;
774 $saveProgressButton = [];
775 foreach ($form->fields['fields'] as $item) {
776 if (isset($item['element']) && $item['element'] === 'save_progress_button') {
777 $hasSaveProgressButton = true;
778 $saveProgressButton = $item;
779 }
780 }
781
782 if ($hasSaveProgressButton && $saveProgressButton) {
783 $this->localizeSaveProgressButton($saveProgressButton, $formId);
784 }
785
786 $this->printLoadedScripts();
787
788 $isRenderable = [
789 'status' => true,
790 'message' => '',
791 ];
792
793 /* This filter is deprecated and will be removed soon */
794 $isRenderable = apply_filters('fluentform_is_form_renderable', $isRenderable, $form);
795
796
797 $isRenderable = apply_filters('fluentform/is_form_renderable', $isRenderable, $form);
798
799 if (is_array($isRenderable) && !$isRenderable['status']) {
800 if (!Acl::hasAnyFormPermission($form->id)) {
801 echo wp_kses_post("<h1 style='width: 600px; margin: 200px auto; text-align: center;' id='ff_form_{$form->id}' class='ff_form_not_render'>" . $isRenderable['message'] . '</h1>');
802 exit();
803 }
804 }
805 /* This filter is deprecated and will be removed soon */
806 $status = apply_filters('fluentform-disabled_analytics', true);
807
808 if (!apply_filters('fluentform/disabled_analytics', $status)) {
809 if (!Acl::hasAnyFormPermission($form->id)) {
810 (new \FluentForm\App\Services\Analytics\AnalyticsService())->store($form->id);
811 }
812 }
813 wpFluentForm('view')->render('public.conversational-form', [
814 'generated_css' => $this->getGeneratedCss($formId),
815 'design' => $designSettings,
816 'submit_css' => $submitCss,
817 'form_id' => $formId,
818 'meta' => $metaSettings,
819 'form' => $form,
820 ]);
821
822 exit(200);
823 }
824
825 /**
826 * Enqueue proper stylesheet based on rtl & JS script.
827 */
828 private function enqueueScripts()
829 {
830 $cssFileName = 'conversationalForm';
831
832 if (is_rtl()) {
833 $cssFileName .= '-rtl';
834 }
835
836 wp_enqueue_style(
837 'fluent_forms_conversational_form',
838 FLUENT_CONVERSATIONAL_FORM_DIR_URL . 'public/css/' . $cssFileName . '.css',
839 [],
840 FLUENTFORM_VERSION
841 );
842
843 wp_enqueue_script(
844 'fluent_forms_conversational_form',
845 FLUENT_CONVERSATIONAL_FORM_DIR_URL . 'public/js/conversationalForm.js',
846 [],
847 FLUENTFORM_VERSION,
848 true
849 );
850 }
851
852 /**
853 * Get the payment configuration of this form.
854 *
855 * @param $form
856 */
857 private function getPaymentConfig($form)
858 {
859 $paymentConfig = null;
860
861 if ($form->has_payment) {
862 $publishableKeyStripe = StripeSettings::getPublishableKey($form->id);
863 $publishableKeyStripe = apply_filters_deprecated(
864 'fluentform-payment_stripe_publishable_key',
865 [
866 $publishableKeyStripe,
867 $form->id
868 ],
869 FLUENTFORM_FRAMEWORK_UPGRADE,
870 'fluentform/payment_stripe_publishable_key',
871 'Use fluentform/payment_stripe_publishable_key instead of fluentform-payment_stripe_publishable_key.'
872 );
873
874 $publishableKey = apply_filters(
875 'fluentform/payment_stripe_publishable_key',
876 $publishableKeyStripe,
877 $form->id
878 );
879
880 $paymentConfig = [
881 'currency_settings' => PaymentHelper::getCurrencyConfig($form->id),
882 'stripe' => [
883 'publishable_key' => $publishableKey,
884 'inlineConfig' => PaymentHelper::getStripeInlineConfig($form->id),
885 ],
886 'stripe_app_info' => [
887 'name' => 'Fluent Forms',
888 'version' => FLUENTFORM_VERSION,
889 'url' => site_url(),
890 'partner_id' => 'pp_partner_FN62GfRLM2Kx5d',
891 ],
892 'i18n' => [
893 'item' => __('Item', 'fluentform'),
894 'price' => __('Price', 'fluentform'),
895 'qty' => __('Qty', 'fluentform'),
896 'line_total' => __('Line Total', 'fluentform'),
897 'total' => __('Total', 'fluentform'),
898 'not_found' => __('No payment item selected yet', 'fluentform'),
899 'discount:' => __('Discount:', 'fluentform'),
900 'processing_text' => __('Processing payment. Please wait...', 'fluentform'),
901 'confirming_text' => __('Confirming payment. Please wait...', 'fluentform'),
902 'signup_fee_for' => __('Signup Fee for', 'fluentform'),
903 ],
904 ];
905
906 $paymentConfig['currency_settings']['currency_symbol'] = \html_entity_decode($paymentConfig['currency_settings']['currency_sign']);
907 }
908
909 return $paymentConfig;
910 }
911
912 protected function getAsteriskPlacement($formId)
913 {
914 $asteriskPlacement = 'asterisk-right';
915
916 $formSettings = wpFluent()
917 ->table('fluentform_form_meta')
918 ->where('form_id', $formId)
919 ->where('meta_key', 'formSettings')
920 ->first();
921
922 if (!$formSettings) {
923 return '';
924 }
925
926 $formSettings = json_decode($formSettings->value, true);
927
928 if (isset($formSettings['layout']['asteriskPlacement'])) {
929 $asteriskPlacement = $formSettings['layout']['asteriskPlacement'];
930 }
931
932 return $asteriskPlacement;
933 }
934
935 private function getLocalizedForm($form)
936 {
937 return [
938 'id' => $form->id,
939 'questions' => $form->questions,
940 'image_preloads' => $form->image_preloads,
941 'submit_button' => $form->submit_button,
942 'hasPayment' => (bool)$form->has_payment,
943 'hasCalculation' => (bool)$form->hasCalculation,
944 'reCaptcha' => $form->reCaptcha,
945 'hCaptcha' => $form->hCaptcha,
946 'turnstile' => $form->turnstile,
947 'has_per_step_save' => ArrayHelper::get($form->settings, 'conv_form_per_step_save', false),
948 'has_resume_from_last_step' => ArrayHelper::get($form->settings, 'conv_form_resume_from_last_step', false),
949 'has_save_link' => $form->save_state?? false,
950 'has_save_and_resume_button'=> $form->hasSaveAndResumeButton ?? false,
951 'step_completed' => $form->stepCompleted ?? 0
952 ];
953 }
954
955 public function localizeSaveProgressButton($field, $formId)
956 {
957 $vars = apply_filters('fluentform/save_progress_vars', [
958 'ajaxurl' => admin_url('admin-ajax.php'),
959 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated, WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized in getFrontendFacingUrl()
960 'source_url' => Helper::getFrontendFacingUrl($_SERVER['REQUEST_URI']),
961 'form_id' => $formId,
962 'nonce' => wp_create_nonce(),
963 'copy_button' => fluentFormMix('img/copy.svg'),
964 'copy_success_button' => fluentFormMix('img/check.svg'),
965 'email_button' => fluentFormMix('img/email.svg'),
966 'email_placeholder_str' => __('Your Email Here', 'fluentform'),
967 'email_resume_link_enabled' => false,
968 'save_progress_btn_name' => ArrayHelper::get($field, 'attributes.name'),
969 ]);
970
971 if (ArrayHelper::get($field, 'settings.email_resume_link_enabled')) {
972 $vars['email_resume_link_enabled'] = true;
973 }
974
975 wp_localize_script('fluent_forms_conversational_form', 'form_state_save_vars', $vars);
976 }
977 }
978