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