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 / FormBuilder / ShortCodeParser.php

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

670 lines 25.0 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\FormBuilder;
4
5 use FluentForm\App\Models\SubmissionMeta;
6 use FluentForm\App\Modules\Form\FormDataParser;
7 use FluentForm\App\Modules\Form\FormFieldsParser;
8 use FluentForm\App\Services\Browser\Browser;
9 use FluentForm\Framework\Helpers\ArrayHelper;
10 use FluentForm\App\Helpers\Helper;
11
12 class ShortCodeParser
13 {
14 protected static $form = null;
15
16 protected static $entry = null;
17
18 protected static $browser = null;
19
20 protected static $formFields = null;
21
22 protected static $provider = null;
23
24 protected static $store = [
25 'inputs' => null,
26 'original_inputs' => null,
27 'user' => null,
28 'post' => null,
29 'other' => null,
30 'submission' => null,
31 ];
32
33 public static function parse($parsable, $entryId, $data = [], $form = null, $isUrl = false, $providerOrIsHTML = false, $htmlSanitized = false)
34 {
35 try {
36 static::setDependencies($entryId, $data, $form, $providerOrIsHTML);
37
38 if (is_array($parsable)) {
39 return static::parseShortCodeFromArray($parsable, $isUrl, $providerOrIsHTML, $htmlSanitized);
40 }
41
42 return static::parseShortCodeFromString($parsable, $isUrl, $providerOrIsHTML, $htmlSanitized);
43 } catch (\Exception $e) {
44 if (defined('WP_DEBUG') && WP_DEBUG) {
45 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Debug logging only when WP_DEBUG is enabled, helps developers troubleshoot shortcode parsing issues
46 error_log($e->getTraceAsString());
47 }
48 return '';
49 }
50 }
51
52 protected static function setDependencies($entry, $data, $form, $provider)
53 {
54 static::setEntry($entry);
55 static::setData($data);
56 static::setForm($form);
57 static::$provider = $provider;
58 }
59
60 protected static function setEntry($entry)
61 {
62 static::$entry = $entry;
63 }
64
65 protected static function setdata($data)
66 {
67 if (!is_null($data)) {
68 static::$store['inputs'] = $data;
69 static::$store['original_inputs'] = $data;
70 } else {
71 $data = json_decode(static::getEntry()->response, true);
72 static::$store['inputs'] = $data;
73 static::$store['original_inputs'] = $data;
74 }
75 }
76
77 protected static function setForm($form)
78 {
79 if (!is_null($form)) {
80 static::$form = $form;
81 } else {
82 static::$form = static::getEntry()->form_id;
83 }
84 }
85
86 protected static function parseShortCodeFromArray($parsable, $isUrl = false, $provider = false, $htmlSanitized = false)
87 {
88 foreach ($parsable as $key => $value) {
89 if (is_array($value)) {
90 $parsable[$key] = static::parseShortCodeFromArray($value, $isUrl, $provider, $htmlSanitized);
91 } else {
92 $isHtml = false;
93 if ($provider) {
94 $isHtml = apply_filters_deprecated(
95 'ff_will_return_html',
96 [
97 false,
98 $provider,
99 $key
100 ],
101 FLUENTFORM_FRAMEWORK_UPGRADE,
102 'fluentform/will_return_html',
103 'Use fluentform/will_return_html instead of ff_will_return_html.'
104 );
105 $isHtml = apply_filters('fluentform/will_return_html', $isHtml, $provider, $key);
106 }
107 $parsable[$key] = static::parseShortCodeFromString($value, $isUrl, $isHtml, $htmlSanitized);
108 }
109 }
110
111 return $parsable;
112 }
113
114 protected static function parseShortCodeFromString($parsable, $isUrl = false, $isHtml = false, $htmlSanitized = false)
115 {
116 if ('0' === $parsable) {
117 return $parsable;
118 }
119
120 if (!$parsable) {
121 return '';
122 }
123 return preg_replace_callback('/{+(.*?)}/', function ($matches) use ($isUrl, $isHtml, $htmlSanitized) {
124 $value = '';
125 if (false !== strpos($matches[1], 'inputs.')) {
126 $formProperty = substr($matches[1], strlen('inputs.'));
127 $value = static::getFormData($formProperty, $isHtml);
128 } else if (false !== strpos($matches[1], 'labels.')) {
129 $formLabelProperty = substr($matches[1], strlen('labels.'));
130 $value = static::getFormLabelData($formLabelProperty);
131 } elseif (false !== strpos($matches[1], 'user.')) {
132 $userProperty = substr($matches[1], strlen('user.'));
133 $value = static::getUserData($userProperty);
134 } elseif (false !== strpos($matches[1], 'embed_post.')) {
135 $postProperty = substr($matches[1], strlen('embed_post.'));
136 $value = static::getPostData($postProperty);
137 } elseif (false !== strpos($matches[1], 'wp.')) {
138 $wpProperty = substr($matches[1], strlen('wp.'));
139 $value = static::getWPData($wpProperty);
140 } elseif (false !== strpos($matches[1], 'submission.')) {
141 $submissionProperty = substr($matches[1], strlen('submission.'));
142 $value = static::getSubmissionData($submissionProperty);
143 } elseif (false !== strpos($matches[1], 'cookie.')) {
144 $scookieProperty = substr($matches[1], strlen('cookie.'));
145 $value = array_key_exists($scookieProperty, $_COOKIE) ? wp_unslash($_COOKIE[$scookieProperty]) : '';
146 } elseif (false !== strpos($matches[1], 'payment.')) {
147 $property = substr($matches[1], strlen('payment.'));
148 $deprecatedValue = apply_filters_deprecated(
149 'fluentform_payment_smartcode', [
150 '',
151 $property,
152 self::getInstance()
153 ],
154 FLUENTFORM_FRAMEWORK_UPGRADE,
155 'fluentform/payment_smartcode',
156 'Use fluentform/payment_smartcode instead of fluentform_payment_smartcode.'
157 );
158
159 $value = apply_filters('fluentform/payment_smartcode', $deprecatedValue, $property, self::getInstance());
160 } else {
161 $value = static::getOtherData($matches[1]);
162 }
163
164 if (is_array($value)) {
165 $value = fluentImplodeRecursive(', ', $value);
166 }
167
168 if ($isUrl) {
169 $value = rawurlencode($value);
170 } else if ($htmlSanitized) {
171 $value = fluentform_sanitize_html($value);
172 }
173
174 return $value;
175 }, $parsable);
176 }
177
178 protected static function getFormData($key, $isHtml = false)
179 {
180 if (strpos($key, '.label')) {
181 $key = str_replace('.label', '', $key);
182 $isHtml = true;
183 }
184
185 if (strpos($key, '.value')) {
186 $key = str_replace('.value', '', $key);
187 return ArrayHelper::get(static::$store['original_inputs'], $key);
188 }
189
190 if (strpos($key, '.') && !isset(static::$store['inputs'][$key])) {
191 return ArrayHelper::get(
192 static::$store['original_inputs'],
193 $key,
194 ''
195 );
196 }
197
198 if (!isset(static::$store['inputs'][$key])) {
199 static::$store['inputs'][$key] = ArrayHelper::get(
200 static::$store['inputs'],
201 $key,
202 ''
203 );
204 }
205
206 if (is_null(static::$formFields)) {
207 static::$formFields = FormFieldsParser::getShortCodeInputs(
208 static::getForm(),
209 ['admin_label', 'attributes', 'options', 'raw']
210 );
211 }
212
213 $field = ArrayHelper::get(static::$formFields, $key, '');
214
215 if (!$field) {
216 return '';
217 }
218
219 if ($isHtml) {
220 $originalInput = ArrayHelper::get(static::$store['original_inputs'], $key, '');
221 $originalInput = apply_filters_deprecated(
222 'fluentform_response_render_' . $field['element'],
223 [
224 $originalInput,
225 $field,
226 static::getForm()->id,
227 $isHtml
228 ],
229 FLUENTFORM_FRAMEWORK_UPGRADE,
230 'fluentform/response_render_' . $field['element'],
231 'Use fluentform/response_render_' . $field['element'] . ' instead of fluentform_response_render_' . $field['element']
232 );
233 return apply_filters(
234 'fluentform/response_render_' . $field['element'],
235 $originalInput,
236 $field,
237 static::getForm()->id,
238 $isHtml
239 );
240 }
241
242 static::$store['inputs'][$key] = apply_filters_deprecated(
243 'fluentform_response_render_' . $field['element'],
244 [
245 static::$store['inputs'][$key],
246 $field,
247 static::getForm()->id,
248 $isHtml
249 ],
250 FLUENTFORM_FRAMEWORK_UPGRADE,
251 'fluentform/response_render_' . $field['element'],
252 'Use fluentform/response_render_' . $field['element'] . ' instead of fluentform_response_render_' . $field['element']
253 );
254
255 return static::$store['inputs'][$key] = apply_filters(
256 'fluentform/response_render_' . $field['element'],
257 static::$store['inputs'][$key],
258 $field,
259 static::getForm()->id,
260 $isHtml
261 );
262 }
263
264 protected static function getFormLabelData($key)
265 {
266 if (is_null(static::$formFields)) {
267 static::$formFields = FormFieldsParser::getShortCodeInputs(
268 static::getForm(),
269 ['admin_label', 'attributes', 'options', 'raw', 'label']
270 );
271 }
272
273 // Resolve global validation messages {labels.current_field} shortcode.
274 // Current field name attribute was setted as inputs data key 'current_field'.
275 if ('current_field' === $key && $currentFieldName = ArrayHelper::get(static::$store['inputs'], $key)) {
276 $currentFieldName = str_replace(['[', ']'], ['.', ''], $currentFieldName);
277 $key = $currentFieldName;
278 }
279 $inputLabel = ArrayHelper::get(ArrayHelper::get(static::$formFields, $key, []), 'label', '');
280 $inputLabel = str_replace(['[', ']'], '', $inputLabel);
281 $keys = explode(".", $key);
282 if (count($keys) > 1) {
283 $parentKey = array_shift($keys);
284 $inputLabel = str_replace($parentKey, '', $inputLabel);
285 }
286 if (empty($inputLabel)) {
287 $inputLabel = ArrayHelper::get(ArrayHelper::get(static::$formFields, $key, []), 'admin_label', '');
288 }
289 if (empty($inputLabel) && isset($parentKey) && $parentKey) {
290 $inputLabel = ArrayHelper::get(ArrayHelper::get(static::$formFields, $parentKey, []), 'label', '');
291 $key = $parentKey;
292 }
293
294 return apply_filters('fluentform/input_label_shortcode', $inputLabel, $key, static::getForm());
295 }
296
297 protected static function getUserData($key)
298 {
299 if (is_null(static::$store['user'])) {
300 static::$store['user'] = wp_get_current_user();
301 }
302 return static::$store['user']->{$key};
303 }
304
305 protected static function getPostData($key)
306 {
307 if (is_null(static::$store['post'])) {
308 $postId = static::$store['inputs']['__fluent_form_embded_post_id'];
309 static::$store['post'] = get_post($postId);
310 if (is_null(static::$store['post'])) {
311 return '';
312 }
313 static::$store['post']->permalink = get_the_permalink(static::$store['post']);
314 }
315
316 if (false !== strpos($key, 'author.')) {
317 $authorProperty = substr($key, strlen('author.'));
318 $authorId = static::$store['post']->post_author;
319 if ($authorId) {
320 $data = get_the_author_meta($authorProperty, $authorId);
321 if (!is_array($data)) {
322 return $data;
323 }
324 }
325 return '';
326 } elseif (false !== strpos($key, 'meta.')) {
327 $metaKey = substr($key, strlen('meta.'));
328 $postId = static::$store['post']->ID;
329 $data = get_post_meta($postId, $metaKey, true);
330 if (!is_array($data)) {
331 return $data;
332 }
333 return '';
334 } elseif (false !== strpos($key, 'acf.')) {
335 $metaKey = substr($key, strlen('acf.'));
336 $postId = static::$store['post']->ID;
337 if (function_exists('get_field')) {
338 $data = get_field($metaKey, $postId, true);
339 if (!is_array($data)) {
340 return $data;
341 }
342 return '';
343 }
344 }
345
346 return static::$store['post']->{$key};
347 }
348
349 protected static function getWPData($key)
350 {
351 if ('admin_email' == $key) {
352 return get_option('admin_email');
353 }
354 if ('site_url' == $key) {
355 return site_url();
356 }
357 if ('site_title' == $key) {
358 return get_option('blogname');
359 }
360 return $key;
361 }
362
363 protected static function getSubmissionData($key)
364 {
365 $entry = static::getEntry();
366
367 if (empty($entry->id)) {
368 return '';
369 }
370
371 if (property_exists($entry, $key)) {
372 if ('total_paid' == $key || 'payment_total' == $key) {
373 return round($entry->{$key} / 100, 2);
374 }
375 if ('payment_method' == $key && 'test' == $entry->{$key}) {
376 return __('Offline', 'fluentform');
377 }
378 return $entry->{$key};
379 }
380 if ('admin_view_url' == $key) {
381 return admin_url('admin.php?page=fluent_forms&route=entries&form_id=' . $entry->form_id . '#/entries/' . $entry->id);
382 } elseif ('entry_uid_link' == $key) {
383 return static::getEntryUidLink($entry);
384 } elseif (false !== strpos($key, 'meta.')) {
385 $metaKey = substr($key, strlen('meta.'));
386 $data = Helper::getSubmissionMeta($entry->id, $metaKey);
387 if (!is_array($data)) {
388 return $data;
389 }
390 return '';
391 }
392
393 return '';
394 }
395
396 protected static function getOtherData($key)
397 {
398 if (0 === strpos($key, 'date.')) {
399 $format = str_replace('date.', '', $key);
400 return date($format, strtotime(current_time('mysql')));
401 } elseif ('admin_email' == $key) {
402 return get_option('admin_email', false);
403 } elseif ('ip' == $key) {
404 return static::getRequest()->getIp();
405 } elseif ('browser.platform' == $key) {
406 return static::getUserAgent()->getPlatform();
407 } elseif ('browser.name' == $key) {
408 return static::getUserAgent()->getBrowser();
409 } elseif (in_array($key, ['all_data', 'all_data_without_hidden_fields'])) {
410 $formFields = FormFieldsParser::getEntryInputs(static::getForm());
411 $inputLabels = FormFieldsParser::getAdminLabels(static::getForm(), $formFields);
412 $response = FormDataParser::parseFormSubmission(static::getEntry(), static::getForm(), $formFields, true);
413
414 $status = apply_filters_deprecated(
415 'fluentform_all_data_skip_password_field',
416 [
417 __return_true()
418 ],
419 FLUENTFORM_FRAMEWORK_UPGRADE,
420 'fluentform/all_data_skip_password_field',
421 'Use fluentform/all_data_skip_password_field instead of fluentform_all_data_skip_password_field.'
422 );
423
424 if (apply_filters('fluentform/all_data_skip_password_field', $status)) {
425 $passwords = FormFieldsParser::getInputsByElementTypes(static::getForm(), ['input_password']);
426 if (is_array($passwords) && !empty($passwords)) {
427 $user_inputs = $response->user_inputs;
428 ArrayHelper::forget($user_inputs, array_keys($passwords));
429 $response->user_inputs = $user_inputs;
430 }
431 }
432
433 $hideHiddenField = true;
434 $hideHiddenField = apply_filters_deprecated(
435 'fluentform_all_data_without_hidden_fields',
436 [
437 $hideHiddenField
438 ],
439 FLUENTFORM_FRAMEWORK_UPGRADE,
440 'fluentform/all_data_without_hidden_fields',
441 'Use fluentform/all_data_without_hidden_fields instead of fluentform_all_data_without_hidden_fields.'
442 );
443 $skipHiddenFields = ('all_data_without_hidden_fields' == $key) &&
444 apply_filters('fluentform/all_data_without_hidden_fields', $hideHiddenField);
445
446 if ($skipHiddenFields) {
447 $hiddenFields = FormFieldsParser::getInputsByElementTypes(static::getForm(), ['input_hidden']);
448 if (is_array($hiddenFields) && !empty($hiddenFields)) {
449 ArrayHelper::forget($response->user_inputs, array_keys($hiddenFields));
450 }
451 }
452
453 $html = '<table class="ff_all_data" width="600" cellpadding="0" cellspacing="0"><tbody>';
454 foreach ($inputLabels as $inputKey => $label) {
455 if (array_key_exists($inputKey, $response->user_inputs) && '' !== ArrayHelper::get($response->user_inputs, $inputKey)) {
456 $data = ArrayHelper::get($response->user_inputs, $inputKey);
457 if (is_array($data) || is_object($data)) {
458 continue;
459 }
460 // $label is admin-set, $data is already sanitized via fluentFormSanitizer() on submission insert
461 $html .= '<tr class="field-label"><th style="padding: 6px 12px; background-color: #f8f8f8; text-align: left;"><strong>' . $label . '</strong></th></tr><tr class="field-value"><td style="padding: 6px 12px 12px 12px;">' . $data . '</td></tr>';
462 }
463 }
464
465 $html .= '</tbody></table>';
466 $html = apply_filters_deprecated(
467 'fluentform_all_data_shortcode_html',
468 [
469 $html,
470 $formFields,
471 $inputLabels,
472 $response
473 ],
474 FLUENTFORM_FRAMEWORK_UPGRADE,
475 'fluentform/all_data_shortcode_html',
476 'Use fluentform/all_data_shortcode_html instead of fluentform_all_data_shortcode_html.'
477 );
478 return apply_filters('fluentform/all_data_shortcode_html', $html, $formFields, $inputLabels, $response);
479 } elseif ('http_referer' === $key) {
480 return wp_get_referer();
481 } elseif (0 === strpos($key, 'pdf.download_link.')) {
482 $key = apply_filters_deprecated(
483 'fluentform_shortcode_parser_callback_pdf.download_link.public',
484 [
485 $key, static::getInstance()
486 ],
487 FLUENTFORM_FRAMEWORK_UPGRADE,
488 'fluentform/shortcode_parser_callback_pdf.download_link.public',
489 'Use fluentform/shortcode_parser_callback_pdf.download_link.public instead of fluentform_shortcode_parser_callback_pdf.download_link.public.'
490 );
491 return apply_filters('fluentform/shortcode_parser_callback_pdf.download_link.public', $key, static::getInstance());
492 } elseif (false !== strpos($key, 'random_string.')) {
493 $exploded = explode('.', $key);
494 $prefix = array_pop($exploded);
495 $value = $prefix . uniqid();
496
497 return apply_filters('fluentform/shortcode_parser_callback_random_string', $value, $prefix, static::getInstance());
498 } elseif ('form_title' == $key) {
499 return static::getForm()->title;
500 } elseif (false !== strpos($key, 'chat_gpt_response.')) {
501 if (defined('FLUENTFORMPRO') && class_exists('\FluentFormPro\classes\Chat\ChatFieldController')) {
502 $exploded = explode('.', $key);
503 $prefix = array_pop($exploded);
504 if (!$prefix) {
505 return '';
506 }
507 $exploded = explode('_', $prefix);
508 $formId = reset($exploded);
509 $feedId = end($exploded);
510 $chatGPT = new \FluentFormPro\classes\Chat\ChatFieldController(wpFluentForm());
511 if ($chatGPT->api->isApiEnabled()) {
512 $entry = static::getEntry();
513 $lastResponse = SubmissionMeta::retrieve("chat_gpt_response_{$feedId}", $entry->id);
514 if (!$lastResponse) {
515 $response = $chatGPT->chatGPTSubmissionMessageHandler($formId, $feedId, static::getInstance());
516 SubmissionMeta::persist($entry->id, "chat_gpt_response_{$feedId}", $response, $formId);
517 return $response;
518 }
519 return $lastResponse;
520 }
521 }
522 return '';
523 }
524
525
526 // if it's multi line then just return
527 if (false !== strpos($key, PHP_EOL)) { // most probably it's a css
528 return '{' . $key . '}';
529 }
530
531
532 $groups = explode('.', $key);
533 if (count($groups) > 1) {
534 $group = array_shift($groups);
535 $property = implode('.', $groups);
536 $handlerValue = apply_filters_deprecated(
537 'fluentform_smartcode_group_' . $group,
538 [
539 $property,
540 static::getInstance()
541 ],
542 FLUENTFORM_FRAMEWORK_UPGRADE,
543 'fluentform/smartcode_group_' . $group,
544 'Use fluentform/smartcode_group_' . $group . ' instead of fluentform_smartcode_group_' . $group
545 );
546
547 $handlerValue = apply_filters('fluentform/smartcode_group_' . $group, $handlerValue, static::getInstance());
548 if ($handlerValue != $property) {
549 return $handlerValue;
550 }
551 }
552
553 // This fallback actually
554 $handlerValue = apply_filters_deprecated(
555 'fluentform_shortcode_parser_callback_' . $key,
556 [
557 '{' . $key . '}',
558 static::getInstance()
559 ],
560 FLUENTFORM_FRAMEWORK_UPGRADE,
561 'fluentform/shortcode_parser_callback_' . $key,
562 'Use fluentform/shortcode_parser_callback_' . $key . ' instead of fluentform_shortcode_parser_callback_' . $key
563 );
564
565
566 $handlerValue = apply_filters('fluentform/shortcode_parser_callback_' . $key, $handlerValue, static::getInstance());
567
568 if ($handlerValue) {
569 return $handlerValue;
570 }
571
572 return '';
573 }
574
575 public static function getForm()
576 {
577 if (!is_object(static::$form)) {
578 static::$form = wpFluent()->table('fluentform_forms')->find(static::$form);
579 }
580
581 return static::$form;
582 }
583
584 public static function getProvider()
585 {
586 return static::$provider;
587 }
588
589 public static function getEntry()
590 {
591 if (!is_object(static::$entry)) {
592 static::$entry = wpFluent()->table('fluentform_submissions')->find(static::$entry);
593 }
594
595 return static::$entry;
596 }
597
598 protected static function getRequest()
599 {
600 return wpFluentForm('request');
601 }
602
603 protected static function getUserAgent()
604 {
605 if (is_null(static::$browser)) {
606 static::$browser = new Browser();
607 }
608 return static::$browser;
609 }
610
611 public static function getInstance()
612 {
613 static $instance;
614 if ($instance) {
615 return $instance;
616 }
617 $instance = new static();
618 return $instance;
619 }
620
621 public static function getInputs()
622 {
623 return static::$store['original_inputs'];
624 }
625
626 /**
627 * Get the entry UID link for a submission
628 *
629 * @param object $entry
630 * @return string
631 */
632 protected static function getEntryUidLink($entry)
633 {
634 // Check if entry already has the entry_uid_link property
635 if (isset($entry->entry_uid_link)) {
636 return $entry->entry_uid_link;
637 }
638
639 // Check if front-end entry view is enabled for this form
640 $frontEndSettings = Helper::getFormMeta($entry->form_id, 'front_end_entry_view', []);
641 if (ArrayHelper::get($frontEndSettings, 'status') !== 'yes') {
642 return '';
643 }
644
645 // Get the UID hash from submission meta
646 $meta = wpFluent()->table('fluentform_submission_meta')
647 ->where('response_id', $entry->id)
648 ->where('meta_key', '_entry_uid_hash')
649 ->first();
650
651 if (!$meta || !$meta->value) {
652 return '';
653 }
654
655 // Generate the link
656 return site_url('?ff_entry=1&hash=' . $meta->value);
657 }
658
659 public static function resetData()
660 {
661 self::$form = null;
662 self::$entry = null;
663 self::$browser = null;
664 self::$formFields = null;
665
666 FormFieldsParser::resetData();
667 FormDataParser::resetData();
668 }
669 }
670