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
← All changes | app/Services/FormBuilder/ShortCodeParser.php +427 -60 3.6.656.2.14 View file →
@@ -1,16 +1,19 @@
1 1 <?php
2 2
3 3 namespace FluentForm\App\Services\FormBuilder;
4 4
5 -use FluentForm\App;
5 +use FluentForm\App\Models\SubmissionMeta;
6 6 use FluentForm\App\Modules\Form\FormDataParser;
7 7 use FluentForm\App\Modules\Form\FormFieldsParser;
8 8 use FluentForm\App\Services\Browser\Browser;
9 9 use FluentForm\Framework\Helpers\ArrayHelper;
10 +use FluentForm\App\Helpers\Helper;
10 11
11 12 class ShortCodeParser
12 13 {
14 + const USER_SECRET_PROPERTIES = ['user_pass', 'user_activation_key', 'session_tokens', 'data'];
15 +
13 16 protected static $form = null;
14 17
15 18 protected static $entry = null;
16 19
@@ -17,8 +20,10 @@
17 20 protected static $browser = null;
18 21
19 22 protected static $formFields = null;
20 23
24 + protected static $provider = null;
25 +
21 26 protected static $store = [
22 27 'inputs' => null,
23 28 'original_inputs' => null,
24 29 'user' => null,
@@ -23,24 +28,24 @@
23 28 'original_inputs' => null,
24 29 'user' => null,
25 30 'post' => null,
26 31 'other' => null,
27 - 'submission' => null
32 + 'submission' => null,
28 33 ];
29 34
30 - public static function parse($parsable, $entryId, $data = [], $form = null, $isUrl = false, $provider = false)
35 + public static function parse($parsable, $entryId, $data = [], $form = null, $isUrl = false, $providerOrIsHTML = false, $htmlSanitized = false)
31 36 {
32 37 try {
33 - static::setDependencies($entryId, $data, $form);
38 + static::setDependencies($entryId, $data, $form, $providerOrIsHTML);
34 39
35 40 if (is_array($parsable)) {
36 - return static::parseShortCodeFromArray($parsable, $isUrl, $provider);
41 + return static::parseShortCodeFromArray($parsable, $isUrl, $providerOrIsHTML, $htmlSanitized);
37 42 }
38 43
39 - return static::parseShortCodeFromString($parsable, $isUrl, false);
40 -
44 + return static::parseShortCodeFromString($parsable, $isUrl, $providerOrIsHTML, $htmlSanitized);
41 45 } catch (\Exception $e) {
42 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
43 48 error_log($e->getTraceAsString());
44 49 }
45 50 return '';
46 51 }
@@ -45,13 +50,14 @@
45 50 return '';
46 51 }
47 52 }
48 53
49 - protected static function setDependencies($entry, $data, $form)
54 + protected static function setDependencies($entry, $data, $form, $provider)
50 55 {
51 56 static::setEntry($entry);
52 57 static::setData($data);
53 58 static::setForm($form);
59 + static::$provider = $provider;
54 60 }
55 61
56 62 protected static function setEntry($entry)
57 63 {
@@ -78,19 +84,30 @@
78 84 static::$form = static::getEntry()->form_id;
79 85 }
80 86 }
81 87
82 - protected static function parseShortCodeFromArray($parsable, $isUrl = false, $provider = false)
88 + protected static function parseShortCodeFromArray($parsable, $isUrl = false, $provider = false, $htmlSanitized = false)
83 89 {
84 90 foreach ($parsable as $key => $value) {
85 91 if (is_array($value)) {
86 - $parsable[$key] = static::parseShortCodeFromArray($value, $isUrl, $provider);
92 + $parsable[$key] = static::parseShortCodeFromArray($value, $isUrl, $provider, $htmlSanitized);
87 93 } else {
88 94 $isHtml = false;
89 95 if ($provider) {
90 - $isHtml = apply_filters('ff_will_return_html', false, $provider, $key);
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);
91 108 }
92 - $parsable[$key] = static::parseShortCodeFromString($value, $isUrl, $isHtml);
109 + $parsable[$key] = static::parseShortCodeFromString($value, $isUrl, $isHtml, $htmlSanitized);
93 110 }
94 111 }
95 112
96 113 return $parsable;
@@ -95,36 +112,54 @@
95 112
96 113 return $parsable;
97 114 }
98 115
99 - protected static function parseShortCodeFromString($parsable, $isUrl = false, $isHtml = false)
116 + protected static function parseShortCodeFromString($parsable, $isUrl = false, $isHtml = false, $htmlSanitized = false)
100 117 {
118 + if ('0' === $parsable) {
119 + return $parsable;
120 + }
121 +
101 122 if (!$parsable) {
102 123 return '';
103 124 }
104 - return preg_replace_callback('/{+(.*?)}/', function ($matches) use ($isUrl, $isHtml) {
125 + return preg_replace_callback('/{+(.*?)}/', function ($matches) use ($isUrl, $isHtml, $htmlSanitized) {
105 126 $value = '';
106 - if (strpos($matches[1], 'inputs.') !== false) {
127 + if (false !== strpos($matches[1], 'inputs.')) {
107 128 $formProperty = substr($matches[1], strlen('inputs.'));
108 129 $value = static::getFormData($formProperty, $isHtml);
109 - } elseif (strpos($matches[1], 'user.') !== false) {
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.')) {
110 134 $userProperty = substr($matches[1], strlen('user.'));
111 135 $value = static::getUserData($userProperty);
112 - } elseif (strpos($matches[1], 'embed_post.') !== false) {
136 + } elseif (false !== strpos($matches[1], 'embed_post.')) {
113 137 $postProperty = substr($matches[1], strlen('embed_post.'));
114 138 $value = static::getPostData($postProperty);
115 - } elseif (strpos($matches[1], 'wp.') !== false) {
139 + } elseif (false !== strpos($matches[1], 'wp.')) {
116 140 $wpProperty = substr($matches[1], strlen('wp.'));
117 141 $value = static::getWPData($wpProperty);
118 - } elseif (strpos($matches[1], 'submission.') !== false) {
142 + } elseif (false !== strpos($matches[1], 'submission.')) {
119 143 $submissionProperty = substr($matches[1], strlen('submission.'));
120 144 $value = static::getSubmissionData($submissionProperty);
121 - } elseif (strpos($matches[1], 'cookie.') !== false) {
145 + } elseif (false !== strpos($matches[1], 'cookie.')) {
122 146 $scookieProperty = substr($matches[1], strlen('cookie.'));
123 - $value = ArrayHelper::get($_COOKIE, $scookieProperty);
124 - } elseif (strpos($matches[1], 'payment.') !== false) {
147 + $value = array_key_exists($scookieProperty, $_COOKIE) ? sanitize_text_field(wp_unslash($_COOKIE[$scookieProperty])) : '';
148 + } elseif (false !== strpos($matches[1], 'payment.')) {
125 149 $property = substr($matches[1], strlen('payment.'));
126 - $value = apply_filters('fluentform_payment_smartcode', '', $property, self::getInstance());
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());
127 162 } else {
128 163 $value = static::getOtherData($matches[1]);
129 164 }
130 165
@@ -132,13 +167,17 @@
132 167 $value = fluentImplodeRecursive(', ', $value);
133 168 }
134 169
135 170 if ($isUrl) {
136 - $value = urlencode($value);
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);
137 177 }
138 178
139 179 return $value;
140 -
141 180 }, $parsable);
142 181 }
143 182
144 183 protected static function getFormData($key, $isHtml = false)
@@ -154,33 +193,52 @@
154 193 }
155 194
156 195 if (strpos($key, '.') && !isset(static::$store['inputs'][$key])) {
157 196 return ArrayHelper::get(
158 - static::$store['original_inputs'], $key, ''
197 + static::$store['original_inputs'],
198 + $key,
199 + ''
159 200 );
160 201 }
161 202
162 203 if (!isset(static::$store['inputs'][$key])) {
163 204 static::$store['inputs'][$key] = ArrayHelper::get(
164 - static::$store['inputs'], $key, ''
205 + static::$store['inputs'],
206 + $key,
207 + ''
165 208 );
166 209 }
167 210
168 211 if (is_null(static::$formFields)) {
169 212 static::$formFields = FormFieldsParser::getShortCodeInputs(
170 - static::getForm(), ['admin_label', 'attributes', 'options', 'raw']
213 + static::getForm(),
214 + ['admin_label', 'attributes', 'options', 'raw']
171 215 );
172 216 }
173 217
174 218 $field = ArrayHelper::get(static::$formFields, $key, '');
175 219
220 + if (!$field) {
221 + return '';
222 + }
176 223
177 - if (!$field) return '';
178 -
179 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 + );
180 238 return apply_filters(
181 - 'fluentform_response_render_' . $field['element'],
182 - static::$store['original_inputs'][$key],
239 + 'fluentform/response_render_' . $field['element'],
240 + $originalInput,
183 241 $field,
184 242 static::getForm()->id,
185 243 $isHtml
186 244 );
@@ -185,10 +243,23 @@
185 243 $isHtml
186 244 );
187 245 }
188 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 +
189 260 return static::$store['inputs'][$key] = apply_filters(
190 - 'fluentform_response_render_' . $field['element'],
261 + 'fluentform/response_render_' . $field['element'],
191 262 static::$store['inputs'][$key],
192 263 $field,
193 264 static::getForm()->id,
194 265 $isHtml
@@ -194,14 +265,72 @@
194 265 $isHtml
195 266 );
196 267 }
197 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 +
198 302 protected static function getUserData($key)
199 303 {
200 304 if (is_null(static::$store['user'])) {
201 305 static::$store['user'] = wp_get_current_user();
202 306 }
203 - return static::$store['user']->{$key};
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 '';
204 333 }
205 334
206 335 protected static function getPostData($key)
207 336 {
@@ -207,15 +336,18 @@
207 336 {
208 337 if (is_null(static::$store['post'])) {
209 338 $postId = static::$store['inputs']['__fluent_form_embded_post_id'];
210 339 static::$store['post'] = get_post($postId);
340 + if (is_null(static::$store['post'])) {
341 + return '';
342 + }
211 343 static::$store['post']->permalink = get_the_permalink(static::$store['post']);
212 344 }
213 345
214 - if (strpos($key, 'author.') !== false) {
346 + if (false !== strpos($key, 'author.')) {
215 347 $authorProperty = substr($key, strlen('author.'));
216 348 $authorId = static::$store['post']->post_author;
217 - if ($authorId) {
349 + if ($authorId && !static::isDeniedUserProperty($authorProperty)) {
218 350 $data = get_the_author_meta($authorProperty, $authorId);
219 351 if (!is_array($data)) {
220 352 return $data;
221 353 }
@@ -220,9 +352,9 @@
220 352 return $data;
221 353 }
222 354 }
223 355 return '';
224 - } else if (strpos($key, 'meta.') !== false) {
356 + } elseif (false !== strpos($key, 'meta.')) {
225 357 $metaKey = substr($key, strlen('meta.'));
226 358 $postId = static::$store['post']->ID;
227 359 $data = get_post_meta($postId, $metaKey, true);
228 360 if (!is_array($data)) {
@@ -228,9 +360,9 @@
228 360 if (!is_array($data)) {
229 361 return $data;
230 362 }
231 363 return '';
232 - } else if (strpos($key, 'acf.') !== false) {
364 + } elseif (false !== strpos($key, 'acf.')) {
233 365 $metaKey = substr($key, strlen('acf.'));
234 366 $postId = static::$store['post']->ID;
235 367 if (function_exists('get_field')) {
236 368 $data = get_field($metaKey, $postId, true);
@@ -240,20 +372,39 @@
240 372 return '';
241 373 }
242 374 }
243 375
376 + if ('post_password' === $key) {
377 + return '';
378 + }
379 +
244 380 return static::$store['post']->{$key};
245 381 }
246 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 +
247 398 protected static function getWPData($key)
248 399 {
249 - if ($key == 'admin_email') {
400 + if ('admin_email' == $key) {
250 401 return get_option('admin_email');
251 402 }
252 - if ($key == 'site_url') {
403 + if ('site_url' == $key) {
253 404 return site_url();
254 405 }
255 - if ($key == 'site_title') {
406 + if ('site_title' == $key) {
256 407 return get_option('blogname');
257 408 }
258 409 return $key;
259 410 }
@@ -260,22 +411,33 @@
260 411
261 412 protected static function getSubmissionData($key)
262 413 {
263 414 $entry = static::getEntry();
264 - if (property_exists($entry, $key)) {
265 - if ($key == 'total_paid' || $key == 'payment_total') {
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) {
266 424 return round($entry->{$key} / 100, 2);
267 425 }
268 - if ($key == 'payment_method' && $key == 'test') {
426 + if ('payment_method' == $key && 'test' == $entry->{$key}) {
269 427 return __('Offline', 'fluentform');
270 428 }
271 429 return $entry->{$key};
272 430 }
273 - if ($key == 'admin_view_url') {
431 + if ('admin_view_url' == $key) {
274 432 return admin_url('admin.php?page=fluent_forms&route=entries&form_id=' . $entry->form_id . '#/entries/' . $entry->id);
275 - } else if (strpos($key, 'meta.') !== false) {
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.')) {
276 438 $metaKey = substr($key, strlen('meta.'));
277 - $data = App\Helpers\Helper::getSubmissionMeta($entry->id, $metaKey);
439 + $data = Helper::getSubmissionMeta($entry->id, $metaKey);
278 440 if (!is_array($data)) {
279 441 return $data;
280 442 }
281 443 return '';
@@ -285,43 +447,179 @@
285 447 }
286 448
287 449 protected static function getOtherData($key)
288 450 {
289 - if (strpos($key, 'date.') === 0) {
451 + if (0 === strpos($key, 'date.')) {
290 452 $format = str_replace('date.', '', $key);
291 453 return date($format, strtotime(current_time('mysql')));
292 - } elseif ($key == 'admin_email') {
454 + } elseif ('admin_email' == $key) {
293 455 return get_option('admin_email', false);
294 - } elseif ($key == 'ip') {
456 + } elseif ('ip' == $key) {
295 457 return static::getRequest()->getIp();
296 - } elseif ($key == 'browser.platform') {
458 + } elseif ('browser.platform' == $key) {
297 459 return static::getUserAgent()->getPlatform();
298 - } elseif ($key == 'browser.name') {
460 + } elseif ('browser.name' == $key) {
299 461 return static::getUserAgent()->getBrowser();
300 - } elseif ($key == 'all_data') {
462 + } elseif (in_array($key, ['all_data', 'all_data_without_hidden_fields'])) {
301 463 $formFields = FormFieldsParser::getEntryInputs(static::getForm());
302 464 $inputLabels = FormFieldsParser::getAdminLabels(static::getForm(), $formFields);
303 465 $response = FormDataParser::parseFormSubmission(static::getEntry(), static::getForm(), $formFields, true);
304 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 +
305 506 $html = '<table class="ff_all_data" width="600" cellpadding="0" cellspacing="0"><tbody>';
306 - foreach ($inputLabels as $key => $label) {
307 - if (array_key_exists($key, $response->user_inputs) && ArrayHelper::get($response->user_inputs, $key)) {
308 - $data = ArrayHelper::get($response->user_inputs, $key);
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);
309 510 if (is_array($data) || is_object($data)) {
310 511 continue;
311 512 }
513 + // $label is admin-set, $data is already sanitized via fluentFormSanitizer() on submission insert
312 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>';
313 515 }
314 516 }
517 +
315 518 $html .= '</tbody></table>';
316 - return $html;
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 '';
317 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 +
318 604 // This fallback actually
319 - $handlerValue = apply_filters('fluentform_shortcode_parser_callback_' . $key, '{' . $key . '}', self::getInstance());
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 + );
320 615
616 + $handlerValue = apply_filters('fluentform/shortcode_parser_callback_' . $key, $handlerValue, static::getInstance());
617 +
321 618 if ($handlerValue) {
322 619 return $handlerValue;
323 620 }
621 +
324 622 return '';
325 623 }
326 624
327 625 public static function getForm()
@@ -332,8 +630,13 @@
332 630
333 631 return static::$form;
334 632 }
335 633
634 + public static function getProvider()
635 + {
636 + return static::$provider;
637 + }
638 +
336 639 public static function getEntry()
337 640 {
338 641 if (!is_object(static::$entry)) {
339 642 static::$entry = wpFluent()->table('fluentform_submissions')->find(static::$entry);
@@ -343,9 +646,9 @@
343 646 }
344 647
345 648 protected static function getRequest()
346 649 {
347 - return App::make('request');
650 + return wpFluentForm('request');
348 651 }
349 652
350 653 protected static function getUserAgent()
351 654 {
@@ -363,6 +666,70 @@
363 666 }
364 667 $instance = new static();
365 668 return $instance;
366 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 + }
367 735 }
368 -