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