Below is a differential between the unpatched vulnerable code and the patched update, for reference.
--- a/fluentform/app/Helpers/Helper.php
+++ b/fluentform/app/Helpers/Helper.php
@@ -1027,10 +1027,19 @@
if (ArrayHelper::isTrue($rawField, 'attributes.multiple')) {
$fieldType = 'multi_select';
}
- $options = array_column(
- ArrayHelper::get($rawField, 'settings.advanced_options', []),
- 'value'
- );
+ $formattedOptions = ArrayHelper::get($rawField, 'settings.advanced_options', []);
+ if (!$formattedOptions) {
+ $formattedOptions = [];
+ foreach (ArrayHelper::get($rawField, 'options', []) as $value => $label) {
+ $formattedOptions[] = [
+ 'label' => $label,
+ 'value' => $value,
+ ];
+ }
+ // @todo : Update all reference in form templates
+ }
+
+ $options = array_column($formattedOptions, 'value');
// Add field-specific __ff_other__ to options if "Other" option is enabled
if (in_array($fieldType, ['input_checkbox', 'input_radio']) &&
--- a/fluentform/app/Http/Policies/GlobalIntegrationPolicy.php
+++ b/fluentform/app/Http/Policies/GlobalIntegrationPolicy.php
@@ -0,0 +1,47 @@
+<?php
+
+namespace FluentFormAppHttpPolicies;
+
+use FluentFormAppModulesAclAcl;
+use FluentFormFrameworkFoundationPolicy;
+use FluentFormFrameworkHttpRequestRequest;
+
+class GlobalIntegrationPolicy extends Policy
+{
+ public function verifyRequest(Request $request)
+ {
+ return $this->canManageGlobalIntegrations();
+ }
+
+ public function index()
+ {
+ return $this->canManageGlobalIntegrations();
+ }
+
+ public function updateIntegration()
+ {
+ return $this->canManageGlobalIntegrations();
+ }
+
+ public function updateModuleStatus()
+ {
+ return $this->canManageGlobalIntegrations();
+ }
+
+ private function canManageGlobalIntegrations()
+ {
+ if (
+ current_user_can('manage_options') ||
+ current_user_can('fluentform_full_access') ||
+ current_user_can('fluentform_settings_manager')
+ ) {
+ return true;
+ }
+
+ $roleCapability = Acl::getCurrentUserCapability();
+
+ // Legacy role-level Fluent Forms access stores the WP role key here.
+ // Granular Fluent Forms permissions must not imply settings access.
+ return $roleCapability && !in_array($roleCapability, Acl::getPermissionSet(), true);
+ }
+}
--- a/fluentform/app/Http/Routes/api.php
+++ b/fluentform/app/Http/Routes/api.php
@@ -93,15 +93,15 @@
/*
* Global Integrations
*/
-$router->prefix('integrations')->withPolicy('FormPolicy')->group(function ($router) {
- $router->get('/', 'GlobalIntegrationController@index');
- $router->post('/', 'GlobalIntegrationController@updateIntegration');
- $router->post('update-status', 'GlobalIntegrationController@updateModuleStatus');
+$router->prefix('integrations')->group(function ($router) {
+ $router->get('/', 'GlobalIntegrationController@index')->withPolicy('GlobalIntegrationPolicy');
+ $router->post('/', 'GlobalIntegrationController@updateIntegration')->withPolicy('GlobalIntegrationPolicy');
+ $router->post('update-status', 'GlobalIntegrationController@updateModuleStatus')->withPolicy('GlobalIntegrationPolicy');
/*
* Form Integrations
*/
- $router->prefix('{form_id}')->group(function ($router) {
+ $router->prefix('{form_id}')->withPolicy('FormPolicy')->group(function ($router) {
$router->get('/form-integrations', 'FormIntegrationController@index');
$router->get('/', 'FormIntegrationController@find');
$router->post('/', 'FormIntegrationController@update');
--- a/fluentform/app/Models/FormMeta.php
+++ b/fluentform/app/Models/FormMeta.php
@@ -42,7 +42,7 @@
$formMeta[] = [
'meta_key' => 'template_name',
- 'value' => Arr::get($attributes, 'predefined'),
+ 'value' => Arr::get($attributes, 'predefined', Arr::get($attributes, 'type', '')),
];
if (isset($predefinedForm['notifications'])) {
@@ -84,7 +84,13 @@
public static function store(Form $form, $formMeta)
{
foreach ($formMeta as $meta) {
- $meta['value'] = trim(preg_replace('/s+/', ' ', $meta['value']));
+ $metaValue = $meta['value'];
+
+ if (is_array($metaValue) || is_object($metaValue)) {
+ $metaValue = wp_json_encode($metaValue);
+ }
+
+ $meta['value'] = trim(preg_replace('/s+/', ' ', (string) $metaValue));
$form->formMeta()->create([
'meta_key' => $meta['meta_key'],
--- a/fluentform/app/Models/Traits/PredefinedForms.php
+++ b/fluentform/app/Models/Traits/PredefinedForms.php
@@ -18,7 +18,19 @@
);
}
- $predefinedForm = json_decode($predefinedForm['json'], true)[0];
+ $predefinedJson = Arr::get($predefinedForm, 'json');
+
+ if ($predefinedJson) {
+ $decodedForm = json_decode($predefinedJson, true);
+ $predefinedForm = isset($decodedForm[0]) ? $decodedForm[0] : [];
+ }
+
+ if (!$predefinedForm || !is_array($predefinedForm)) {
+ throw new Exception(
+ // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped -- Exception message, not output
+ __("The selected template is invalid.", 'fluentform')
+ );
+ }
if (isset($predefinedForm['form_fields'])) {
$predefinedForm['form_fields'] = json_encode($predefinedForm['form_fields']);
--- a/fluentform/app/Modules/Acl/Acl.php
+++ b/fluentform/app/Modules/Acl/Acl.php
@@ -159,38 +159,51 @@
if ($formId && !FormManagerService::hasFormPermission($formId)) {
return false;
}
- $userCapability = static::getCurrentUserCapability();
- if ($userCapability) {
+ // Only explicit full-access users should bypass individual permission checks.
+ if (static::hasExplicitFullAccess()) {
return true;
- } else {
- if (current_user_can('fluentform_full_access')) {
- return true;
- }
+ }
- $permissions = (array) $permissions;
+ $grantedRole = static::getCurrentUserCapability();
- foreach ($permissions as $permission) {
- $allowed = current_user_can($permission);
+ foreach ((array) $permissions as $permission) {
+ $allowed = current_user_can($permission);
- if ($allowed) {
- $allowed = apply_filters_deprecated(
- 'fluentform_verify_user_permission_' . $permission,
- [
- $allowed,
- $formId
- ],
- FLUENTFORM_FRAMEWORK_UPGRADE,
- 'fluentform/verify_user_permission_' . $permission,
- 'Use fluentform/verify_user_permission_' . $permission . ' instead of fluentform_verify_user_permission_' . $permission
- );
+ // A granted role can satisfy scoped permissions, but never full access.
+ if (!$allowed && $grantedRole && 'fluentform_full_access' !== $permission) {
+ $allowed = true;
+ }
- return apply_filters('fluentform/verify_user_permission_' . $permission, $allowed, $formId);
- }
+ if (!$allowed) {
+ continue;
}
- return false;
+ return static::filterPermissionCheck($permission, $allowed, $formId);
}
+
+ return false;
+ }
+
+ private static function hasExplicitFullAccess()
+ {
+ return current_user_can('fluentform_full_access') || current_user_can('manage_options');
+ }
+
+ private static function filterPermissionCheck($permission, $allowed, $formId)
+ {
+ $allowed = apply_filters_deprecated(
+ 'fluentform_verify_user_permission_' . $permission,
+ [
+ $allowed,
+ $formId
+ ],
+ FLUENTFORM_FRAMEWORK_UPGRADE,
+ 'fluentform/verify_user_permission_' . $permission,
+ 'Use fluentform/verify_user_permission_' . $permission . ' instead of fluentform_verify_user_permission_' . $permission
+ );
+
+ return apply_filters('fluentform/verify_user_permission_' . $permission, $allowed, $formId);
}
public static function hasAnyFormPermission($form_id = false)
--- a/fluentform/app/Modules/Component/Component.php
+++ b/fluentform/app/Modules/Component/Component.php
@@ -338,7 +338,7 @@
];
$disabled['phone'] = [
'disabled' => true,
- 'title' => 'Phone Field',
+ 'title' => __('Phone Field', 'fluentform'),
'description' => __('Phone Field is not available with the free version. Please upgrade to pro to get all the advanced features.', 'fluentform'),
'image' => fluentformMix('img/pro-fields/phone-field.png'),
'video' => '',
@@ -510,7 +510,7 @@
if (!empty($atts['permission'])) {
if (!current_user_can($atts['permission'])) {
- return "<div id='ff_form_{$form->id}' class='ff_form_not_render'>{$atts['permission_message']}</div>";
+ return $this->getNotRenderableHtml($form->id, $atts['permission_message']);
}
}
@@ -565,7 +565,7 @@
$isRenderable = $this->app->applyFilters('fluentform/is_form_renderable', $isRenderable, $form);
if (is_array($isRenderable) && !$isRenderable['status']) {
- return "<div id='ff_form_{$form->id}' class='ff_form_not_render'>{$isRenderable['message']}</div>";
+ return $this->getNotRenderableHtml($form->id, $isRenderable['message']);
}
$instanceCssClass = Helper::getFormInstaceClass($form->id);
@@ -805,6 +805,13 @@
return $output . $otherScripts;
}
+ protected function getNotRenderableHtml($formId, $message)
+ {
+ return "<div id='ff_form_" . esc_attr($formId) . "' class='ff_form_not_render'>"
+ . wp_kses_post($message)
+ . "</div>";
+ }
+
/**
* Process the output HTML to generate the default values.
*
--- a/fluentform/app/Modules/Entries/EntryViewRenderer.php
+++ b/fluentform/app/Modules/Entries/EntryViewRenderer.php
@@ -36,7 +36,7 @@
}
$form = wpFluent()->table('fluentform_forms')->find($form_id);
- $submissionShortcodes = FluentFormAppServicesFormBuilderEditorShortCode::getSubmissionShortcodes();
+ $submissionShortcodes = FluentFormAppServicesFormBuilderEditorShortCode::getSubmissionShortcodes($form);
$submissionShortcodes['shortcodes']['{submission.ip}'] = __('Submitter IP', 'fluentform');
if ($form->has_payment) {
$submissionShortcodes['shortcodes']['{payment.payment_status}'] = __('Payment Status','fluentform');
--- a/fluentform/app/Modules/Payments/Classes/PaymentEntries.php
+++ b/fluentform/app/Modules/Payments/Classes/PaymentEntries.php
@@ -248,7 +248,31 @@
public function getFilters()
{
- $transactionTypes = Transaction::select('transaction_type')
+ $request = wpFluentForm()->request;
+ $attributes = $request->all();
+
+ $sanitizeMap = [
+ 'form_id' => function ($value) {
+ return Acl::normalizeFormId($value);
+ },
+ ];
+ $attributes = fluentform_backend_sanitizer($attributes, $sanitizeMap);
+
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Nonce verified by Acl::verify() below
+ Acl::verify('fluentform_view_payments', ArrayHelper::get($attributes, 'form_id'));
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Nonce verified by Acl::verify() above
+ $selectedFormId = ArrayHelper::get($attributes, 'form_id');
+ $allowFormIds = apply_filters('fluentform/current_user_allowed_forms', false);
+
+ $transactionTypesQuery = Transaction::select('transaction_type');
+ if ($selectedFormId) {
+ $transactionTypesQuery = $transactionTypesQuery->where('form_id', $selectedFormId);
+ }
+ if (false !== $allowFormIds && is_array($allowFormIds)) {
+ $transactionTypesQuery = $transactionTypesQuery->whereIn('form_id', $allowFormIds ?: [0]);
+ }
+
+ $transactionTypes = $transactionTypesQuery
->groupBy('transaction_type')
->get();
// Define transaction type labels
@@ -268,7 +292,15 @@
];
}
- $statuses = Transaction::select('status')
+ $statusesQuery = Transaction::select('status');
+ if ($selectedFormId) {
+ $statusesQuery = $statusesQuery->where('form_id', $selectedFormId);
+ }
+ if (false !== $allowFormIds && is_array($allowFormIds)) {
+ $statusesQuery = $statusesQuery->whereIn('form_id', $allowFormIds ?: [0]);
+ }
+
+ $statuses = $statusesQuery
->groupBy('status')
->get();
$statusTypes = PaymentHelper::getPaymentStatuses();
@@ -276,11 +308,15 @@
foreach ($statuses as $status) {
$formattedStatuses[] = ArrayHelper::get($statusTypes, $status->status, $status->status);
}
- $allowFormIds = apply_filters('fluentform/current_user_allowed_forms', false);
- $forms = Transaction::select('fluentform_transactions.form_id', 'fluentform_forms.title')
- ->when(false !== $allowFormIds && is_array($allowFormIds), function ($q) use ($allowFormIds){
- return $q->whereIn('fluentform_transactions.form_id', $allowFormIds ?: [0]);
- })
+ $formsQuery = Transaction::select('fluentform_transactions.form_id', 'fluentform_forms.title');
+ if ($selectedFormId) {
+ $formsQuery = $formsQuery->where('fluentform_transactions.form_id', $selectedFormId);
+ }
+ if (false !== $allowFormIds && is_array($allowFormIds)) {
+ $formsQuery = $formsQuery->whereIn('fluentform_transactions.form_id', $allowFormIds ?: [0]);
+ }
+
+ $forms = $formsQuery
->groupBy('fluentform_transactions.form_id')
->orderBy('fluentform_transactions.form_id', 'DESC')
->join('fluentform_forms', 'fluentform_forms.id', '=', 'fluentform_transactions.form_id')
@@ -294,7 +330,15 @@
];
}
- $paymentMethods = Transaction::select('payment_method')
+ $paymentMethodsQuery = Transaction::select('payment_method');
+ if ($selectedFormId) {
+ $paymentMethodsQuery = $paymentMethodsQuery->where('form_id', $selectedFormId);
+ }
+ if (false !== $allowFormIds && is_array($allowFormIds)) {
+ $paymentMethodsQuery = $paymentMethodsQuery->whereIn('form_id', $allowFormIds ?: [0]);
+ }
+
+ $paymentMethods = $paymentMethodsQuery
->groupBy('payment_method')
->get();
--- a/fluentform/app/Modules/Payments/Components/Subscription.php
+++ b/fluentform/app/Modules/Payments/Components/Subscription.php
@@ -187,10 +187,12 @@
}
$inputAttributes = [
- 'type' => 'hidden',
- 'name' => $data['attributes']['name'],
- 'value' => '0',
- 'class' => 'ff_payment_item ff_subscription_item',
+ 'type' => 'hidden',
+ 'name' => $data['attributes']['name'],
+ 'value' => '0',
+ 'class' => 'ff_payment_item ff_subscription_item',
+ 'data-name' => $data['attributes']['name'],
+ 'data-payment_item' => 'yes',
];
$inputAttributes['id'] = $this->makeElementId($data, $form);
--- a/fluentform/app/Modules/Registerer/Menu.php
+++ b/fluentform/app/Modules/Registerer/Menu.php
@@ -1044,7 +1044,8 @@
'net_promoter_score',
'rangeslider',
'custom_payment_component',
- 'item_quantity_component'
+ 'item_quantity_component',
+ 'subscription_payment_component'
]
];
}
--- a/fluentform/app/Services/Form/Updater.php
+++ b/fluentform/app/Services/Form/Updater.php
@@ -175,7 +175,49 @@
if ('welcome_screen' == $element) {
if ($value = Arr::get($field, 'settings.button_ui.text')) {
- $field['settings']['button_ui']['text'] = sanitize_text_field($value);
+ $field['settings']['button_ui']['text'] = fluentform_sanitize_html($value);
+ }
+ }
+
+ if ('form_step' == $element) {
+ foreach (['next_btn', 'prev_btn'] as $buttonKey) {
+ $buttonSettings = Arr::get($field, 'settings.' . $buttonKey);
+ if (!is_array($buttonSettings)) {
+ continue;
+ }
+
+ if (isset($buttonSettings['type'])) {
+ $field['settings'][$buttonKey]['type'] = sanitize_text_field($buttonSettings['type']);
+ }
+
+ if (isset($buttonSettings['text'])) {
+ $field['settings'][$buttonKey]['text'] = fluentform_sanitize_html($buttonSettings['text']);
+ }
+
+ if (isset($buttonSettings['img_url'])) {
+ $field['settings'][$buttonKey]['img_url'] = esc_url_raw($buttonSettings['img_url']);
+ }
+
+ if (isset($buttonSettings['img_alt'])) {
+ $field['settings'][$buttonKey]['img_alt'] = sanitize_text_field($buttonSettings['img_alt']);
+ }
+ }
+ }
+
+ if ('save_progress_button' == $element) {
+ $buttonUi = Arr::get($field, 'settings.button_ui');
+ if (is_array($buttonUi)) {
+ if (isset($buttonUi['type'])) {
+ $field['settings']['button_ui']['type'] = sanitize_text_field($buttonUi['type']);
+ }
+
+ if (isset($buttonUi['text'])) {
+ $field['settings']['button_ui']['text'] = fluentform_sanitize_html($buttonUi['text']);
+ }
+
+ if (isset($buttonUi['img_url'])) {
+ $field['settings']['button_ui']['img_url'] = esc_url_raw($buttonUi['img_url']);
+ }
}
}
@@ -258,7 +300,7 @@
],
'button_ui' => [
'type' => 'sanitize_text_field',
- 'text' => 'sanitize_text_field',
+ 'text' => 'fluentform_sanitize_html',
'img_url' => 'esc_url_raw',
],
];
@@ -294,7 +336,7 @@
$stepsSanitizationMap = [
'prev_btn' => [
'type' => 'sanitize_text_field',
- 'text' => 'sanitize_text_field',
+ 'text' => 'fluentform_sanitize_html',
'img_url' => 'esc_url_raw',
],
];
--- a/fluentform/app/Services/FormBuilder/DefaultElements.php
+++ b/fluentform/app/Services/FormBuilder/DefaultElements.php
@@ -195,7 +195,7 @@
],
],
'editor_options' => [
- 'title' => 'Name Fields',
+ 'title' => __('Name Fields', 'fluentform'),
'element' => 'name-fields',
'icon_class' => 'ff-edit-name',
'template' => 'nameFields',
@@ -736,7 +736,7 @@
'UK' => 'United Kingdom',
],
'editor_options' => [
- 'title' => 'Country List',
+ 'title' => __('Country List', 'fluentform'),
'element' => 'country-list',
'icon_class' => 'icon-text-width',
'template' => 'selectCountry',
--- a/fluentform/app/Services/FormBuilder/EditorShortcodeParser.php
+++ b/fluentform/app/Services/FormBuilder/EditorShortcodeParser.php
@@ -111,7 +111,7 @@
if (false !== strpos($handler, 'cookie.')) {
$scookieProperty = substr($handler, strlen('cookie.'));
- return wpFluentForm('request')->cookie($scookieProperty);
+ return array_key_exists($scookieProperty, $_COOKIE) ? wp_unslash($_COOKIE[$scookieProperty]) : '';
}
if (false !== strpos($handler, 'dynamic.')) {
--- a/fluentform/app/Services/FormBuilder/Notifications/EmailNotificationActions.php
+++ b/fluentform/app/Services/FormBuilder/Notifications/EmailNotificationActions.php
@@ -130,13 +130,9 @@
$fileUrls = ArrayHelper::get($formData, $name);
if ($fileUrls && is_array($fileUrls)) {
foreach ($fileUrls as $url) {
- if (strpos($url, $uploadDir['baseurl']) === 0) {
- $relativePath = str_replace($uploadDir['baseurl'], '', $url);
- $filePath = wp_normalize_path($uploadDir['basedir'] . $relativePath);
-
- if (file_exists($filePath)) {
- $attachments[] = $filePath;
- }
+ $filePath = $this->resolveUploadAttachmentPath($url, $uploadDir);
+ if ($filePath) {
+ $attachments[] = $filePath;
}
}
}
@@ -148,13 +144,9 @@
$attachments = [];
foreach ($mediaAttachments as $file) {
$fileUrl = ArrayHelper::get($file, 'url');
- if ($fileUrl && strpos($fileUrl, $uploadDir['baseurl']) === 0) {
- $relativePath = str_replace($uploadDir['baseurl'], '', $fileUrl);
- $filePath = wp_normalize_path($uploadDir['basedir'] . $relativePath);
-
- if (file_exists($filePath)) {
- $attachments[] = $filePath;
- }
+ $filePath = $this->resolveUploadAttachmentPath($fileUrl, $uploadDir);
+ if ($filePath) {
+ $attachments[] = $filePath;
}
}
$emailAttachments = array_merge($emailAttachments, $attachments);
@@ -185,6 +177,44 @@
return $emailAttachments;
}
+ private function resolveUploadAttachmentPath($fileUrl, $uploadDir)
+ {
+ if (!$fileUrl || empty($uploadDir['baseurl']) || empty($uploadDir['basedir'])) {
+ return null;
+ }
+
+ $normalizedUrl = strtok($fileUrl, '?#');
+ if (strpos($normalizedUrl, $uploadDir['baseurl']) !== 0) {
+ return null;
+ }
+
+ $relativePath = rawurldecode(str_replace($uploadDir['baseurl'], '', $normalizedUrl));
+ $relativePath = ltrim(wp_normalize_path($relativePath), '/');
+
+ if (!$relativePath || strpos($relativePath, '../') !== false) {
+ return null;
+ }
+
+ $uploadsBaseDir = realpath($uploadDir['basedir']);
+ if (!$uploadsBaseDir) {
+ return null;
+ }
+
+ $uploadsBaseDir = trailingslashit(wp_normalize_path($uploadsBaseDir));
+ $resolvedPath = realpath($uploadsBaseDir . $relativePath);
+
+ if (!$resolvedPath) {
+ return null;
+ }
+
+ $resolvedPath = wp_normalize_path($resolvedPath);
+ if (strpos($resolvedPath, $uploadsBaseDir) !== 0 || !is_file($resolvedPath)) {
+ return null;
+ }
+
+ return $resolvedPath;
+ }
+
public function getFormData($submissionId)
{
$submission = wpFluent()->table('fluentform_submissions')
--- a/fluentform/app/Services/FormBuilder/ShortCodeParser.php
+++ b/fluentform/app/Services/FormBuilder/ShortCodeParser.php
@@ -142,7 +142,7 @@
$value = static::getSubmissionData($submissionProperty);
} elseif (false !== strpos($matches[1], 'cookie.')) {
$scookieProperty = substr($matches[1], strlen('cookie.'));
- $value = wpFluentForm('request')->cookie($scookieProperty);
+ $value = array_key_exists($scookieProperty, $_COOKIE) ? wp_unslash($_COOKIE[$scookieProperty]) : '';
} elseif (false !== strpos($matches[1], 'payment.')) {
$property = substr($matches[1], strlen('payment.'));
$deprecatedValue = apply_filters_deprecated(
--- a/fluentform/app/Services/Settings/Validator/Confirmations.php
+++ b/fluentform/app/Services/Settings/Validator/Confirmations.php
@@ -38,7 +38,7 @@
public static function conditionalValidations(Validator $validator)
{
$validator->sometimes('customUrl', 'required', function ($input) {
- return 'customUrl' === $input['redirectTo'];
+ return isset($input['redirectTo']) && 'customUrl' === $input['redirectTo'];
});
return $validator;
--- a/fluentform/app/Services/Transfer/TransferService.php
+++ b/fluentform/app/Services/Transfer/TransferService.php
@@ -187,6 +187,8 @@
$submissions = FormDataParser::parseFormEntries($submissions, $form, $formInputs);
$parsedShortCodes = [];
$exportData = [];
+ $selectedShortcodes = self::getSelectedExportShortcodes($args, $form);
+ $legacyShortcodeHeaders = self::getLegacyExportShortcodeHeaders();
// Preload notes for all submissions in a single query to avoid N+1
$notesMap = [];
@@ -229,21 +231,29 @@
$temp[] = Helper::sanitizeForCSV($content);
}
- if($selectedShortcodes = Arr::get($args,'shortcodes_to_export')){
- $selectedShortcodes = fluentFormSanitizer($selectedShortcodes);
- $parsedShortCodes = ShortCodeParser::parse(
- $selectedShortcodes,
- $submission->id,
- $submission->response,
- $form,
- false,
- true
- );
- if(!empty($parsedShortCodes)){
- foreach ($parsedShortCodes as $code){
- $temp[] = Arr::get($code,'value');
- }
+ if (!empty($selectedShortcodes)) {
+ $regularShortcodes = self::getRegularExportShortcodes($selectedShortcodes, $legacyShortcodeHeaders);
+
+ if (!empty($regularShortcodes)) {
+ $parsedShortCodes = ShortCodeParser::parse(
+ $regularShortcodes,
+ $submission->id,
+ $submission->response,
+ $form,
+ false,
+ true
+ );
}
+
+ $temp = array_merge(
+ $temp,
+ self::getSelectedShortcodeExportValues(
+ $selectedShortcodes,
+ $parsedShortCodes,
+ $legacyShortcodeHeaders,
+ $submission
+ )
+ );
}
if ($withNotes) {
$noteValues = isset($notesMap[$submission->id]) ? $notesMap[$submission->id] : [];
@@ -252,17 +262,6 @@
}
}
- if (!$tableName) {
- if ($form->has_payment) {
- $temp[] = round(($submission->payment_total ?? 0) / 100, 1);
- $temp[] = $submission->payment_status ?? '';
- $temp[] = $submission->currency ?? '';
- }
- $temp[] = $submission->id ?? '';
- $temp[] = $submission->status ?? '';
- $temp[] = $submission->created_at ?? '';
- }
-
$temp = apply_filters('fluentform/export_entry_metadata', $temp, $submission, $form, $args);
$exportData[] = $temp;
@@ -270,27 +269,16 @@
$extraLabels = [];
- if(!empty($parsedShortCodes)){
- foreach ($parsedShortCodes as $code){
- $extraLabels[] = Arr::get($code,'label');
- }
- }
+ $extraLabels = self::getSelectedShortcodeExportLabels(
+ $selectedShortcodes,
+ $parsedShortCodes,
+ $legacyShortcodeHeaders
+ );
$inputLabels = array_merge($inputLabels, $extraLabels);
if($withNotes){
$inputLabels[] = __('Notes','fluentform');
}
-
- if (!$tableName) {
- if ($form->has_payment) {
- $inputLabels[] = 'payment_total';
- $inputLabels[] = 'payment_status';
- $inputLabels[] = 'currency';
- }
- $inputLabels[] = 'entry_id';
- $inputLabels[] = 'entry_status';
- $inputLabels[] = 'created_at';
- }
$inputLabels = apply_filters('fluentform/export_entry_metadata_labels', $inputLabels, $form, $args);
$data = array_merge([array_values($inputLabels)], $exportData);
@@ -311,6 +299,145 @@
);
}
+ private static function getSelectedExportShortcodes($args, $form)
+ {
+ $selectedShortcodes = fluentFormSanitizer(Arr::get($args, 'shortcodes_to_export', []));
+
+ if (!Arr::has($args, 'shortcodes_to_export_defined') && empty($selectedShortcodes)) {
+ return self::getDefaultExportShortcodes($form);
+ }
+
+ return $selectedShortcodes;
+ }
+
+ private static function getDefaultExportShortcodes($form)
+ {
+ $defaults = [
+ [
+ 'label' => __('Submission ID', 'fluentform'),
+ 'value' => '{submission.id}',
+ ],
+ [
+ 'label' => __('Submission Create Date', 'fluentform'),
+ 'value' => '{submission.created_at}',
+ ],
+ [
+ 'label' => __('Submission Status', 'fluentform'),
+ 'value' => '{submission.status}',
+ ],
+ ];
+
+ if ($form->has_payment) {
+ $defaults[] = [
+ 'label' => __('Payment Status', 'fluentform'),
+ 'value' => '{payment.payment_status}',
+ ];
+ $defaults[] = [
+ 'label' => __('Payment Total', 'fluentform'),
+ 'value' => '{payment.payment_total}',
+ ];
+ $defaults[] = [
+ 'label' => __('Currency', 'fluentform'),
+ 'value' => '{submission.currency}',
+ ];
+ }
+
+ return $defaults;
+ }
+
+ private static function getLegacyExportShortcodeHeaders()
+ {
+ return [
+ '{submission.id}' => 'entry_id',
+ '{submission.status}' => 'entry_status',
+ '{submission.created_at}' => 'created_at',
+ '{payment.payment_status}' => 'payment_status',
+ '{submission.payment_status}' => 'payment_status',
+ '{payment.payment_total}' => 'payment_total',
+ '{submission.payment_total}' => 'payment_total',
+ '{submission.currency}' => 'currency',
+ ];
+ }
+
+ private static function getRegularExportShortcodes($selectedShortcodes, $legacyShortcodeHeaders)
+ {
+ $regularShortcodes = [];
+
+ foreach ($selectedShortcodes as $index => $shortcode) {
+ if (!isset($legacyShortcodeHeaders[Arr::get($shortcode, 'value')])) {
+ $regularShortcodes[$index] = $shortcode;
+ }
+ }
+
+ return $regularShortcodes;
+ }
+
+ private static function getSelectedShortcodeExportValues($selectedShortcodes, $parsedShortCodes, $legacyShortcodeHeaders, $submission)
+ {
+ $values = [];
+
+ foreach ($selectedShortcodes as $index => $shortcode) {
+ $shortcodeValue = Arr::get($shortcode, 'value');
+
+ if (!isset($legacyShortcodeHeaders[$shortcodeValue])) {
+ $values[] = Arr::get($parsedShortCodes, $index . '.value');
+ continue;
+ }
+
+ $values[] = self::getLegacyExportValue($legacyShortcodeHeaders[$shortcodeValue], $submission);
+ }
+
+ return $values;
+ }
+
+ private static function getSelectedShortcodeExportLabels($selectedShortcodes, $parsedShortCodes, $legacyShortcodeHeaders)
+ {
+ $labels = [];
+
+ foreach ($selectedShortcodes as $index => $shortcode) {
+ $shortcodeValue = Arr::get($shortcode, 'value');
+
+ if (isset($legacyShortcodeHeaders[$shortcodeValue])) {
+ $labels[] = $legacyShortcodeHeaders[$shortcodeValue];
+ continue;
+ }
+
+ $labels[] = Arr::get($parsedShortCodes, $index . '.label');
+ }
+
+ return $labels;
+ }
+
+ private static function getLegacyExportValue($header, $submission)
+ {
+ $legacyValueResolvers = [
+ 'entry_id' => function ($submission) {
+ return $submission->id ?? '';
+ },
+ 'entry_status' => function ($submission) {
+ return $submission->status ?? '';
+ },
+ 'created_at' => function ($submission) {
+ return $submission->created_at ?? '';
+ },
+ 'payment_status' => function ($submission) {
+ return $submission->payment_status ?? '';
+ },
+ 'payment_total' => function ($submission) {
+ return round(($submission->payment_total ?? 0) / 100, 1);
+ },
+ 'currency' => function ($submission) {
+ return $submission->currency ?? '';
+ },
+ ];
+
+ if (!isset($legacyValueResolvers[$header])) {
+ return '';
+ }
+
+ return $legacyValueResolvers[$header]($submission);
+ }
+
private static function exportAsJSON($form, $args)
{
$formInputs = FormFieldsParser::getEntryInputs($form, ['admin_label', 'raw']);
--- a/fluentform/app/Services/WPAsync/FluentFormAsyncRequest.php
+++ b/fluentform/app/Services/WPAsync/FluentFormAsyncRequest.php
@@ -66,7 +66,7 @@
'timeout' => 0.1,
'blocking' => false,
'body' => $data,
- 'cookies' => wpFluentForm('request')->cookie(),
+ 'cookies' => $_COOKIE,
'sslverify' => apply_filters('fluentform/https_local_ssl_verify', $sslVerify),
);
--- a/fluentform/boot/app.php
+++ b/fluentform/boot/app.php
@@ -37,13 +37,25 @@
($app->make(ActivationHandler::class))->handle($network_wide);
});
- add_action('wp_insert_site', function ($blog) use ($app) {
- if (is_plugin_active_for_network('fluentform/fluentform.php')) {
- switch_to_blog($blog->blog_id);
- ($app->make(ActivationHandler::class))->handle(false);
- restore_current_blog();
+ $initializeNewSite = function ($blogId) use ($app) {
+ if (!is_plugin_active_for_network('fluentform/fluentform.php')) {
+ return;
}
- });
+
+ switch_to_blog($blogId);
+ ($app->make(ActivationHandler::class))->handle(false);
+ restore_current_blog();
+ };
+
+ if (function_exists('wp_initialize_site')) {
+ add_action('wp_initialize_site', function ($newSite) use ($initializeNewSite) {
+ $initializeNewSite($newSite->id);
+ }, 20, 1);
+ } else {
+ add_action('wpmu_new_blog', function ($blogId) use ($initializeNewSite) {
+ $initializeNewSite($blogId);
+ }, 10, 1);
+ }
register_deactivation_hook($file, function () use ($app) {
($app->make(DeactivationHandler::class))->handle();
--- a/fluentform/boot/globals.php
+++ b/fluentform/boot/globals.php
@@ -387,9 +387,6 @@
'style' => [],
];
- //button
- $tags['button']['onclick'] = [];
-
//svg
if (empty($tags['svg'])) {
$svg_args = [
@@ -434,6 +431,19 @@
$tags = apply_filters('fluentform/allowed_html_tags', $tags);
+ // Event-handler attributes are executable JavaScript and must not be re-enabled by filters.
+ foreach ($tags as $tagName => $attributes) {
+ if (!is_array($attributes)) {
+ continue;
+ }
+
+ foreach (array_keys($attributes) as $attribute) {
+ if (preg_match('/^on[a-z]+/i', $attribute)) {
+ unset($tags[$tagName][$attribute]);
+ }
+ }
+ }
+
return wp_kses($html, $tags);
}
--- a/fluentform/fluentform.php
+++ b/fluentform/fluentform.php
@@ -4,7 +4,7 @@
/**
* Plugin Name: Fluent Forms
* Description: Contact Form By Fluent Forms is the advanced Contact form plugin with drag and drop, multi column supported form builder plugin
- * Version: 6.2.1
+ * Version: 6.2.2
* Author: Contact Form - WPManageNinja LLC
* Author URI: https://fluentforms.com
* Plugin URI: https://wpmanageninja.com/wp-fluent-form/
@@ -17,7 +17,7 @@
defined('FLUENTFORM') or define('FLUENTFORM', true);
define('FLUENTFORM_DIR_PATH', plugin_dir_path(__FILE__));
define('FLUENTFORM_FRAMEWORK_UPGRADE', '4.3.22');
-defined('FLUENTFORM_VERSION') or define('FLUENTFORM_VERSION', '6.2.1');
+defined('FLUENTFORM_VERSION') or define('FLUENTFORM_VERSION', '6.2.2');
defined('FLUENTFORM_MINIMUM_PRO_VERSION') or define('FLUENTFORM_MINIMUM_PRO_VERSION', '6.0.0');
if (!defined('FLUENTFORM_HAS_NIA')) {