validate([ 'title' => $title, 'formFields' => $formFields, ]); try { $form = Form::findOrFail($formId); } catch (Exception $e) { throw new \Exception("The form couldn't be found."); } $data = [ 'title' => $title, 'status' => $status, 'updated_at' => current_time('mysql'), ]; if ($formFields) { $formFields = apply_filters_deprecated( 'fluentform_form_fields_update', [ $formFields, $formId ], FLUENTFORM_FRAMEWORK_UPGRADE, 'fluentform/form_fields_update', 'Use fluentform/form_fields_update instead of fluentform_form_fields_update.' ); $formFields = apply_filters('fluentform/form_fields_update', $formFields, $formId); $formFields = $this->sanitizeFields($formFields); $data['form_fields'] = $formFields; /** * Fires before a Form is updated. * @since 5.2.1 */ do_action('fluentform/before_updating_form', $form, $data); $form->fill($data); if (FormFieldsParser::hasPaymentFields($form)) { $data['has_payment'] = 1; } elseif ($form->has_payment) { $data['has_payment'] = 0; } $this->updatePrimaryEmail($form); } $form->fill($data)->save(); return $form; } private function validate($attributes) { if ($attributes['formFields']) { $duplicates = Helper::getDuplicateFieldNames($attributes['formFields']); if ($duplicates) { $duplicateString = implode(', ', $duplicates); throw new Exception( sprintf('Name attribute %s has duplicate value.', esc_html($duplicateString)) ); } $duplicateRankingFields = Helper::getRankingFieldsWithDuplicateOptionValues($attributes['formFields']); if ($duplicateRankingFields) { $duplicateRankingFields = implode(', ', array_unique($duplicateRankingFields)); throw new Exception( sprintf( __('Ranking field %s has duplicate option values. Please make each option value unique.', 'fluentform'), esc_html($duplicateRankingFields) ) ); } } if (!$attributes['title']) { throw new Exception('The title field is required.'); } } private function sanitizeFields($formFields) { if (fluentformCanUnfilteredHTML()) { return $formFields; } $fieldsArray = json_decode($formFields, true); if (isset($fieldsArray['submitButton'])) { $fieldsArray['submitButton']['settings']['button_ui']['text'] = fluentform_sanitize_html( $fieldsArray['submitButton']['settings']['button_ui']['text'] ); if (!empty($fieldsArray['submitButton']['settings']['button_ui']['img_url'])) { $fieldsArray['submitButton']['settings']['button_ui']['img_url'] = sanitize_url( $fieldsArray['submitButton']['settings']['button_ui']['img_url'] ); } } $fieldsArray['fields'] = $this->sanitizeFieldMaps($fieldsArray['fields']); $fieldsArray['fields'] = $this->sanitizeCustomSubmit($fieldsArray['fields']); if ($stepsWrapper = Arr::get($fieldsArray, 'stepsWrapper')) { $fieldsArray['stepsWrapper'] = $this->sanitizeStepsWrapper($stepsWrapper); } return json_encode($fieldsArray); } private function sanitizeFieldMaps($fields) { if (!is_array($fields)) { return $fields; } $attributesMap = [ 'name' => 'sanitize_key', 'value' => 'sanitize_textarea_field', 'id' => 'sanitize_key', 'class' => 'sanitize_text_field', 'placeholder' => 'sanitize_text_field', ]; $attributesKeys = array_keys($attributesMap); $settingsMap = [ 'container_class' => 'sanitize_text_field', 'label' => 'fluentform_sanitize_html', 'tnc_html' => 'fluentform_sanitize_html', 'label_placement' => 'sanitize_text_field', 'help_message' => 'wp_kses_post', 'admin_field_label' => 'sanitize_text_field', 'prefix_label' => 'sanitize_text_field', 'suffix_label' => 'sanitize_text_field', 'icon_source' => 'sanitize_key', 'icon_type' => 'sanitize_key', 'custom_icon_svg' => [RatingIcon::class, 'sanitizeCustomSvg'], 'inactive_color' => [RatingIcon::class, 'sanitizeColor'], 'active_color' => [RatingIcon::class, 'sanitizeColor'], 'unique_validation_message' => 'sanitize_text_field', 'advanced_options' => 'fluentform_options_sanitize', 'html_codes' => 'fluentform_sanitize_html', 'description' => 'fluentform_sanitize_html', 'grid_columns' => [Helper::class, 'sanitizeArrayKeysAndValues'], 'grid_rows' => [Helper::class, 'sanitizeArrayKeysAndValues'], 'enable_crop' => 'sanitize_text_field', 'crop_mode' => 'sanitize_text_field', 'crop_ratio' => 'sanitize_text_field', 'crop_width' => 'absint', 'crop_height' => 'absint', 'enforce_image_dimensions' => 'sanitize_text_field', ]; $settingsKeys = array_keys($settingsMap); $stylePrefMap = [ 'layout' => 'sanitize_key', 'media' => 'sanitize_url', 'alt_text' => 'sanitize_text_field', ]; $stylePrefKeys = array_keys($stylePrefMap); foreach ($fields as $fieldIndex => &$field) { $element = Arr::get($field, 'element'); if ('container' == $element) { $columns = $field['columns']; foreach ($columns as $columnIndex => $column) { $fields[$fieldIndex]['columns'][$columnIndex]['fields'] = $this->sanitizeFieldMaps($column['fields']); } continue; } if ('welcome_screen' == $element) { if ($value = Arr::get($field, 'settings.button_ui.text')) { $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']); } } } if (!empty($field['attributes'])) { $attributes = array_filter(Arr::only($field['attributes'], $attributesKeys)); foreach ($attributes as $key => $value) { $fields[$fieldIndex]['attributes'][$key] = call_user_func($attributesMap[$key], $value); } } if (!empty($field['settings'])) { $settings = array_filter(Arr::only($field['settings'], array_values($settingsKeys))); foreach ($settings as $key => $value) { $fields[$fieldIndex]['settings'][$key] = call_user_func($settingsMap[$key], $value); } } /* * Handle Name or address fields */ if (!empty($field['fields'])) { $fields[$fieldIndex]['fields'] = $this->sanitizeFieldMaps($field['fields']); continue; } if (!empty($field['style_pref'])) { $settings = array_filter(Arr::only($field['style_pref'], $stylePrefKeys)); foreach ($settings as $key => $value) { $fields[$fieldIndex]['style_pref'][$key] = call_user_func($stylePrefMap[$key], $value); } } $validationRules = Arr::get($field, 'settings.validation_rules'); if (!empty($validationRules)) { foreach ($validationRules as $key => $rule) { if (isset($rule['message'])) { $message = $rule['message']; $field['settings']['validation_rules'][$key]['message'] = wp_kses_post($message); continue; } } } } return $fields; } private function updatePrimaryEmail($form) { $emailInputs = FormFieldsParser::getElement($form, ['input_email'], ['element', 'attributes']); if ($emailInputs) { $emailInput = array_shift($emailInputs); $emailInputName = Arr::get($emailInput, 'attributes.name'); } else { $emailInputName = ''; } FormMeta::persist($form->id, '_primary_email_field', $emailInputName); } private function sanitizeCustomSubmit($fields) { $customSubmitSanitizationMap = [ 'hover_styles' => [ 'backgroundColor' => [$this, 'sanitizeRgbColor'], 'borderColor' => [$this, 'sanitizeRgbColor'], 'color' => [$this, 'sanitizeRgbColor'], 'borderRadius' => 'sanitize_text_field', 'minWidth' => [$this, 'sanitizeMinWidth'] ], 'normal_styles' => [ 'backgroundColor' => [$this, 'sanitizeRgbColor'], 'borderColor' => [$this, 'sanitizeRgbColor'], 'color' => [$this, 'sanitizeRgbColor'], 'borderRadius' => 'sanitize_text_field', 'minWidth' => [$this, 'sanitizeMinWidth'] ], 'button_ui' => [ 'type' => 'sanitize_text_field', 'text' => 'fluentform_sanitize_html', 'img_url' => 'esc_url_raw', ], ]; foreach ($fields as $fieldIndex => $field) { $element = Arr::get($field, 'element'); if ('custom_submit_button' == $element) { $styleAttr = ['hover_styles', 'normal_styles', 'button_ui']; foreach ($styleAttr as $attr) { if ($styleConfigs = Arr::get($field, 'settings.' . $attr)) { foreach ($styleConfigs as $key => $value) { if (isset($customSubmitSanitizationMap[$attr][$key])) { $sanitizeFunction = $customSubmitSanitizationMap[$attr][$key]; $fields[$fieldIndex]['settings'][$attr][$key] = $sanitizeFunction($value); } } } } } elseif ('container' == $element) { $columns = $field['columns']; foreach ($columns as $columnIndex => $column) { $fields[$fieldIndex]['columns'][$columnIndex]['fields'] = $this->sanitizeCustomSubmit($column['fields']); } return $fields; } } return $fields; } private function sanitizeStepsWrapper($stepWrapper) { $stepsSanitizationMap = [ 'prev_btn' => [ 'type' => 'sanitize_text_field', 'text' => 'fluentform_sanitize_html', 'img_url' => 'esc_url_raw', ], ]; foreach ($stepWrapper as $fieldIndex => $field) { $element = Arr::get($field, 'element'); if ($element === 'step_start' || $element === 'step_end') { if (!empty($field['settings']['step_titles']) && is_array($field['settings']['step_titles'])) { foreach ($field['settings']['step_titles'] as $index => $title) { $field['settings']['step_titles'][$index] = fluentform_sanitize_html($title); } } if (isset($field['settings']['tabs_show_progress_bar'])) { $field['settings']['tabs_show_progress_bar'] = sanitize_text_field($field['settings']['tabs_show_progress_bar']) === 'yes' ? 'yes' : 'no'; } if (isset($field['settings']['progress_layout'])) { $progressLayout = sanitize_text_field($field['settings']['progress_layout']); $field['settings']['progress_layout'] = in_array($progressLayout, ['top', 'left'], true) ? $progressLayout : 'top'; } if (!empty($field['settings']['prev_btn']) && is_array($field['settings']['prev_btn'])) { foreach ($field['settings']['prev_btn'] as $key => $value) { if (isset($stepsSanitizationMap['prev_btn'][$key])) { $sanitizeFunction = $stepsSanitizationMap['prev_btn'][$key]; $field['settings']['prev_btn'][$key] = $sanitizeFunction($value); } } } if (!empty($field['attributes']['class'])) { $field['attributes']['class'] = sanitize_text_field($field['attributes']['class']); } if (!empty($field['attributes']['id'])) { $field['attributes']['id'] = sanitize_text_field($field['attributes']['id']); } } if ($element === 'step_start' && isset($field['fields'])) { $field['fields'] = $this->sanitizeStepsWrapper($field['fields']); } $stepWrapper[$fieldIndex] = $field; } return $stepWrapper; } public function sanitizeMinWidth($value) { if (is_string($value) && preg_match('/^\d+%$/', $value)) { return $value; } return ''; } public function sanitizeRgbColor($value) { if (preg_match('/^rgba?\((\d{1,3}\s*,\s*){2,3}(0|1|0?\.\d+)\)$/', $value)) { return $value; } return ''; } }