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/Modules/Form/Form.php +530 -227 3.6.616.2.14 View file →
@@ -3,13 +3,18 @@
3 3 namespace FluentForm\App\Modules\Form;
4 4
5 5 use FluentForm\App\Helpers\Helper;
6 6 use FluentForm\App\Modules\Acl\Acl;
7 +use FluentForm\App\Modules\Payments\PaymentHelper;
8 +use FluentForm\App\Services\FormBuilder\RatingIcon;
7 9 use FluentForm\Framework\Foundation\Application;
10 +use FluentForm\Framework\Helpers\ArrayHelper;
8 11
9 12 class Form
10 13 {
11 14 /**
15 + * Request object
16 + *
12 17 * @var \FluentForm\Framework\Request\Request $request
13 18 */
14 19 protected $request;
15 20
@@ -19,9 +24,8 @@
19 24 * @var array $defaultSettings
20 25 */
21 26 protected $defaultSettings;
22 27
23 -
24 28 /**
25 29 * Set this value when we need predefined default notifications.
26 30 *
27 31 * @var array $defaultNotifications
@@ -39,15 +43,17 @@
39 43
40 44 protected $formType = 'form';
41 45
42 46 protected $hasPayment = 0;
47 + /**
48 + * @var \FluentForm\Framework\Database\Query\Builder
49 + */
50 + protected $model = null;
43 51
44 52 /**
45 53 * Form constructor.
46 54 *
47 55 * @param \FluentForm\Framework\Foundation\Application $application
48 - *
49 - * @throws \Exception
50 56 */
51 57 public function __construct(Application $application)
52 58 {
53 59 $this->request = $application->request;
@@ -55,93 +61,31 @@
55 61 }
56 62
57 63 /**
58 64 * Get all forms from database
59 - *
60 - * @return void
61 - * @throws \Exception
62 65 */
63 66 public function index()
64 67 {
65 - $search = $this->request->get('search');
66 - $status = $this->request->get('status');
68 + $forms = fluentFormApi('forms')->forms([
69 + 'search' => $this->request->get('search'),
70 + 'status' => $this->request->get('status'),
71 + 'filter_by' => $this->request->get('filter_by', 'all'),
72 + 'date_range' => $this->request->get('date_range', []),
73 + 'sort_column' => $this->request->get('sort_column', 'id'),
74 + 'sort_by' => $this->request->get('sort_by', 'DESC'),
75 + 'per_page' => $this->request->get('per_page', 10),
76 + 'page' => $this->request->get('page', 1),
77 + ]);
67 78
68 - $shortColumn = $this->request->get('sort_column', 'id');
69 - $sortBy = $this->request->get('sort_by', 'DESC');
70 -
71 - $query = wpFluent()->table('fluentform_forms')
72 - ->orderBy($shortColumn, $sortBy);
73 -
74 - if ($status && $status != 'all') {
75 - $query->where('status', $status);
76 - }
77 -
78 - if ($search) {
79 - $query->where(function ($q) use ($search) {
80 - $q->where('id', 'LIKE', '%' . $search . '%');
81 - $q->orWhere('title', 'LIKE', '%' . $search . '%');
82 - });
83 - }
84 -
85 - $forms = $query->paginate();
86 -
87 - foreach ($forms['data'] as $form) {
88 - $form->preview_url = site_url('?fluentform_pages=1&preview_id=' . $form->id) . '#ff_preview';;
89 - $form->edit_url = $this->getAdminPermalink('editor', $form);
90 - $form->settings_url = $this->getSettingsUrl($form);
91 - $form->entries_url = $this->getAdminPermalink('entries', $form);
92 - $form->analytics_url = $this->getAdminPermalink('analytics', $form);
93 - $form->total_views = $this->getFormViewCount($form->id);
94 - $form->total_views = $this->getFormViewCount($form->id);
95 - $form->total_Submissions = $this->getSubmissionCount($form->id);
96 - $form->unread_count = $this->getUnreadCount($form->id);
97 - $form->conversion = $this->getConversionRate($form);
98 - unset($form->form_fields);
99 - }
100 -
101 79 wp_send_json($forms, 200);
102 80 }
103 81
104 - private function getFormViewCount($formId)
105 - {
106 - $hasCount = wpFluent()
107 - ->table('fluentform_form_meta')
108 - ->where('meta_key', '_total_views')
109 - ->where('form_id', $formId)
110 - ->first();
111 -
112 - if ($hasCount) {
113 - return intval($hasCount->value);
114 - }
115 -
116 - return 0;
117 - }
118 -
119 - private function getSubmissionCount($formID)
120 - {
121 - return wpFluent()
122 - ->table('fluentform_submissions')
123 - ->where('form_id', $formID)
124 - ->where('status', '!=', 'trashed')
125 - ->count();
126 - }
127 -
128 - private function getConversionRate($form)
129 - {
130 - if (!$form->total_Submissions)
131 - return 0;
132 -
133 - if (!$form->total_views)
134 - return 0;
135 -
136 - return ceil(($form->total_Submissions / $form->total_views) * 100);
137 - }
138 -
139 82 /**
140 83 * Create a form from backend/editor
141 - * @return void
84 + *
85 + * @return void|array
142 86 */
143 - public function store()
87 + public function store($returnJSON = true)
144 88 {
145 89 $type = $this->request->get('type', $this->formType);
146 90 $title = $this->request->get('title', 'My New Form');
147 91 $status = $this->request->get('status', 'published');
@@ -149,14 +93,14 @@
149 93
150 94 $now = current_time('mysql');
151 95
152 96 $insertData = [
153 - 'title' => $title,
154 - 'type' => $type,
155 - 'status' => $status,
97 + 'title' => $title,
98 + 'type' => $type,
99 + 'status' => $status,
156 100 'created_by' => $createdBy,
157 101 'created_at' => $now,
158 - 'updated_at' => $now
102 + 'updated_at' => $now,
159 103 ];
160 104
161 105 if ($this->formFields) {
162 106 $insertData['form_fields'] = $this->formFields;
@@ -161,104 +105,132 @@
161 105 if ($this->formFields) {
162 106 $insertData['form_fields'] = $this->formFields;
163 107 }
164 108
165 - if($this->hasPayment) {
109 + if ($this->hasPayment) {
166 110 $insertData['has_payment'] = $this->hasPayment;
167 111 }
168 112
169 - $formId = $this->model->insert($insertData);
113 + $formId = $this->model->insertGetId($insertData);
170 114
171 115 // Rename the form name here
172 - wpFluent()->table('fluentform_forms')->where('id', $formId)->update(array(
173 - 'title' => $title . ' (#' . $formId . ')'
174 - ));
116 + wpFluent()->table('fluentform_forms')->where('id', $formId)->update([
117 + 'title' => $title . ' (#' . $formId . ')',
118 + ]);
175 119
176 - if($this->metas && is_array($this->metas)) {
120 + if ($this->metas && is_array($this->metas)) {
177 121 foreach ($this->metas as $meta) {
178 122 $meta['value'] = trim(preg_replace('/\s+/', ' ', $meta['value']));
179 123
180 124 wpFluent()->table('fluentform_form_meta')
181 - ->insert(array(
182 - 'form_id' => $formId,
125 + ->insert([
126 + 'form_id' => $formId,
183 127 'meta_key' => $meta['meta_key'],
184 - 'value' => $meta['value']
185 - ));
128 + 'value' => $meta['value'],
129 + ]);
186 130 }
187 131 } else {
188 132 // add default form settings now
189 133 $defaultSettings = $this->defaultSettings ?: $this->getFormsDefaultSettings($formId);
134 +
135 + $defaultSettings = apply_filters_deprecated(
136 + 'fluentform_create_default_settings',
137 + [
138 + $defaultSettings
139 + ],
140 + FLUENTFORM_FRAMEWORK_UPGRADE,
141 + 'fluentform/create_default_settings',
142 + 'Use fluentform/create_default_settings instead of fluentform_create_default_settings.'
143 + );
190 144
191 - $defaultSettings = apply_filters('fluentform_create_default_settings', $defaultSettings);
145 + $defaultSettings = apply_filters('fluentform/create_default_settings', $defaultSettings);
192 146
193 147 wpFluent()->table('fluentform_form_meta')
194 - ->insert(array(
195 - 'form_id' => $formId,
148 + ->insert([
149 + 'form_id' => $formId,
196 150 'meta_key' => 'formSettings',
197 - 'value' => json_encode($defaultSettings)
198 - ));
151 + 'value' => json_encode($defaultSettings),
152 + ]);
199 153
200 154 if ($this->defaultNotifications) {
201 155 wpFluent()->table('fluentform_form_meta')
202 - ->insert(array(
203 - 'form_id' => $formId,
156 + ->insert([
157 + 'form_id' => $formId,
204 158 'meta_key' => 'notifications',
205 - 'value' => json_encode($this->defaultNotifications)
206 - ));
159 + 'value' => json_encode($this->defaultNotifications),
160 + ]);
207 161 }
208 162 }
209 163
210 - do_action('fluentform_inserted_new_form', $formId, $insertData);
164 + do_action_deprecated(
165 + 'fluentform_inserted_new_form',
166 + [
167 + $formId,
168 + $insertData
169 + ],
170 + FLUENTFORM_FRAMEWORK_UPGRADE,
171 + 'fluentform/inserted_new_form',
172 + 'Use fluentform/inserted_new_form instead of fluentform_inserted_new_form.'
173 + );
211 174
212 - wp_send_json_success(array(
213 - 'formId' => $formId,
175 + do_action('fluentform/inserted_new_form', $formId, $insertData);
176 +
177 + $data = [
178 + 'formId' => $formId,
214 179 'redirect_url' => admin_url('admin.php?page=fluent_forms&form_id=' . $formId . '&route=editor'),
215 - 'message' => __('Successfully created a form.', 'fluentform')
216 - ), 200);
180 + 'message' => __('Successfully created a form.', 'fluentform'),
181 + ];
182 +
183 + if ($returnJSON) {
184 + wp_send_json_success($data, 200);
185 + }
186 +
187 + return $data;
217 188 }
218 189
219 190 public function getFormsDefaultSettings($formId = false)
220 191 {
221 - $defaultSettings = array(
222 - 'confirmation' => array(
223 - 'redirectTo' => 'samePage',
224 - 'messageToShow' => __('Thank you for your message. We will get in touch with you shortly', 'fluentform'),
225 - 'customPage' => null,
192 + $defaultSettings = [
193 + 'confirmation' => [
194 + 'redirectTo' => 'samePage',
195 + 'messageToShow' => __('Thank you for your message. We will get in touch with you shortly.', 'fluentform'),
196 + 'customPage' => null,
226 197 'samePageFormBehavior' => 'hide_form',
227 - 'customUrl' => null
228 - ),
229 - 'restrictions' => array(
230 - 'limitNumberOfEntries' => array(
231 - 'enabled' => false,
198 + 'customUrl' => null,
199 + ],
200 + 'restrictions' => [
201 + 'limitNumberOfEntries' => [
202 + 'enabled' => false,
232 203 'numberOfEntries' => null,
233 - 'period' => 'total',
234 - 'limitReachedMsg' => 'Maximum number of entries exceeded.'
235 - ),
236 - 'scheduleForm' => array(
237 - 'enabled' => false,
238 - 'start' => null,
239 - 'end' => null,
240 - 'pendingMsg' => __("Form submission is not started yet.", 'fluentform'),
241 - 'expiredMsg' => __("Form submission is now closed.", 'fluentform')
242 - ),
243 - 'requireLogin' => array(
244 - 'enabled' => false,
204 + 'period' => 'total',
205 + 'limitReachedMsg' => 'Maximum number of entries exceeded.',
206 + ],
207 + 'scheduleForm' => [
208 + 'enabled' => false,
209 + 'start' => null,
210 + 'end' => null,
211 + 'selectedDays' => null,
212 + 'pendingMsg' => __('Form submission is not started yet.', 'fluentform'),
213 + 'expiredMsg' => __('Form submission is now closed.', 'fluentform'),
214 + ],
215 + 'requireLogin' => [
216 + 'enabled' => false,
245 217 'requireLoginMsg' => 'You must be logged in to submit the form.',
246 - ),
218 + ],
247 219 'denyEmptySubmission' => [
248 220 'enabled' => false,
249 221 'message' => __('Sorry, you cannot submit an empty form. Let\'s hear what you wanna say.', 'fluentform'),
250 - ]
251 - ),
252 - 'layout' => array(
253 - 'labelPlacement' => 'top',
254 - 'helpMessagePlacement' => 'with_label',
222 + ],
223 + ],
224 + 'layout' => [
225 + 'labelPlacement' => 'top',
226 + 'helpMessagePlacement' => 'with_label',
255 227 'errorMessagePlacement' => 'inline',
256 - 'cssClassName' => '',
257 - 'asteriskPlacement' => 'asterisk-right'
258 - ),
259 - 'delete_entry_on_submission' => 'no'
260 - );
228 + 'cssClassName' => '',
229 + 'asteriskPlacement' => 'asterisk-right'
230 + ],
231 + 'delete_entry_on_submission' => 'no',
232 + ];
261 233
262 234 if ($formId) {
263 235 $value = $this->getMeta($formId, 'formSettings', true);
264 236 if ($value) {
@@ -276,24 +248,24 @@
276 248
277 249 public function getAdvancedValidationSettings($formId)
278 250 {
279 251 $settings = [
280 - 'status' => false,
281 - 'type' => 'all',
252 + 'status' => false,
253 + 'type' => 'all',
282 254 'conditions' => [
283 255 [
284 - 'field' => '',
256 + 'field' => '',
285 257 'operator' => '=',
286 - 'value' => ''
287 - ]
258 + 'value' => '',
259 + ],
288 260 ],
289 - 'error_message' => '',
290 - 'validation_type' => 'fail_on_condition_met'
261 + 'error_message' => '',
262 + 'validation_type' => 'fail_on_condition_met',
291 263 ];
292 264
293 265 $metaSettings = $this->getMeta($formId, 'advancedValidationSettings', true);
294 266
295 - if($metaSettings && is_array($metaSettings)) {
267 + if ($metaSettings && is_array($metaSettings)) {
296 268 $settings = wp_parse_args($metaSettings, $settings);
297 269 }
298 270
299 271 return $settings;
@@ -305,9 +277,9 @@
305 277 ->where('form_id', $formId)
306 278 ->where('meta_key', $metaKey)
307 279 ->first();
308 280 if ($settingsMeta) {
309 - if($isJson) {
281 + if ($isJson) {
310 282 return \json_decode($settingsMeta->value, true);
311 283 } else {
312 284 return $settingsMeta->value;
313 285 }
@@ -321,24 +293,24 @@
321 293 ->where('form_id', $formId)
322 294 ->where('meta_key', $metaKey)
323 295 ->first();
324 296
325 - if(is_array($metaValue) || is_object($metaValue)) {
297 + if (is_array($metaValue) || is_object($metaValue)) {
326 298 $metaValue = \json_encode($metaValue);
327 299 }
328 300
329 - if($exist) {
301 + if ($exist) {
330 302 return wpFluent()->table('fluentform_form_meta')
331 303 ->where('id', $exist->id)
332 304 ->update([
333 - 'value' => $metaValue
305 + 'value' => $metaValue,
334 306 ]);
335 307 }
336 308
337 - return wpFluent()->table('fluentform_form_meta')->insert([
338 - 'form_id' => $formId,
309 + return wpFluent()->table('fluentform_form_meta')->insertGetId([
310 + 'form_id' => $formId,
339 311 'meta_key' => $metaKey,
340 - 'value' => $metaValue
312 + 'value' => $metaValue,
341 313 ]);
342 314 }
343 315
344 316 public function deleteMeta($formId, $metaKey)
@@ -350,9 +322,8 @@
350 322 }
351 323
352 324 /**
353 325 * Find/Read a from from the database
354 - * @return void
355 326 */
356 327 public function find()
357 328 {
358 329 $form = $this->fetchForm($this->request->get('formId'));
@@ -361,8 +332,9 @@
361 332
362 333 /**
363 334 * Fetch a from from the database
364 335 * Note: required for ninja-tables
336 + *
365 337 * @return mixed
366 338 */
367 339 public function fetchForm($formId)
368 340 {
@@ -370,28 +342,36 @@
370 342 }
371 343
372 344 /**
373 345 * Save/update a form from backend/editor
374 - * @return void
375 - * @throws \WpFluent\Exception
376 346 */
377 347 public function update()
378 348 {
379 349 $formId = $this->request->get('formId');
380 - $title = $this->request->get('title');
350 + $title = sanitize_text_field($this->request->get('title'));
381 351 $status = $this->request->get('status', 'published');
382 352
383 353 $this->validate();
384 354
385 355 $data = [
386 - 'title' => $title,
387 - 'status' => $status,
388 - 'updated_at' => current_time('mysql')
356 + 'title' => $title,
357 + 'status' => $status,
358 + 'updated_at' => current_time('mysql'),
389 359 ];
390 360
391 -
392 361 if ($formFields = $this->request->get('formFields')) {
393 - $formFields = apply_filters('fluentform_form_fields_update', $formFields, $formId);
362 + $formFields = apply_filters_deprecated(
363 + 'fluentform_form_fields_update',
364 + [
365 + $formFields,
366 + $formId
367 + ],
368 + FLUENTFORM_FRAMEWORK_UPGRADE,
369 + 'fluentform/form_fields_update',
370 + 'Use fluentform/form_fields_update instead of fluentform_form_fields_update.'
371 + );
372 + $formFields = apply_filters('fluentform/form_fields_update', $formFields, $formId);
373 + $formFields = $this->sanitizeFields($formFields);
394 374 $data['form_fields'] = $formFields;
395 375 }
396 376
397 377 $this->model->where('id', $formId)->update($data);
@@ -399,25 +379,141 @@
399 379 $form = $this->fetchForm($formId);
400 380
401 381 if (FormFieldsParser::hasPaymentFields($form)) {
402 382 $this->model->where('id', $formId)->update([
403 - 'has_payment' => 1
383 + 'has_payment' => 1,
404 384 ]);
405 - } else if ($form->has_payment) {
385 + } elseif ($form->has_payment) {
406 386 $this->model->where('id', $formId)->update([
407 - 'has_payment' => 0
387 + 'has_payment' => 0,
408 388 ]);
409 389 }
410 390
391 + $emailInputs = FormFieldsParser::getElement($form, ['input_email'], ['element', 'attributes']);
392 + if ($emailInputs) {
393 + $emailInput = array_shift($emailInputs);
394 + $emailInputName = ArrayHelper::get($emailInput, 'attributes.name');
395 + $this->updateMeta($formId, '_primary_email_field', $emailInputName);
396 + } else {
397 + $this->updateMeta($formId, '_primary_email_field', '');
398 + }
399 +
411 400 wp_send_json([
412 - 'message' => __('The form is successfully updated.', 'fluentform')
401 + 'message' => __('The form is successfully updated.', 'fluentform'),
413 402 ], 200);
414 403 }
415 404
405 + private function sanitizeFields($formFields)
406 + {
407 + if (fluentformCanUnfilteredHTML()) {
408 + return $formFields;
409 + }
410 +
411 + $fieldsArray = json_decode($formFields, true);
412 +
413 + if (isset($fieldsArray['submitButton'])) {
414 + $fieldsArray['submitButton']['settings']['button_ui']['text'] = fluentform_sanitize_html($fieldsArray['submitButton']['settings']['button_ui']['text']);
415 + if (!empty($fieldsArray['submitButton']['settings']['button_ui']['img_url'])) {
416 + $fieldsArray['submitButton']['settings']['button_ui']['img_url'] = sanitize_url($fieldsArray['submitButton']['settings']['button_ui']['img_url']);
417 + }
418 + }
419 +
420 + $fieldsArray['fields'] = $this->sanitizeFieldMaps($fieldsArray['fields']);
421 +
422 + return json_encode($fieldsArray);
423 + }
424 +
425 + private function sanitizeFieldMaps($fields)
426 + {
427 + if (!is_array($fields)) {
428 + return $fields;
429 + }
430 +
431 + $attributesMap = [
432 + 'name' => 'sanitize_key',
433 + 'value' => 'sanitize_textarea_field',
434 + 'id' => 'sanitize_key',
435 + 'class' => 'sanitize_text_field',
436 + 'placeholder' => 'sanitize_text_field',
437 + ];
438 + $attributesKeys = array_keys($attributesMap);
439 + $settingsMap = [
440 + 'container_class' => 'sanitize_text_field',
441 + 'label' => 'wp_kses_post',
442 + 'label_placement' => 'sanitize_text_field',
443 + 'help_message' => 'wp_kses_post',
444 + 'admin_field_label' => 'sanitize_text_field',
445 + 'prefix_label' => 'sanitize_text_field',
446 + 'suffix_label' => 'sanitize_text_field',
447 + 'icon_source' => 'sanitize_key',
448 + 'icon_type' => 'sanitize_key',
449 + 'custom_icon_svg' => [RatingIcon::class, 'sanitizeCustomSvg'],
450 + 'inactive_color' => [RatingIcon::class, 'sanitizeColor'],
451 + 'active_color' => [RatingIcon::class, 'sanitizeColor'],
452 + 'unique_validation_message' => 'sanitize_text_field',
453 + 'advanced_options' => 'fluentform_options_sanitize',
454 + 'html_codes' => 'fluentform_sanitize_html',
455 + 'enable_crop' => 'sanitize_text_field',
456 + 'crop_mode' => 'sanitize_text_field',
457 + 'crop_ratio' => 'sanitize_text_field',
458 + 'crop_width' => 'absint',
459 + 'crop_height' => 'absint',
460 + 'enforce_image_dimensions' => 'sanitize_text_field',
461 + ];
462 + $settingsKeys = array_keys($settingsMap);
463 + $stylePrefMap = [
464 + 'layout' => 'sanitize_key',
465 + 'media' => 'sanitize_url',
466 + 'alt_text' => 'sanitize_text_field',
467 + ];
468 + $stylePrefKeys = array_keys($stylePrefMap);
469 +
470 + foreach ($fields as $fieldIndex => $field) {
471 + $element = ArrayHelper::get($field, 'element');
472 +
473 + if ('container' == $element) {
474 + $columns = $field['columns'];
475 + foreach ($columns as $columnIndex => $column) {
476 + $fields[$fieldIndex]['columns'][$columnIndex]['fields'] = $this->sanitizeFieldMaps($column['fields']);
477 + }
478 + return $fields;
479 + }
480 +
481 + /*
482 + * Handle Name or address fields
483 + */
484 + if (!empty($field['fields'])) {
485 + $fields[$fieldIndex]['fields'] = $this->sanitizeFieldMaps($field['fields']);
486 + return $fields;
487 + }
488 +
489 + if (!empty($field['attributes'])) {
490 + $attributes = array_filter(ArrayHelper::only($field['attributes'], $attributesKeys));
491 + foreach ($attributes as $key => $value) {
492 + $fields[$fieldIndex]['attributes'][$key] = call_user_func($attributesMap[$key], $value);
493 + }
494 + }
495 +
496 + if (!empty($field['settings'])) {
497 + $settings = array_filter(ArrayHelper::only($field['settings'], $settingsKeys));
498 + foreach ($settings as $key => $value) {
499 + $fields[$fieldIndex]['settings'][$key] = call_user_func($settingsMap[$key], $value);
500 + }
501 + }
502 +
503 + if (!empty($field['style_pref'])) {
504 + $settings = array_filter(ArrayHelper::only($field['style_pref'], $stylePrefKeys));
505 + foreach ($settings as $key => $value) {
506 + $fields[$fieldIndex]['style_pref'][$key] = call_user_func($stylePrefMap[$key], $value);
507 + }
508 + }
509 + }
510 +
511 + return $fields;
512 + }
513 +
416 514 /**
417 515 * Delete a from from database
418 - * @return void
419 - * @throws \WpFluent\Exception
420 516 */
421 517 public function delete()
422 518 {
423 519 $formId = $this->request->get('formId');
@@ -425,16 +521,14 @@
425 521 $this->model->where('id', $formId)->delete();
426 522
427 523 $maybeErrors = $this->deleteFormAssests($formId);
428 524
429 -
430 525 wp_send_json([
431 526 'message' => __('Successfully deleted the form.', 'fluentform'),
432 - 'errors' => $maybeErrors
527 + 'errors' => $maybeErrors,
433 528 ], 200);
434 529 }
435 530
436 -
437 531 protected function deleteFormAssests($formId)
438 532 {
439 533 // Now Let's delete associate items
440 534 wpFluent()->table('fluentform_submissions')
@@ -448,8 +542,12 @@
448 542 wpFluent()->table('fluentform_entry_details')
449 543 ->where('form_id', $formId)
450 544 ->delete();
451 545
546 + wpFluent()->table('fluentform_form_meta')
547 + ->where('form_id', $formId)
548 + ->delete();
549 +
452 550 wpFluent()->table('fluentform_form_analytics')
453 551 ->where('form_id', $formId)
454 552 ->delete();
455 553
@@ -454,27 +552,20 @@
454 552 ->delete();
455 553
456 554 wpFluent()->table('fluentform_logs')
457 555 ->where('parent_source_id', $formId)
458 - ->whereIn('source_type', ['submission_item', 'form_item'])
556 + ->whereIn('source_type', ['submission_item', 'form_item', 'draft_submission_meta'])
459 557 ->delete();
460 558
461 559 ob_start();
462 - if (defined('FLUENTFORMPRO')) {
560 + if (PaymentHelper::hasPaymentSettings()) {
463 561 try {
464 - wpFluent()->table('fluentform_order_items')
465 - ->where('form_id', $formId)
466 - ->delete();
467 - wpFluent()->table('fluentform_subscriptions')
468 - ->where('form_id', $formId)
469 - ->delete();
470 - wpFluent()->table('fluentform_transactions')
471 - ->where('form_id', $formId)
472 - ->delete();
562 + \FluentForm\App\Models\OrderItem::where('form_id', $formId)->delete();
563 + \FluentForm\App\Models\Transaction::where('form_id', $formId)->delete();
473 564 } catch (\Exception $exception) {
474 -
475 565 }
476 566 }
567 +
477 568 $errors = ob_get_clean();
478 569 return $errors;
479 570 }
480 571
@@ -479,10 +570,8 @@
479 570 }
480 571
481 572 /**
482 573 * Duplicate a from
483 - * @return void
484 - * @throws \WpFluent\Exception
485 574 */
486 575 public function duplicate()
487 576 {
488 577 $formId = absint($this->request->get('formId'));
@@ -487,29 +576,29 @@
487 576 {
488 577 $formId = absint($this->request->get('formId'));
489 578 $form = $this->model->where('id', $formId)->first();
490 579
491 - $data = array(
492 - 'title' => $form->title,
493 - 'status' => $form->status,
580 + $data = [
581 + 'title' => $form->title,
582 + 'status' => $form->status,
494 583 'appearance_settings' => $form->appearance_settings,
495 - 'form_fields' => $form->form_fields,
496 - 'type' => $form->type,
497 - 'has_payment' => $form->has_payment,
498 - 'conditions' => $form->conditions,
499 - 'created_by' => get_current_user_id(),
500 - 'created_at' => current_time('mysql'),
501 - 'updated_at' => current_time('mysql')
502 - );
584 + 'form_fields' => $form->form_fields,
585 + 'type' => $form->type,
586 + 'has_payment' => $form->has_payment,
587 + 'conditions' => $form->conditions,
588 + 'created_by' => get_current_user_id(),
589 + 'created_at' => current_time('mysql'),
590 + 'updated_at' => current_time('mysql'),
591 + ];
503 592
504 - $newFormId = $this->model->insert($data);
593 + $newFormId = $this->model->insertGetId($data);
505 594
506 - // Ranme the form name here
595 + // Rename the form name here
507 596 wpFluent()->table('fluentform_forms')
508 597 ->where('id', $newFormId)
509 - ->update(array(
510 - 'title' => $form->title . ' (#' . $newFormId . ')'
511 - ));
598 + ->update([
599 + 'title' => $form->title . ' (#' . $newFormId . ')',
600 + ]);
512 601
513 602 $formMetas = wpFluent()->table('fluentform_form_meta')
514 603 ->where('form_id', $formId)
515 604 ->whereNot('meta_key', ['_total_views'])
@@ -514,40 +603,126 @@
514 603 ->where('form_id', $formId)
515 604 ->whereNot('meta_key', ['_total_views'])
516 605 ->get();
517 606
607 + // Required for duplicating PDF feeds
608 + $extras = [];
609 +
518 610 foreach ($formMetas as $meta) {
611 + if ('notifications' == $meta->meta_key || '_pdf_feeds' == $meta->meta_key) {
612 + $extras[$meta->meta_key][] = $meta;
613 + continue;
614 + }
615 + if ("ffc_form_settings_generated_css" == $meta->meta_key || "ffc_form_settings_meta" == $meta->meta_key) {
616 + $meta->value = str_replace('ff_conv_app_' . $formId, 'ff_conv_app_' . $newFormId, $meta->value);
617 + }
519 618 $metaData = [
520 619 'meta_key' => $meta->meta_key,
521 - 'value' => $meta->value,
522 - 'form_id' => $newFormId
620 + 'value' => $meta->value,
621 + 'form_id' => $newFormId,
523 622 ];
524 623
525 624 wpFluent()->table('fluentform_form_meta')->insert($metaData);
526 625 }
527 626
528 - do_action('flentform_form_duplicated', $newFormId);
627 + $pdfFeedMap = $this->getPdfFeedMap($extras, $newFormId);
628 + if (array_key_exists('notifications', $extras)) {
629 + $extras = $this->notificationWithPdfMap($extras, $pdfFeedMap);
630 + foreach ($extras['notifications'] as $notify) {
631 + $notifyData = [
632 + 'meta_key' => $notify->meta_key,
633 + 'value' => $notify->value,
634 + 'form_id' => $newFormId,
635 + ];
636 + wpFluent()->table('fluentform_form_meta')->insert($notifyData);
637 + }
638 + }
529 639
640 + do_action_deprecated(
641 + 'flentform_form_duplicated',
642 + [
643 + $newFormId
644 + ],
645 + FLUENTFORM_FRAMEWORK_UPGRADE,
646 + 'fluentform/form_duplicated',
647 + 'Use fluentform/form_duplicated instead of flentform_form_duplicated.'
648 + );
649 +
650 + do_action('fluentform/form_duplicated', $newFormId);
651 +
530 652 wp_send_json([
531 - 'message' => __('Form has been successfully duplicated.', 'fluentform'),
532 - 'form_id' => $newFormId,
533 - 'redirect' => admin_url('admin.php?page=fluent_forms&route=editor&form_id=' . $newFormId)
653 + 'message' => __('Form has been successfully duplicated.', 'fluentform'),
654 + 'form_id' => $newFormId,
655 + 'redirect' => admin_url('admin.php?page=fluent_forms&route=editor&form_id=' . $newFormId),
534 656 ], 200);
535 657 }
536 658
537 659 /**
538 - * Validate a form only by form title
539 - * @return void
660 + * Validate a form by form title & for duplicate name attributes
540 661 */
541 662 private function validate()
542 663 {
543 - if (!$this->request->get('title')) {
664 + $fields = $this->request->get('formFields');
665 + if ($fields) {
666 + $duplicates = Helper::getDuplicateFieldNames($fields);
667 + if ($duplicates) {
668 + $duplicateString = implode(', ', $duplicates);
669 + wp_send_json([
670 + 'title' => sprintf('Name attribute %s has duplicate value.', $duplicateString),
671 + ], 422);
672 + }
673 +
674 + $duplicateRankingFields = Helper::getRankingFieldsWithDuplicateOptionValues($fields);
675 + if ($duplicateRankingFields) {
676 + $duplicateRankingFields = implode(', ', array_unique($duplicateRankingFields));
677 + wp_send_json([
678 + 'title' => sprintf(
679 + __('Ranking field %s has duplicate option values. Please make each option value unique.', 'fluentform'),
680 + $duplicateRankingFields
681 + ),
682 + ], 422);
683 + }
684 + }
685 +
686 + if (!sanitize_text_field($this->request->get('title'))) {
544 687 wp_send_json([
545 - 'title' => 'The title field is required.'
688 + 'title' => 'The title field is required.',
546 689 ], 422);
547 690 }
548 691 }
549 692
693 + public function convertToConversational()
694 + {
695 + $formId = $this->request->get('form_id');
696 + $form = $this->fetchForm($formId);
697 +
698 + if (!$form) {
699 + wp_send_json([
700 + 'message' => __('Form Not Found! Try Again.', 'fluentform'),
701 + ], 422);
702 + }
703 +
704 + $conversationalMeta = $this->getMeta($formId, 'is_conversion_form', false);
705 +
706 + $shouldConvert = in_array($conversationalMeta, [false, 'no']);
707 +
708 + if ($shouldConvert) {
709 + $formConverted['form_fields'] = \FluentForm\App\Services\FluentConversational\Classes\Converter\Converter::convertExistingForm($form);
710 +
711 + $this->model->where('id', $formId)->update($formConverted);
712 +
713 + $conversationalMetaValue = 'yes';
714 + } else {
715 + $conversationalMetaValue = 'no';
716 + }
717 +
718 + $this->updateMeta($formId, 'is_conversion_form', $conversationalMetaValue);
719 +
720 + wp_send_json_success([
721 + 'message' => __('Form has been successfully converted.', 'fluentform'),
722 + ], 200);
723 + }
724 +
550 725 private function getAdminPermalink($route, $form)
551 726 {
552 727 $baseUrl = admin_url('admin.php?page=fluent_forms');
553 728 return $baseUrl . '&route=' . $route . '&form_id=' . $form->id;
@@ -557,28 +732,156 @@
557 732 {
558 733 $baseUrl = admin_url('admin.php?page=fluent_forms');
559 734 return $baseUrl . '&form_id=' . $form->id . '&route=settings&sub_route=form_settings#basic_settings';
560 735 }
736 +
561 737
562 - public function getAllForms()
738 + /**
739 + * Map pdf feed ID to replace with duplicated PDF feed ID when duplicating form
740 + *
741 + * @param array $extras
742 + * @param array $newFormId
743 + *
744 + * @return array
745 + */
746 + private function getPdfFeedMap($extras, $newFormId)
563 747 {
564 - $fields = $this->request->get('fields');
748 + $pdfFeedMap = [];
749 + if (array_key_exists('_pdf_feeds', $extras)) {
750 + foreach ($extras['_pdf_feeds'] as $pdf_feed) {
751 + $pdfData = [
752 + 'meta_key' => $pdf_feed->meta_key,
753 + 'value' => $pdf_feed->value,
754 + 'form_id' => $newFormId,
755 + ];
756 + $pdfFeedMap[$pdf_feed->id] = wpFluent()->table('fluentform_form_meta')->insertGetId($pdfData);
757 + }
758 + }
759 + return $pdfFeedMap;
760 + }
565 761
566 - if ($fields) {
567 - $forms = $this->model
568 - ->select($fields)
569 - ->orderBy('created_at', 'DESC')->get();
570 - } else {
571 - $forms = $this->model->orderBy('created_at', 'DESC')->get();
762 + /**
763 + * Map notification data with PDF feed map
764 + *
765 + * @param array $extras
766 + * @param array $pdfFeedMap
767 + *
768 + * @return array
769 + */
770 + private function notificationWithPdfMap($extras, $pdfFeedMap)
771 + {
772 + foreach ($extras['notifications'] as $key => $notification) {
773 + $notificationValue = json_decode($notification->value);
774 + $pdf_attachments = [];
775 + if (isset($notificationValue->pdf_attachments) && count($notificationValue->pdf_attachments)) {
776 + foreach ($notificationValue->pdf_attachments as $attachment) {
777 + $pdf_attachments[] = json_encode($pdfFeedMap[$attachment]);
778 + }
779 + }
780 + $notificationValue->pdf_attachments = $pdf_attachments;
781 + $notification->value = json_encode($notificationValue);
782 +
783 + $extras['notifications'][$key] = $notification;
572 784 }
785 + return $extras;
786 + }
787 +
788 + public function findFormLocations()
789 + {
790 + $formId = intval($this->request->get('form_id'));
791 +
792 + $excluded = ['attachment'];
793 + $post_types = get_post_types(['show_in_menu' => true], 'objects', 'or');
794 + $postTypes = [];
795 + foreach($post_types as $post_type) {
796 + $postTypeName = $post_type->name;
797 + if (in_array($postTypeName, $excluded)) {
798 + continue;
799 + }
800 + $postTypes[] = $postTypeName;
801 + }
802 +
803 + $params = array(
804 + 'post_type' => $postTypes,
805 + 'posts_per_page' => -1
806 + );
807 +
808 + $params = apply_filters_deprecated(
809 + 'fluentform_find_shortcode_params',
810 + [
811 + $params
812 + ],
813 + FLUENTFORM_FRAMEWORK_UPGRADE,
814 + 'fluentform/find_shortcode_params',
815 + 'Use fluentform/find_shortcode_params instead of fluentform_find_shortcode_params.'
816 + );
573 817
574 - wp_send_json($forms, 200);
818 + $params = apply_filters('fluentform/find_shortcode_params', $params);
819 +
820 + $formLocations = [];
821 + $posts = get_posts($params);
822 + foreach($posts as $post) {
823 +
824 + $formIds = self::getShortCodeIds($post->post_content);
825 + if(!empty($formIds) && in_array($formId,$formIds)) {
826 +
827 + $postType = get_post_type_object($post->post_type);
828 + $formLocations[] = [
829 + 'id' => $post->ID,
830 + 'name' => $postType->labels->singular_name,
831 + 'title' => (empty($post->post_title) ? $post->ID : $post->post_title),
832 + 'edit_link' => sprintf("%spost.php?post=%s&action=edit", admin_url(), $post->ID),
833 + ];
834 + }
835 + }
836 + $data = [
837 + 'locations' => $formLocations,
838 + 'status' => !empty($formLocations),
839 + ];
840 + wp_send_json($data, 200);
841 +
575 842 }
843 +
844 + public static function getShortCodeIds($content)
845 + {
846 + $ids = [];
847 + $tag = 'fluentform';
848 + $selector = 'id';
849 +
850 + if (function_exists('parse_blocks')) {
851 + $parsedBlocks = parse_blocks($content);
852 + foreach ($parsedBlocks as $block) {
853 + if (!ArrayHelper::exists($block, 'blockName') || ArrayHelper::exists($block, 'attrs.formId')) {
854 + continue;
855 + }
856 + $hasBlock = strpos($block['blockName'], 'fluentfom/guten-block') === 0;
857 + if ($hasBlock) {
858 + $ids[] = intval($block['attrs']['formId']);
859 + }
860 + }
861 + }
576 862
577 - private function getUnreadCount($formId)
578 - {
579 - return wpFluent()->table('fluentform_submissions')
580 - ->where('status', 'unread')
581 - ->where('form_id', $formId)
582 - ->count();
863 + $hasShortCode = has_shortcode($content, $tag);
864 + if(!$hasShortCode){
865 + return $ids;
866 + }
867 +
868 + preg_match_all('/' . get_shortcode_regex() . '/', $content, $matches, PREG_SET_ORDER);
869 + if (empty($matches)) {
870 + return $ids;
871 + }
872 +
873 +
874 + foreach ($matches as $shortcode) {
875 + if (count($shortcode) >= 2 && $tag === $shortcode[2]) {
876 + $parsedCode = str_replace(['[', ']', '[', ']'], '', $shortcode[0]);
877 +
878 + $result = shortcode_parse_atts($parsedCode);
879 +
880 + if (!empty($result[$selector])) {
881 + $ids[] = $result[$selector];
882 + }
883 + }
884 + }
885 + return $ids;
583 886 }
584 887 }