PluginProbe
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder / 6.2.14
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder v6.2.14
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.14, at app/Services/FormBuilder/ShortCodeParser.php

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