PluginProbe
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder / 4.3.13
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder v4.3.13
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 3.6.66 All 195 releases
fluentform / app / Modules / Component / Component.php

Component.php in Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder 4.3.13, at app/Modules/Component/Component.php

1,188 lines 46.5 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\Modules\Component;
4
5 use FluentForm\App\Helpers\Helper;
6 use FluentForm\App\Modules\Acl\Acl;
7 use FluentForm\App\Services\FormBuilder\EditorShortcodeParser;
8 use FluentForm\App\Services\FormBuilder\Notifications\EmailNotificationActions;
9 use FluentForm\Framework\Foundation\Application;
10 use FluentForm\Framework\Helpers\ArrayHelper;
11
12 class Component
13 {
14 /**
15 * FluentForm\Framework\Foundation\Application
16 *
17 * @var $app
18 */
19 protected $app = null;
20
21 /**
22 * Determine whether to register Elementor PopUp handler.
23 *
24 * @var bool
25 */
26 protected $elementorPopUpHandler = false;
27
28 /**
29 * Biuld the instance of this class
30 *
31 * @param \FluentForm\Framework\Foundation\Application $app
32 */
33 public function __construct(Application $app)
34 {
35 $this->app = $app;
36 }
37
38 public function registerScripts()
39 {
40 $app = $this->app;
41
42 // We will just register the scripts here. We will not load any scripts from here
43
44 $fluentFormPublicCss = $app->publicUrl('css/fluent-forms-public.css');
45 $fluentFormPublicDefaultCss = $app->publicUrl('css/fluentform-public-default.css');
46
47 if (is_rtl()) {
48 $fluentFormPublicCss = $app->publicUrl('css/fluent-forms-public-rtl.css');
49 $fluentFormPublicDefaultCss = $app->publicUrl('css/fluentform-public-default-rtl.css');
50 }
51
52 wp_register_style(
53 'fluent-form-styles',
54 $fluentFormPublicCss,
55 array(),
56 FLUENTFORM_VERSION
57 );
58
59 wp_register_style(
60 'fluentform-public-default',
61 $fluentFormPublicDefaultCss,
62 array(),
63 FLUENTFORM_VERSION
64 );
65
66 wp_register_script(
67 'fluent-form-submission',
68 $app->publicUrl('js/form-submission.js'),
69 array('jquery'),
70 FLUENTFORM_VERSION,
71 true
72 );
73
74 wp_register_script(
75 'fluentform-advanced',
76 $app->publicUrl('js/fluentform-advanced.js'),
77 array('jquery'),
78 FLUENTFORM_VERSION,
79 true
80 );
81
82 // Date Pickckr Style
83 //fix for essential addon event picker conflict
84 if (!wp_script_is('flatpickr', 'registered')) {
85 wp_register_style(
86 'flatpickr',
87 $app->publicUrl('libs/flatpickr/flatpickr.min.css')
88 );
89 }
90 // Date Pickckr Script
91 wp_register_script(
92 'flatpickr',
93 $app->publicUrl('libs/flatpickr/flatpickr.js'),
94 array('jquery'),
95 false,
96 true
97 );
98
99 wp_register_script(
100 'choices',
101 $app->publicUrl('libs/choices/choices.min.js'),
102 array(),
103 '9.0.1',
104 true
105 );
106
107 wp_register_style(
108 'ff_choices',
109 $app->publicUrl('css/choices.css'),
110 [],
111 FLUENTFORM_VERSION
112 );
113
114 wp_register_script(
115 'form-save-progress',
116 $app->publicUrl('js/form-save-progress.js'),
117 ['jquery'],
118 FLUENTFORM_VERSION,
119 true
120 );
121
122 do_action('fluentform_scripts_registered');
123
124 $this->maybeLoadFluentFormStyles();
125 }
126
127 protected function maybeLoadFluentFormStyles()
128 {
129 global $post;
130
131 $postId = isset( $post->ID ) ? $post->ID : false;
132 if (!$postId) {
133 return;
134 }
135 $fluentFormIds = get_post_meta($postId, '_has_fluentform', true);
136 $hasFluentformMeta = is_a($post, 'WP_Post') && $fluentFormIds;
137
138 if ($hasFluentformMeta || apply_filters('fluentform_load_styles', false, $post)) {
139 wp_enqueue_style('fluent-form-styles');
140 wp_enqueue_style('fluentform-public-default');
141 do_action('fluentform_pre_load_scripts', $post);
142 wp_enqueue_script('fluent-form-submission');
143 }
144 }
145
146 /**
147 * Get all the available components
148 *
149 * @return void
150 * @throws \Exception
151 * @throws \FluentForm\Framework\Exception\UnResolveableEntityException
152 */
153 public function index()
154 {
155 $formId = intval($_REQUEST['formId']);
156 $components = $this->app->make('components');
157
158 $this->app->doAction('fluent_editor_init', $components);
159
160 $editorComponents = $components->sort()->toArray();
161 $editorComponents = apply_filters('fluent_editor_components', $editorComponents, $formId);
162
163 $countries = $this->app->load($this->app->appPath('Services/FormBuilder/CountryNames.php'));
164
165 wp_send_json_success(array(
166 'countries' => $countries,
167 'components' => $editorComponents,
168 'disabled_components' => $this->getDisabledComponents()
169 ));
170 }
171
172
173 /**
174 * Get disabled components
175 *
176 * @return array
177 */
178 private function getDisabledComponents()
179 {
180 $isReCaptchaDisabled = !get_option('_fluentform_reCaptcha_keys_status', false);
181 $isHCaptchaDisabled = !get_option('_fluentform_hCaptcha_keys_status', false);
182 $isTurnstileDisabled = !get_option('_fluentform_turnstile_keys_status', false);
183
184 $disabled = array(
185 'recaptcha' => array(
186 'disabled' => $isReCaptchaDisabled,
187 'title' => __('reCaptcha', 'fluentform'),
188 'description' => __('Please enter a valid API key on FluentForms->Settings->reCaptcha', 'fluentform'),
189 'hidePro' => true
190 ),
191 'hcaptcha' => array(
192 'disabled' => $isHCaptchaDisabled,
193 'title' => __('hCaptcha', 'fluentform'),
194 'description' => __('Please enter a valid API key on FluentForms->Settings->hCaptcha', 'fluentform'),
195 'hidePro' => true
196 ),
197 'turnstile' => array(
198 'disabled' => $isTurnstileDisabled,
199 'title' => __('Turnstile', 'fluentform'),
200 'description' => __('Please enter a valid API key on FluentForms->Settings->Turnstile', 'fluentform'),
201 'hidePro' => true
202 ),
203 'input_image' => array(
204 'disabled' => true,
205 'title' => __('Image Upload', 'fluentform'),
206 'description' => __('Image Upload is not available with the free version. Please upgrade to pro to get all the advanced features.', 'fluentform'),
207 'image' => '',
208 'video' => 'https://www.youtube.com/embed/Yb3FSoZl9Zg'
209 ),
210 'input_file' => array(
211 'disabled' => true,
212 'title' => __('File Upload', 'fluentform'),
213 'description' => __('File Upload is not available with the free version. Please upgrade to pro to get all the advanced features.', 'fluentform'),
214 'image' => '',
215 'video' => 'https://www.youtube.com/embed/bXbTbNPM_4k'
216 ),
217 'shortcode' => array(
218 'disabled' => true,
219 'title' => __('Shortcode', 'fluentform'),
220 'description' => __('Shortcode is not available with the free version. Please upgrade to pro to get all the advanced features.', 'fluentform'),
221 'image' => '',
222 'video' => 'https://www.youtube.com/embed/op3mEQxX1MM'
223 ),
224 'action_hook' => array(
225 'disabled' => true,
226 'title' => __('Action Hook', 'fluentform'),
227 'description' => __('Action Hook is not available with the free version. Please upgrade to pro to get all the advanced features.', 'fluentform'),
228 'image' => $this->app->publicUrl('img/pro-fields/Action Hook.png'),
229 'video' => ''
230 ),
231 'form_step' => array(
232 'disabled' => true,
233 'title' => __('Form Step', 'fluentform'),
234 'description' => __('Form Step is not available with the free version. Please upgrade to pro to get all the advanced features.', 'fluentform'),
235 'image' => '',
236 'video' => 'https://www.youtube.com/embed/VQTWnM6BbRU'
237 )
238 );
239
240 if (!defined('FLUENTFORMPRO')) {
241 $disabled['ratings'] = array(
242 'disabled' => true,
243 'title' => __('Ratings', 'fluentform'),
244 'description' => __('Ratings is not available with the free version. Please upgrade to pro to get all the advanced features.', 'fluentform'),
245 'image' => '',
246 'video' => 'https://www.youtube.com/embed/YGdkNspMaEs'
247 );
248 $disabled['tabular_grid'] = array(
249 'disabled' => true,
250 'title' => __('Checkable Grid', 'fluentform'),
251 'description' => __('Checkable Grid is not available with the free version. Please upgrade to pro to get all the advanced features.', 'fluentform'),
252 'image' => '',
253 'video' => 'https://www.youtube.com/embed/ayI3TzXXANA'
254 );
255 $disabled['chained_select'] = array(
256 'disabled' => true,
257 'title' => __('Chained Select Field', 'fluentform'),
258 'description' => __('Chained Select Field is not available with the free version. Please upgrade to pro to get all the advanced features.', 'fluentform'),
259 'image' => $this->app->publicUrl('img/pro-fields/Chained Select Field.png'),
260 'video' => ''
261 );
262 $disabled['phone'] = array(
263 'disabled' => true,
264 'title' => 'Phone Field',
265 'description' => __('Phone Field is not available with the free version. Please upgrade to pro to get all the advanced features.', 'fluentform'),
266 'image' => $this->app->publicUrl('img/pro-fields/Phone Field.png'),
267 'video' => ''
268 );
269 $disabled['rich_text_input'] = array(
270 'disabled' => true,
271 'title' => __('Rich Text Input', 'fluentform'),
272 'description' => __('Rich Text Input is not available with the free version. Please upgrade to pro to get all the advanced features.', 'fluentform'),
273 'image' => $this->app->publicUrl('img/pro-fields/Rich Text Input.png'),
274 'video' => ''
275 );
276 $disabled['save_progress_button'] = array(
277 'disabled' => true,
278 'title' => __('Save & Resume', 'fluentform'),
279 'description' => __('Save & Resume is not available with the free version. Please upgrade to pro to get all the advanced features.', 'fluentform'),
280 'image' => $this->app->publicUrl('img/pro-fields/Save Progress Button.png'),
281 'video' => ''
282 );
283 $disabled['cpt_selection'] = array(
284 'disabled' => true,
285 'title' => __('Post/CPT Selection', 'fluentform'),
286 'description' => __('Post/CPT Selection is not available with the free version. Please upgrade to pro to get all the advanced features.', 'fluentform'),
287 'image' => $this->app->publicUrl('img/pro-fields/Post_CPT Selection.png'),
288 'video' => ''
289 );
290 $disabled['quiz_score'] = array(
291 'disabled' => true,
292 'title' => __('Quiz Score', 'fluentform'),
293 'description' => __('Quiz Score is not available with the free version. Please upgrade to pro to get all the advanced features.', 'fluentform'),
294 'image' => '',
295 'video' => 'https://www.youtube.com/embed/bPjDXR0y_Oo'
296 );
297 $disabled['net_promoter_score'] = array(
298 'disabled' => true,
299 'title' => __('Net Promoter Score', 'fluentform'),
300 'description' => __('Net Promoter Score is not available with the free version. Please upgrade to pro to get all the advanced features.', 'fluentform'),
301 'image' => $this->app->publicUrl('img/pro-fields/Net Promoter Score.png'),
302 'video' => ''
303 );
304 $disabled['repeater_field'] = array(
305 'disabled' => true,
306 'title' => __('Repeat Field', 'fluentform'),
307 'description' => __('Repeat Field is not available with the free version. Please upgrade to pro to get all the advanced features.', 'fluentform'),
308 'image' => '',
309 'video' => 'https://www.youtube.com/embed/BXo9Sk-OLnQ'
310 );
311 $disabled['rangeslider'] = array(
312 'disabled' => true,
313 'title' => __('Range Slider', 'fluentform'),
314 'description' => __('Range Slider is not available with the free version. Please upgrade to pro to get all the advanced features.', 'fluentform'),
315 'image' => '',
316 'video' => 'https://www.youtube.com/embed/RaY2VcPWk6I'
317 );
318 $disabled['color-picker'] = array(
319 'disabled' => true,
320 'title' => __('Color Picker', 'fluentform'),
321 'description' => __('Color Picker is not available with the free version. Please upgrade to pro to get all the advanced features.', 'fluentform'),
322 'image' => $this->app->publicUrl('img/pro-fields/Color Picker.png'),
323 'video' => ''
324 );
325 $disabled['multi_payment_component'] = array(
326 'disabled' => true,
327 'is_payment' => true,
328 'title' => __('Payment Field', 'fluentform'),
329 'description' => __('Payment Field is not available with the free version. Please upgrade to pro to get all the advanced features.', 'fluentform'),
330 'image' => $this->app->publicUrl('img/pro-fields/Payment Field.png'),
331 'video' => ''
332 );
333 $disabled['custom_payment_component'] = array(
334 'disabled' => true,
335 'is_payment' => true,
336 'title' => 'Custom Payment Amount',
337 'description' => __('Custom Payment Amount is not available with the free version. Please upgrade to pro to get all the advanced features.', 'fluentform'),
338 'image' => $this->app->publicUrl('img/pro-fields/Custom Payment Amount.png'),
339 'video' => ''
340 );
341 $disabled['subscription_payment_component'] = array(
342 'disabled' => true,
343 'is_payment' => true,
344 'title' => __('Subscription Field', 'fluentform'),
345 'description' => __('Subscription Field is not available with the free version. Please upgrade to pro to get all the advanced features.', 'fluentform'),
346 'image' => $this->app->publicUrl('img/pro-fields/Subscription Field.png'),
347 'video' => ''
348 );
349 $disabled['item_quantity_component'] = array(
350 'disabled' => true,
351 'is_payment' => true,
352 'title' => __('Item Quantity', 'fluentform'),
353 'description' => __('Item Quantity is not available with the free version. Please upgrade to pro to get all the advanced features.', 'fluentform'),
354 'image' => $this->app->publicUrl('img/pro-fields/Item Quantity.png'),
355 'video' => ''
356 );
357 $disabled['payment_method'] = array(
358 'disabled' => true,
359 'is_payment' => true,
360 'title' => __('Payment Method', 'fluentform'),
361 'description' => __('Payment Method is not available with the free version. Please upgrade to pro to get all the advanced features.', 'fluentform'),
362 'image' => $this->app->publicUrl('img/pro-fields/Payment Method.png'),
363 'video' => ''
364 );
365 $disabled['payment_summary_component'] = array(
366 'disabled' => true,
367 'is_payment' => true,
368 'title' => __('Payment Summary', 'fluentform'),
369 'description' => __('Payment Summary is not available with the free version. Please upgrade to pro to get all the advanced features.', 'fluentform'),
370 'image' => $this->app->publicUrl('img/pro-fields/Payment Summary.png'),
371 'video' => ''
372 );
373 $disabled['payment_coupon'] = array(
374 'disabled' => true,
375 'title' => __('Coupon', 'fluentform'),
376 'description' => __('Coupon is not available with the free version. Please upgrade to pro to get all the advanced features.', 'fluentform'),
377 'image' => $this->app->publicUrl('img/pro-fields/Coupon.png'),
378 'video' => ''
379 );
380 }
381 return $this->app->applyFilters('fluentform_disabled_components', $disabled);
382 }
383
384 /**
385 * Get available shortcodes for editor
386 *
387 * @return void
388 * @throws \Exception
389 */
390 public function getEditorShortcodes()
391 {
392 $editor_shortcodes = fluentFormEditorShortCodes();
393 wp_send_json_success(['shortcodes' => $editor_shortcodes], 200);
394 }
395
396 /**
397 * Get all available shortcodes for editor
398 *
399 * @return void
400 * @throws \Exception
401 */
402 public function getAllEditorShortcodes()
403 {
404 wp_send_json(fluentFormGetAllEditorShortCodes(
405 $this->app->request->get('formId')
406 ), 200);
407 }
408
409 /**
410 * Register the form renderer shortcode
411 *
412 * @return void
413 */
414 public function addFluentFormShortCode()
415 {
416
417 add_action('wp_enqueue_scripts', array($this, 'registerScripts'), 9);
418
419 $this->app->addShortCode('fluentform', function ($atts, $content) {
420 $shortcodeDefaults = apply_filters('fluentform_shortcode_defaults', array(
421 'id' => null,
422 'title' => null,
423 'css_classes' => '',
424 'permission' => '',
425 'type' => 'classic',
426 'permission_message' => __('Sorry, You do not have permission to view this form', 'fluentform')
427 ), $atts);
428
429 $atts = shortcode_atts($shortcodeDefaults, $atts);
430
431 return $this->renderForm($atts);
432 });
433
434 $this->app->addShortCode('fluentform_info', function ($atts) {
435 $shortcodeDefaults = apply_filters('fluentform_info_shortcode_defaults', array(
436 'id' => null, // This is the form id
437 'info' => 'submission_count', // submission_count | created_at | updated_at | payment_total
438 'status' => 'all', // get submission cound of a particular entry status favourites | unread | read
439 'with_trashed' => 'no', // yes | no
440 'substract_from' => 0, // [fluentform_info id="2" info="submission_count" substract_from="20"]
441 'hide_on_zero' => 'no',
442 'payment_status' => 'all', // it can be all / specific payment status
443 'currency_formatted' => 'yes',
444 'date_format' => ''
445 ), $atts);
446
447 $atts = shortcode_atts($shortcodeDefaults, $atts);
448 $formId = $atts['id'];
449 $form = wpFluent()->table('fluentform_forms')->find($formId);
450
451 if (!$form) {
452 return '';
453 }
454
455 if ($atts['info'] == 'submission_count') {
456 $countQuery = wpFluent()->table('fluentform_submissions')
457 ->where('form_id', $formId);
458
459 if ($atts['status'] != 'trashed' && $atts['with_trashed'] == 'no') {
460 $countQuery = $countQuery->where('status', '!=', 'trashed');
461 }
462
463 if ($atts['status'] == 'all') {
464 // ...
465 } else if ($atts['status'] == 'favourites') {
466 $countQuery = $countQuery->where('is_favourite', '=', 1);
467 } else {
468 $countQuery = $countQuery->where('status', '=', sanitize_key($atts['status']));
469 }
470 if ($atts['payment_status'] && defined('FLUENTFORMPRO') && $atts['payment_status'] != 'all') {
471 $countQuery = $countQuery->where('payment_status', '=', sanitize_key($atts['payment_status']));
472 }
473
474 $total = $countQuery->count();
475
476 if ($atts['substract_from']) {
477 $total = intval($atts['substract_from']) - $total;
478 }
479
480 if ($atts['hide_on_zero'] == 'yes' && !$total || $total < 0) {
481 return '';
482 }
483
484 return $total;
485 } else if ($atts['info'] == 'created_at') {
486 if ($atts['date_format']) {
487 $dateFormat = $atts['date_format'];
488 } else {
489 $dateFormat = get_option('date_format') . ' ' . get_option('time_format');
490 }
491 return date($dateFormat, strtotime($form->created_at));
492 } else if ($atts['info'] == 'updated_at') {
493 if ($atts['date_format']) {
494 $dateFormat = $atts['date_format'];
495 } else {
496 $dateFormat = get_option('date_format') . ' ' . get_option('time_format');
497 }
498 return date($dateFormat, strtotime($form->updated_at));
499 } else if ($atts['info'] == 'payment_total') {
500
501 if (!defined('FLUENTFORMPRO')) {
502 return '';
503 }
504
505 global $wpdb;
506 $countQuery = wpFluent()
507 ->table('fluentform_submissions')
508 ->select(wpFluent()->raw('SUM(payment_total) as payment_total'))
509 ->where('form_id', $formId);
510
511 if ($atts['status'] != 'trashed' && $atts['with_trashed'] == 'no') {
512 $countQuery = $countQuery->where('status', '!=', 'trashed');
513 }
514
515 if ($atts['status'] == 'all') {
516 // ...
517 } else if ($atts['status'] == 'favourites') {
518 $countQuery = $countQuery->where('is_favourite', '=', 1);
519 } else {
520 $countQuery = $countQuery->where('status', '=', sanitize_key($atts['status']));
521 }
522
523 if ($atts['payment_status'] == 'all') {
524 // ...
525 } else if ($atts['payment_status']) {
526 $countQuery = $countQuery->where('payment_status', '=', sanitize_key($atts['payment_status']));
527 }
528
529 $row = $countQuery->first();
530
531 $total = 0;
532 if ($row) {
533 $total = $row->payment_total;
534 }
535
536 if ($atts['substract_from']) {
537 $total = intval($atts['substract_from'] * 100) - $total;
538 }
539
540 if ($atts['hide_on_zero'] == 'yes' && !$total) {
541 return '';
542 }
543
544 if ($atts['currency_formatted'] == 'yes') {
545 $currency = \FluentFormPro\Payments\PaymentHelper::getFormCurrency($formId);
546 return \FluentFormPro\Payments\PaymentHelper::formatMoney($total, $currency);
547 }
548
549 if (!$total) {
550 return 0;
551 }
552
553 return $total / 100;
554 }
555
556 return '';
557 });
558
559 $this->app->addShortCode('ff_get', function ($atts) {
560 $atts = shortcode_atts(array(
561 'param' => '',
562 ), $atts);
563 if ($atts['param'] && isset($_GET[$atts['param']])) {
564 $value = $_GET[$atts['param']];
565 if (is_array($value)) {
566 return implode(', ', $value);
567 }
568 return esc_html($value);
569 }
570 return '';
571 });
572
573 }
574
575 public function renderForm($atts)
576 {
577 $form_id = $atts['id'];
578 $query = wpFluent()->table('fluentform_forms');
579 if (!isset($_GET['preview_id'])) {
580 $query->where('status', 'published');
581 }
582 if ($form_id) {
583 $form = $query->find($form_id);
584 } elseif ($formTitle = $atts['title']) {
585 $form = $query->where('title', $formTitle)->first();
586 } else {
587 return '';
588 }
589
590 if (!$form) {
591 return '';
592 }
593
594 if (!empty($atts['permission'])) {
595 if (!current_user_can($atts['permission'])) {
596 return "<div id='ff_form_{$form->id}' class='ff_form_not_render'>{$atts['permission_message']}</div>";
597 }
598 }
599
600 if (is_feed()) {
601 global $post;
602 $feedText = sprintf(__('The form can be filled in the actual <a href="%s">website url</a>.', 'fluentform'), get_permalink($post));
603 $feedText = apply_filters('fluentform_shortcode_feed_text', $feedText, $form);
604 return $feedText;
605 }
606
607 $formSettings = wpFluent()
608 ->table('fluentform_form_meta')
609 ->where('form_id', $form_id)
610 ->where('meta_key', 'formSettings')
611 ->first();
612
613 if (!$formSettings) {
614 return '';
615 }
616
617 $form->fields = json_decode($form->form_fields, true);
618
619 if (!$form->fields['fields']) {
620 return '';
621 }
622
623 $form->settings = json_decode($formSettings->value, true);
624 $form = $this->app->applyFilters('fluentform_rendering_form', $form);
625
626 $isRenderable = array(
627 'status' => true,
628 'message' => ''
629 );
630
631 $isRenderable = $this->app->applyFilters('fluentform_is_form_renderable', $isRenderable, $form);
632
633 if (is_array($isRenderable) && !$isRenderable['status']) {
634 return "<div id='ff_form_{$form->id}' class='ff_form_not_render'>{$isRenderable['message']}</div>";
635 }
636
637 $instanceCssClass = Helper::getFormInstaceClass($form->id);
638
639 $form->instance_css_class = $instanceCssClass;
640 $form->instance_index = Helper::$formInstance;
641
642
643 if ($atts['type'] == 'conversational') {
644 $this->addInlineVars();
645 return (new \FluentForm\App\Services\FluentConversational\Classes\Form())->renderShortcode($form);
646 }
647
648 $formBuilder = $this->app->make('formBuilder');
649
650 $cssClasses = trim($instanceCssClass . ' ff-form-loading');
651
652 $output = $formBuilder->build($form, $cssClasses, $instanceCssClass, $atts);
653
654 $output = $this->replaceEditorSmartCodes($output, $form);
655
656 if (!wp_script_is('fluent-form-submission', 'registered')) {
657 $this->registerScripts();
658 }
659
660 wp_enqueue_style('fluent-form-styles');
661 if (apply_filters('fluentform_load_default_public', true, $form)) {
662 wp_enqueue_style('fluentform-public-default');
663 }
664 /*
665 * We will load fluentform-advanced if the form has certain fields or feature
666 */
667 $this->maybeHasAdvandedFields($form, $formBuilder);
668 wp_enqueue_script('fluent-form-submission');
669
670 $stepText = __('Step %activeStep% of %totalStep% - %stepTitle%', 'fluentform');
671 $stepText = apply_filters('fluentform_step_string', $stepText);
672 $vars = apply_filters('fluentform_global_form_vars', array(
673 'ajaxUrl' => admin_url('admin-ajax.php'),
674 'forms' => array(),
675 'step_text' => $stepText,
676 'is_rtl' => is_rtl(),
677 'date_i18n' => $this->getDatei18n(),
678 'pro_version' => (defined('FLUENTFORMPRO_VERSION')) ? FLUENTFORMPRO_VERSION : false,
679 'fluentform_version' => FLUENTFORM_VERSION,
680 'force_init' => false,
681 'stepAnimationDuration' => 350,
682 'upload_completed_txt' => __('100% Completed', 'fluentform'),
683 'upload_start_txt' => __('0% Completed', 'fluentform'),
684 'uploading_txt' => __('Uploading', 'fluentform'),
685 'choice_js_vars' => [
686 'noResultsText' => __('No results found', 'fluentform'),
687 'loadingText' => __('Loading...', 'fluentform'),
688 'noChoicesText' => __('No choices to choose from', 'fluentform'),
689 'itemSelectText' => __('Press to select', 'fluentform'),
690 'maxItemText' => __('Only %%maxItemCount%% options can be added', 'fluentform'),
691 ],
692 'input_mask_vars' => [
693 'clearIfNotMatch' => false,
694 ]
695 ));
696
697 wp_localize_script('fluent-form-submission', 'fluentFormVars', $vars);
698
699 $formSettings = $form->settings;
700
701 $formSettings = ArrayHelper::only($formSettings, ['layout', 'id']);
702
703 $formSettings['restrictions']['denyEmptySubmission'] = [
704 'enabled' => false
705 ];
706
707 $form_vars = array(
708 'id' => $form->id,
709 'settings' => $formSettings,
710 'form_instance' => $instanceCssClass,
711 'form_id_selector' => 'fluentform_' . $form->id,
712 'rules' => $formBuilder->validationRules
713 );
714
715 if ($conditionals = $formBuilder->conditions) {
716 $form_vars['conditionals'] = $conditionals;
717 }
718
719 $form_vars = apply_filters('fluentform/form_vars_for_JS', $form_vars, $form);
720
721 if ($form->has_payment) {
722 do_action('fluentform_rendering_payment_form', $form);
723 }
724
725 $otherScripts = '';
726 ob_start();
727 ?>
728 <script type="text/javascript">
729 window.fluent_form_<?php echo esc_attr($instanceCssClass); ?> = <?php echo wp_json_encode($form_vars);?>;
730 <?php if(wp_doing_ajax()): ?>
731 function initFFInstance_<?php echo esc_attr($form_vars['id']); ?>() {
732 if (!window.fluentFormApp) {
733 console.log('No fluentFormApp found');
734 return;
735 }
736 var ajax_formInstance = window.fluentFormApp(jQuery('form.<?php echo esc_attr($form_vars['form_instance']); ?>'));
737 if (ajax_formInstance) {
738 ajax_formInstance.initFormHandlers();
739 }
740 }
741
742 initFFInstance_<?php echo esc_attr($form_vars['id']); ?>();
743 <?php endif; ?>
744 </script>
745 <?php
746 $this->addInlineVars();
747 $otherScripts .= ob_get_clean();
748
749 if (!apply_filters('fluentform-disabled_analytics', false)) {
750 if (!Acl::hasAnyFormPermission($form->id)) {
751 (new \FluentForm\App\Modules\Form\Analytics($this->app))->record($form->id);
752 }
753 }
754
755 return $output . $otherScripts;
756 }
757
758 /**
759 * Process the output HTML to generate the default values.
760 *
761 * @param string $output
762 * @param \stdClass $form
763 * @return string
764 */
765 public function replaceEditorSmartCodes($output, $form)
766 {
767 // Get the patterns for default values from the output HTML string.
768 // The example of a pattern would be for user ID: {user.ID}
769 preg_match_all('/{(.*?)}/', $output, $matches);
770 $patterns = array_unique($matches[0]);
771
772
773 $attrDefaultValues = [];
774
775 foreach ($patterns as $pattern) {
776 // The default value for each pattern will be resolved here.
777 $attrDefaultValues[$pattern] = apply_filters('fluentform_parse_default_value', $pattern, $form);
778 }
779
780 // Raising an event so that others can hook into it and modify the default values later.
781 $attrDefaultValues = (array)apply_filters('fluentform_parse_default_values', $attrDefaultValues);
782
783 if (isset($attrDefaultValues['{payment_total}'])) {
784 $attrDefaultValues['{payment_total}'] = '<span class="ff_order_total"></span>';
785 }
786
787 // Finally, replace the patterns with the replacements and return the output HTML.
788 return str_replace(array_keys($attrDefaultValues), array_values($attrDefaultValues), $output);
789 }
790
791 /**
792 * Register renderer actions for compiling each element
793 *
794 * @return void
795 */
796 public function addRendererActions()
797 {
798 $actionMappings = [
799 'Select@compile' => ['fluentform_render_item_select'],
800 'Rating@compile' => ['fluentform_render_item_ratings'],
801 'Address@compile' => ['fluentform_render_item_address'],
802 'Name@compile' => ['fluentform_render_item_input_name'],
803 'TextArea@compile' => ['fluentform_render_item_textarea'],
804 'DateTime@compile' => ['fluentform_render_item_input_date'],
805 'Recaptcha@compile' => ['fluentform_render_item_recaptcha'],
806 'Hcaptcha@compile' => ['fluentform_render_item_hcaptcha'],
807 'Turnstile@compile' => ['fluentform_render_item_turnstile'],
808 'Container@compile' => ['fluentform_render_item_container'],
809 'CustomHtml@compile' => ['fluentform_render_item_custom_html'],
810 'SectionBreak@compile' => ['fluentform_render_item_section_break'],
811 'SubmitButton@compile' => ['fluentform_render_item_submit_button'],
812 'SelectCountry@compile' => ['fluentform_render_item_select_country'],
813
814 'TermsAndConditions@compile' => [
815 'fluentform_render_item_terms_and_condition',
816 'fluentform_render_item_gdpr_agreement'
817 ],
818
819 'TabularGrid@compile' => [
820 'fluentform_render_item_tabular_grid'
821 ],
822
823 'Checkable@compile' => [
824 'fluentform_render_item_input_radio',
825 'fluentform_render_item_input_checkbox',
826 ],
827
828 'Text@compile' => [
829 'fluentform_render_item_input_url',
830 'fluentform_render_item_input_text',
831 'fluentform_render_item_input_email',
832 'fluentform_render_item_input_number',
833 'fluentform_render_item_input_hidden',
834 'fluentform_render_item_input_password',
835 ],
836 ];
837
838 $path = 'FluentForm\App\Services\FormBuilder\Components\\';
839 foreach ($actionMappings as $handler => $actions) {
840 foreach ($actions as $action) {
841 $this->app->addAction($action, function () use ($path, $handler) {
842 list($class, $method) = $this->app->parseHandler($path . $handler);
843 call_user_func_array(array($class, $method), func_get_args());
844 }, 10, 2);
845 }
846 }
847 }
848
849 /**
850 * Register dynamic value shortcode parser (filter default value)
851 *
852 * @return void
853 */
854 public function addFluentFormDefaultValueParser()
855 {
856 $this->app->addFilter('fluentform_parse_default_value', function ($value, $form) {
857 return EditorShortcodeParser::filter($value, $form);
858 }, 10, 2);
859 }
860
861 /**
862 * Register filter to check whether the form is renderable
863 *
864 * @return mixed
865 */
866 public function addIsRenderableFilter()
867 {
868 $this->app->addFilter('fluentform_is_form_renderable', function ($isRenderable, $form) {
869 $checkables = array('limitNumberOfEntries', 'scheduleForm', 'requireLogin');
870
871 foreach ($form->settings['restrictions'] as $key => $restrictions) {
872 if (in_array($key, $checkables)) {
873 $isRenderable['status'] = $this->{$key}($restrictions, $form, $isRenderable);
874 if (!$isRenderable['status']) {
875 $isRenderable['status'] = false;
876 return $isRenderable;
877 }
878 }
879 }
880
881 return $isRenderable;
882 }, 10, 2);
883 }
884
885 /**
886 * Check if limit is set on form submits and it's valid yet
887 *
888 * @param array $restrictions
889 *
890 * @return bool
891 */
892 private function limitNumberOfEntries($restrictions, $form, &$isRenderable)
893 {
894 if (!$restrictions['enabled']) {
895 return true;
896 }
897
898 $col = 'created_at';
899 $period = $restrictions['period'];
900 $maxAllowedEntries = $restrictions['numberOfEntries'];
901
902 if (!$maxAllowedEntries) {
903 return true;
904 }
905
906 $query = wpFluent()->table('fluentform_submissions')
907 ->where('form_id', $form->id)
908 ->where('status', '!=', 'trashed');
909
910 if ($period == 'day') {
911 $year = "YEAR(`{$col}`) = YEAR(NOW())";
912 $month = "MONTH(`{$col}`) = MONTH(NOW())";
913 $day = "DAY(`{$col}`) = DAY(NOW())";
914 $query->where(wpFluent()->raw("{$year} AND {$month} AND {$day}"));
915 } elseif ($period == 'week') {
916 $query->where(
917 wpFluent()->raw("YEARWEEK(`{$col}`, 1) = YEARWEEK(CURDATE(), 1)")
918 );
919 } elseif ($period == 'month') {
920 $year = "YEAR(`{$col}`) = YEAR(NOW())";
921 $month = "MONTH(`{$col}`) = MONTH(NOW())";
922 $query->where(wpFluent()->raw("{$year} AND {$month}"));
923 } elseif ($period == 'year') {
924 $query->where(wpFluent()->raw("YEAR(`{$col}`) = YEAR(NOW())"));
925 } else if ($period == 'per_user_ip') {
926 $ip = $this->app->request->getIp();
927 $query->where('ip', $ip);
928 } else if ($period == 'per_user_id') {
929 $userId = get_current_user_id();
930 if (!$userId) {
931 return true;
932 }
933 $query->where('user_id', $userId);
934 }
935
936 $count = $query->count();
937
938
939 if ($count >= $maxAllowedEntries) {
940 $isRenderable['message'] = $restrictions['limitReachedMsg'];
941 return false;
942 }
943
944 return true;
945 }
946
947 /**
948 * Check if form has scheduled date & weekdays and open for submission
949 *
950 * @param array $restrictions
951 *
952 * @return bool
953 */
954 private function scheduleForm($restrictions, $form, &$isRenderable)
955 {
956 if (!$restrictions['enabled']) {
957 return true;
958 }
959
960 $time = time();
961 $start = strtotime($restrictions['start']);
962 $end = strtotime($restrictions['end']);
963
964 if ($time < $start) {
965 $isRenderable['message'] = $restrictions['pendingMsg'];
966 return false;
967 }
968
969 if ($time >= $end) {
970 $isRenderable['message'] = $restrictions['expiredMsg'];
971
972 return false;
973 }
974
975 $weekDayToday = date("l"); //day of the week
976 $selectedWeekDays = ArrayHelper::get($restrictions, 'selectedDays');
977 //skip if it was not set initially and $selectedWeekDays is null
978 if ($selectedWeekDays && is_array($selectedWeekDays) && !in_array($weekDayToday, $selectedWeekDays)) {
979 $isRenderable['message'] = $restrictions['expiredMsg'];
980 return false;
981 }
982
983 return true;
984 }
985
986 /**
987 * * Check if form requires loged in user and user is logged in
988 *
989 * @param array $restrictions
990 *
991 * @return bool
992 */
993 private function requireLogin($restrictions, $form, &$isRenderable)
994 {
995 if (!$restrictions['enabled']) {
996 return true;
997 }
998
999 if (!($isLoggedIn = is_user_logged_in())) {
1000 $isRenderable['message'] = $restrictions['requireLoginMsg'];
1001 }
1002
1003 return $isLoggedIn;
1004 }
1005
1006 /**
1007 * Register fluentform_submission_inserted actions
1008 *
1009 * @return void
1010 */
1011 public function addFluentformSubmissionInsertedFilter()
1012 {
1013 (new EmailNotificationActions($this->app))->register();
1014 }
1015
1016 /**
1017 * Add inline scripts [Add localized script using same var]
1018 *
1019 * @return void
1020 */
1021 private function addInlineVars()
1022 {
1023 if (!defined('ELEMENTOR_PRO_VERSION') || $this->elementorPopUpHandler) {
1024 return '';
1025 }
1026
1027 // Previously this handler was registered for every form
1028 // in a single page. So multiple event handlers were
1029 // registered. This flag ensures the handler is
1030 // registered just once, since one is enough!
1031 $this->elementorPopUpHandler = true;
1032
1033 $actionName = 'wp_footer';
1034 if (is_admin()) {
1035 $actionName = 'admin_footer';
1036 }
1037
1038 add_action($actionName, function () {
1039 ?>
1040 <script type="text/javascript">
1041 <?php if(defined('ELEMENTOR_PRO_VERSION')): ?>
1042 jQuery(document).on('elementor/popup/show', function (event, id, instance) {
1043 var ffForms = jQuery('#elementor-popup-modal-' + id).find('form.frm-fluent-form');
1044
1045 /**
1046 * Support conversation form in elementor popup
1047 * No regular form found, check for conversational form
1048 */
1049 if (!ffForms.length) {
1050 const elements = document.getElementsByClassName('ffc_conv_form');
1051 if (elements.length) {
1052 let jsEvent = new CustomEvent('ff-elm-conv-form-event', {
1053 detail: elements
1054 });
1055 document.dispatchEvent(jsEvent);
1056 }
1057 }
1058 if (ffForms.length) {
1059 jQuery.each(ffForms, function (index, ffForm) {
1060 jQuery(ffForm).trigger('reInitExtras');
1061 jQuery(document).trigger('ff_reinit', [ffForm]);
1062 });
1063 }
1064 });
1065 <?php endif; ?>
1066 </script>
1067 <?php
1068 }, 999);
1069 return '';
1070 }
1071
1072 public static function getDatei18n()
1073 {
1074 $i18n = array(
1075 'previousMonth' => __('Previous Month', 'fluentform'),
1076 'nextMonth' => __('Next Month', 'fluentform'),
1077 'months' => [
1078 'shorthand' => [
1079 __('Jan', 'fluentform'),
1080 __('Feb', 'fluentform'),
1081 __('Mar', 'fluentform'),
1082 __('Apr', 'fluentform'),
1083 __('May', 'fluentform'),
1084 __('Jun', 'fluentform'),
1085 __('Jul', 'fluentform'),
1086 __('Aug', 'fluentform'),
1087 __('Sep', 'fluentform'),
1088 __('Oct', 'fluentform'),
1089 __('Nov', 'fluentform'),
1090 __('Dec', 'fluentform')
1091 ],
1092 'longhand' => [
1093 __('January', 'fluentform'),
1094 __('February', 'fluentform'),
1095 __('March', 'fluentform'),
1096 __('April', 'fluentform'),
1097 __('May', 'fluentform'),
1098 __('June', 'fluentform'),
1099 __('July', 'fluentform'),
1100 __('August', 'fluentform'),
1101 __('September', 'fluentform'),
1102 __('October', 'fluentform'),
1103 __('November', 'fluentform'),
1104 __('December', 'fluentform')
1105 ]
1106 ],
1107 'weekdays' => [
1108 'longhand' => array(
1109 __('Sunday', 'fluentform'),
1110 __('Monday', 'fluentform'),
1111 __('Tuesday', 'fluentform'),
1112 __('Wednesday', 'fluentform'),
1113 __('Thursday', 'fluentform'),
1114 __('Friday', 'fluentform'),
1115 __('Saturday', 'fluentform')
1116 ),
1117 'shorthand' => array(
1118 __('Sun', 'fluentform'),
1119 __('Mon', 'fluentform'),
1120 __('Tue', 'fluentform'),
1121 __('Wed', 'fluentform'),
1122 __('Thu', 'fluentform'),
1123 __('Fri', 'fluentform'),
1124 __('Sat', 'fluentform')
1125 )
1126 ],
1127 'daysInMonth' => [
1128 31,
1129 28,
1130 31,
1131 30,
1132 31,
1133 30,
1134 31,
1135 31,
1136 30,
1137 31,
1138 30,
1139 31
1140 ],
1141 'rangeSeparator' => __(' to ', 'fluentform'),
1142 'weekAbbreviation' => __('Wk', 'fluentform'),
1143 'scrollTitle' => __('Scroll to increment', 'fluentform'),
1144 'toggleTitle' => __('Click to toggle', 'fluentform'),
1145 'amPM' => [
1146 __('AM', 'fluentform'),
1147 __('PM', 'fluentform')
1148 ],
1149 'yearAriaLabel' => __('Year', 'fluentform')
1150 );
1151
1152 return apply_filters('fluentform/date_i18n', $i18n);
1153 }
1154
1155 protected function maybeHasAdvandedFields($form, $formBuilder)
1156 {
1157 $advancedFields = [
1158 'step_start',
1159 'repeater_field',
1160 'ratings',
1161 'form_step',
1162 'input_file',
1163 'input_image',
1164 'net_promoter_score',
1165 'featured_image'
1166 ];
1167
1168 if ($formBuilder->conditions || array_intersect($formBuilder->fieldLists, $advancedFields)) {
1169 wp_enqueue_script('fluentform-advanced');
1170 }
1171 }
1172
1173 public function registerInputSanitizers()
1174 {
1175 add_filter('fluentform_input_data_input_number', array($this, 'getNumericInputValue'), 10, 2);
1176 add_filter('fluentform_input_data_custom_payment_component', array($this, 'getNumericInputValue'), 10, 2);
1177 }
1178
1179 public function getNumericInputValue($value, $field)
1180 {
1181 $formatter = ArrayHelper::get($field, 'raw.settings.numeric_formatter');
1182 if (!$formatter) {
1183 return $value;
1184 }
1185 return Helper::getNumericValue($value, $formatter);
1186 }
1187 }
1188