PluginProbe
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder / 6.2.2
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder v6.2.2
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
fluentform / app / Services / Form / FormService.php

FormService.php in Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder 6.2.2, at app/Services/Form/FormService.php

704 lines 27.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentForm\App\Services\Form;
4
5 use Exception;
6 use FluentForm\App\Helpers\Helper;
7 use FluentForm\App\Models\Form;
8 use FluentForm\App\Models\FormMeta;
9 use FluentForm\Framework\Foundation\App;
10 use FluentForm\Framework\Support\Arr;
11 use FluentForm\App\Modules\Form\FormFieldsParser;
12 use FluentForm\App\Services\FluentConversational\Classes\Converter\Converter;
13
14 class FormService
15 {
16 /** @var \FluentForm\Framework\Foundation\Application */
17 protected $app;
18
19 /** @var \FluentForm\App\Models\Form|\FluentForm\Framework\Database\Query\Builder */
20 protected $model;
21
22 /** @var \FluentForm\App\Services\Form\Updater */
23 protected $updater;
24
25 /** @var \FluentForm\App\Services\Form\Duplicator */
26 protected $duplicator;
27
28 /** @var \FluentForm\App\Services\Form\Fields */
29 protected $fields;
30
31
32 public function __construct()
33 {
34 $this->model = new Form();
35 $this->fields = new Fields();
36 $this->app = App::getInstance();
37 $this->updater = new Updater();
38 $this->duplicator = new Duplicator();
39 }
40
41 /**
42 * Get the paginated forms matching search criteria.
43 *
44 * @param array $attributes
45 * @return array
46 */
47 public function get($attributes = [])
48 {
49 return fluentFormApi('forms')->forms([
50 'search' => Arr::get($attributes, 'search'),
51 'status' => Arr::get($attributes, 'status'),
52 'filter_by' => Arr::get($attributes, 'filter_by', 'all'),
53 'date_range' => Arr::get($attributes, 'date_range', []),
54 'sort_column' => Arr::get($attributes, 'sort_column', 'id'),
55 'sort_by' => Arr::get($attributes, 'sort_by', 'DESC'),
56 'per_page' => Arr::get($attributes, 'per_page', 10),
57 'page' => Arr::get($attributes, 'page', 1),
58 ]);
59 }
60
61 /**
62 * Store a form with its associated meta.
63 *
64 * @param array $attributes
65 * @return \FluentForm\App\Models\Form $form
66 * @throws Exception
67 */
68 public function store($attributes = [])
69 {
70 try {
71 $predefinedForm = Form::resolvePredefinedForm($attributes);
72
73 $data = Form::prepare($predefinedForm);
74
75 $form = $this->model->create($data);
76
77 $form->title = $form->title . ' (#' . $form->id . ')';
78
79 $form->save();
80
81 $formMeta = FormMeta::prepare($attributes, $predefinedForm);
82
83 FormMeta::store($form, $formMeta);
84
85 do_action_deprecated(
86 'fluentform_inserted_new_form',
87 [
88 $form->id,
89 $data
90 ],
91 FLUENTFORM_FRAMEWORK_UPGRADE,
92 'fluentform/inserted_new_form',
93 'Use fluentform/inserted_new_form instead of fluentform_inserted_new_form.'
94 );
95
96 do_action('fluentform/inserted_new_form', $form->id, $data);
97
98 return $form;
99 } catch (Exception $e) {
100 throw new Exception(esc_html($e->getMessage()));
101 }
102 }
103
104 /**
105 * Duplicate a form with its associated meta.
106 *
107 * @param array $attributes
108 * @return \FluentForm\App\Models\Form $form
109 * @throws Exception
110 */
111 public function duplicate($attributes = [])
112 {
113 $formId = Arr::get($attributes, 'form_id');
114
115 $existingForm = $this->model->with([
116 'formMeta' => function ($formMeta) {
117 return $formMeta->whereNotIn('meta_key', ['_total_views']);
118 },
119 ])->find($formId);
120
121 if (!$existingForm) {
122 throw new Exception(
123 esc_html__("The form couldn't be found.", 'fluentform')
124 );
125 }
126
127 $data = Form::prepare($existingForm->toArray());
128
129 $form = $this->model->create($data);
130
131 // Rename the form name here
132 $form->title = $form->title . ' (#' . $form->id . ')';
133 $form->save();
134
135 $this->duplicator->duplicateFormMeta($form, $existingForm);
136 $this->duplicator->maybeDuplicateFiles($form, $existingForm, $data);
137
138 do_action_deprecated(
139 'fluentform_form_duplicated',
140 [
141 $form->id
142 ],
143 FLUENTFORM_FRAMEWORK_UPGRADE,
144 'fluentform/form_duplicated',
145 'Use fluentform/form_duplicated instead of fluentform_form_duplicated.'
146 );
147 do_action('fluentform/form_duplicated', $form->id);
148
149 return $form;
150 }
151
152 public function find($id)
153 {
154 try {
155 return $this->model->with('formMeta')->findOrFail($id);
156 } catch (Exception $e) {
157 throw new Exception(
158 esc_html__("The form couldn't be found.", 'fluentform')
159 );
160 }
161 }
162
163 public function delete($id)
164 {
165 Form::remove($id);
166 }
167
168 /**
169 * Update a form with its relevant fields.
170 *
171 * @param array $attributes
172 * @return \FluentForm\App\Models\Form $form
173 * @throws Exception
174 */
175 public function update($attributes = [])
176 {
177 return $this->updater->update($attributes);
178 }
179
180 /**
181 * Duplicate a form with its associated meta.
182 *
183 * @param int $id
184 * @return \FluentForm\App\Models\Form $form
185 * @throws Exception
186 */
187 public function convert($id)
188 {
189 try {
190 $form = Form::with('conversationalMeta')->findOrFail($id);
191 } catch (Exception $e) {
192 throw new Exception(
193 esc_html__("The form couldn't be found.", 'fluentform')
194 );
195 }
196
197 $isConversationalForm = $form->conversationalMeta && 'yes' === $form->conversationalMeta->value;
198
199 if ($isConversationalForm) {
200 $conversationalMetaValue = 'no';
201 } else {
202 $form->fill([
203 'form_fields' => Converter::convertExistingForm($form),
204 ])->save();
205
206 $conversationalMetaValue = 'yes';
207 }
208
209 FormMeta::persist($form->id, 'is_conversion_form', $conversationalMetaValue);
210
211 return $form;
212 }
213
214 public function templates()
215 {
216 $forms = [
217 'Basic' => [],
218 ];
219
220 $predefinedForms = $this->model::findPredefinedForm();
221
222 foreach ($predefinedForms as $key => $item) {
223 if (!$item['category']) {
224 $item['category'] = 'Other';
225 }
226
227 if (!isset($forms[$item['category']])) {
228 $forms[$item['category']] = [];
229 }
230
231 $itemClass = 'item_' . str_replace([' ', '&', '/'], '_', strtolower($item['category']));
232
233 if (empty($item['screenshot'])) {
234 $itemClass .= ' item_no_image';
235 } else {
236 $itemClass .= ' item_has_image';
237 }
238
239 $forms[$item['category']][$key] = [
240 'class' => $itemClass,
241 'tags' => Arr::get($item, 'tag', ''),
242 'title' => Arr::get($item, 'title', ''),
243 'brief' => Arr::get($item, 'brief', ''),
244 'category' => Arr::get($item, 'category', ''),
245 'screenshot' => Arr::get($item, 'screenshot', ''),
246 'createable' => $item['createable'] ?? false,
247 'prev_link' => $item['prev_link'] ?? false,
248 'is_pro' => $item['is_pro'] ?? false,
249 'type' => Arr::get($item, 'type', 'form'),
250 ];
251 }
252 $dropDownForms = [
253 'post' => [
254 'title' => 'Post Form',
255 ],
256 ];
257 $dropDownForms = apply_filters_deprecated(
258 'fluentform-predefined-dropDown-forms',
259 [
260 $dropDownForms
261 ],
262 FLUENTFORM_FRAMEWORK_UPGRADE,
263 'fluentform/predefined_dropdown_forms',
264 'Use fluentform/predefined_dropdown_forms instead of fluentform-predefined-dropDown-forms.'
265 );
266
267 return [
268 'forms' => $forms,
269 'categories' => array_keys($forms),
270 'predefined_dropDown_forms' => apply_filters('fluentform/predefined_dropdown_forms', $dropDownForms),
271 ];
272 }
273
274 public function components($formId)
275 {
276 /**
277 * @var \FluentForm\App\Services\FormBuilder\Components
278 */
279 $components = $this->app->make('components');
280
281 do_action_deprecated(
282 'fluent_editor_init',
283 [
284 $components
285 ],
286 FLUENTFORM_FRAMEWORK_UPGRADE,
287 'fluentform/editor_init',
288 'Use fluentform/editor_init instead of fluent_editor_init.'
289 );
290
291 $this->app->doAction('fluentform/editor_init', $components);
292
293 $editorComponents = $components->sort()->toArray();
294
295 $editorComponents = apply_filters_deprecated(
296 'fluent_editor_components',
297 [
298 $editorComponents,
299 $formId
300 ],
301 FLUENTFORM_FRAMEWORK_UPGRADE,
302 'fluentform/editor_components',
303 'Use fluentform/editor_components instead of fluent_editor_components.'
304 );
305
306 return apply_filters('fluentform/editor_components', $editorComponents, $formId);
307 }
308
309 public function getDisabledComponents()
310 {
311 $isReCaptchaDisabled = !get_option('_fluentform_reCaptcha_keys_status', false);
312 $isHCaptchaDisabled = !get_option('_fluentform_hCaptcha_keys_status', false);
313 $isTurnstileDisabled = !get_option('_fluentform_turnstile_keys_status', false);
314
315 $disabled = [
316 'recaptcha' => [
317 'disabled' => $isReCaptchaDisabled,
318 'title' => __('reCaptcha', 'fluentform'),
319 'description' => __('Please enter a valid API key on Global Settings->Security->reCaptcha', 'fluentform'),
320 'hidePro' => true,
321 ],
322 'hcaptcha' => [
323 'disabled' => $isHCaptchaDisabled,
324 'title' => __('hCaptcha', 'fluentform'),
325 'description' => __('Please enter a valid API key on Global Settings->Security->hCaptcha', 'fluentform'),
326 'hidePro' => true,
327 ],
328 'turnstile' => [
329 'disabled' => $isTurnstileDisabled,
330 'title' => __('Turnstile', 'fluentform'),
331 'description' => __('Please enter a valid API key on Global Settings->Security->Turnstile', 'fluentform'),
332 'hidePro' => true,
333 ],
334 ];
335
336 if (!Helper::hasPro()) {
337 $disabled['input_image'] = [
338 'disabled' => true,
339 'title' => __('Image Upload', 'fluentform'),
340 'description' => __('Image Upload is not available with the free version. Please upgrade to pro to get all the advanced features.',
341 'fluentform'),
342 'image' => '',
343 'video' => 'https://www.youtube.com/embed/Yb3FSoZl9Zg',
344 ];
345 $disabled['input_file'] = [
346 'disabled' => true,
347 'title' => __('File Upload', 'fluentform'),
348 'description' => __('File Upload is not available with the free version. Please upgrade to pro to get all the advanced features.',
349 'fluentform'),
350 'image' => '',
351 'video' => 'https://www.youtube.com/embed/bXbTbNPM_4k',
352 ];
353 $disabled['shortcode'] = [
354 'disabled' => true,
355 'title' => __('Shortcode', 'fluentform'),
356 'description' => __('Shortcode is not available with the free version. Please upgrade to pro to get all the advanced features.',
357 'fluentform'),
358 'image' => '',
359 'video' => 'https://www.youtube.com/embed/op3mEQxX1MM',
360 ];
361 $disabled['action_hook'] = [
362 'disabled' => true,
363 'title' => __('Action Hook', 'fluentform'),
364 'description' => __('Action Hook is not available with the free version. Please upgrade to pro to get all the advanced features.',
365 'fluentform'),
366 'image' => fluentformMix('img/pro-fields/action-hook.png'),
367 'video' => '',
368 ];
369 $disabled['form_step'] = [
370 'disabled' => true,
371 'title' => __('Form Step', 'fluentform'),
372 'description' => __('Form Step is not available with the free version. Please upgrade to pro to get all the advanced features.',
373 'fluentform'),
374 'image' => '',
375 'video' => 'https://www.youtube.com/embed/VQTWnM6BbRU',
376 ];
377 $disabled['ratings'] = [
378 'disabled' => true,
379 'title' => __('Ratings', 'fluentform'),
380 'description' => __('Ratings is not available with the free version. Please upgrade to pro to get all the advanced features.',
381 'fluentform'),
382 'image' => '',
383 'video' => 'https://www.youtube.com/embed/YGdkNspMaEs',
384 ];
385 $disabled['tabular_grid'] = [
386 'disabled' => true,
387 'title' => __('Checkable Grid', 'fluentform'),
388 'description' => __('Checkable Grid is not available with the free version. Please upgrade to pro to get all the advanced features.',
389 'fluentform'),
390 'image' => '',
391 'video' => 'https://www.youtube.com/embed/ayI3TzXXANA',
392 ];
393 $disabled['chained_select'] = [
394 'disabled' => true,
395 'title' => __('Chained Select Field', 'fluentform'),
396 'description' => __('Chained Select Field is not available with the free version. Please upgrade to pro to get all the advanced features.',
397 'fluentform'),
398 'image' => fluentformMix('img/pro-fields/chained-select-field.png'),
399 'video' => '',
400 ];
401 $disabled['phone'] = [
402 'disabled' => true,
403 'title' => 'Phone Field',
404 'description' => __('Phone Field is not available with the free version. Please upgrade to pro to get all the advanced features.',
405 'fluentform'),
406 'image' => fluentformMix('img/pro-fields/phone-field.png'),
407 'video' => '',
408 ];
409 $disabled['rich_text_input'] = [
410 'disabled' => true,
411 'title' => __('Rich Text Input', 'fluentform'),
412 'description' => __('Rich Text Input is not available with the free version. Please upgrade to pro to get all the advanced features.',
413 'fluentform'),
414 'image' => fluentformMix('img/pro-fields/rich-text-input.png'),
415 'video' => '',
416 ];
417 $disabled['save_progress_button'] = [
418 'disabled' => true,
419 'title' => __('Save & Resume', 'fluentform'),
420 'description' => __('Save & Resume is not available with the free version. Please upgrade to pro to get all the advanced features.',
421 'fluentform'),
422 'image' => fluentformMix('img/pro-fields/save-progress-button.png'),
423 'video' => '',
424 ];
425 $disabled['cpt_selection'] = [
426 'disabled' => true,
427 'title' => __('Post/CPT Selection', 'fluentform'),
428 'description' => __('Post/CPT Selection is not available with the free version. Please upgrade to pro to get all the advanced features.',
429 'fluentform'),
430 'image' => fluentformMix('img/pro-fields/post-cpt-selection.png'),
431 'video' => '',
432 ];
433 $disabled['quiz_score'] = [
434 'disabled' => true,
435 'title' => __('Quiz Score', 'fluentform'),
436 'description' => __('Quiz Score is not available with the free version. Please upgrade to pro to get all the advanced features.',
437 'fluentform'),
438 'image' => '',
439 'video' => 'https://www.youtube.com/embed/bPjDXR0y_Oo',
440 ];
441 $disabled['net_promoter_score'] = [
442 'disabled' => true,
443 'title' => __('Net Promoter Score', 'fluentform'),
444 'description' => __('Net Promoter Score is not available with the free version. Please upgrade to pro to get all the advanced features.',
445 'fluentform'),
446 'image' => fluentformMix('img/pro-fields/net-promoter-score.png'),
447 'video' => '',
448 ];
449 $disabled['dynamic_field'] = [
450 'disabled' => true,
451 'title' => __('Dynamic Field', 'fluentform'),
452 'description' => __('Dynamic Field is not available with the free version. Please upgrade to pro to get all the advanced features.', 'fluentform'),
453 'image' => '',
454 'video' => 'https://www.youtube.com/embed/cx3N5y1ddOQ',
455 ];
456 $disabled['repeater_field'] = [
457 'disabled' => true,
458 'title' => __('Repeat Field', 'fluentform'),
459 'description' => __('Repeat Field is not available with the free version. Please upgrade to pro to get all the advanced features.',
460 'fluentform'),
461 'image' => '',
462 'video' => 'https://www.youtube.com/embed/BXo9Sk-OLnQ',
463 ];
464 $disabled['rangeslider'] = [
465 'disabled' => true,
466 'title' => __('Range Slider', 'fluentform'),
467 'description' => __('Range Slider is not available with the free version. Please upgrade to pro to get all the advanced features.',
468 'fluentform'),
469 'image' => '',
470 'video' => 'https://www.youtube.com/embed/RaY2VcPWk6I',
471 ];
472 $disabled['color-picker'] = [
473 'disabled' => true,
474 'title' => __('Color Picker', 'fluentform'),
475 'description' => __('Color Picker is not available with the free version. Please upgrade to pro to get all the advanced features.',
476 'fluentform'),
477 'image' => fluentformMix('img/pro-fields/color-picker.png'),
478 'video' => '',
479 ];
480 $disabled['payment_coupon'] = [
481 'disabled' => true,
482 'title' => __('Coupon', 'fluentform'),
483 'description' => __('Coupon is not available with the free version. Please upgrade to pro to get all the advanced features.',
484 'fluentform'),
485 'image' => fluentformMix('img/pro-fields/coupon.png'),
486 'video' => '',
487 ];
488 $disabled['accordion'] = [
489 'disabled' => true,
490 'title' => __('Accordion/Tab', 'fluentform'),
491 'description' => __('Accordion/Tab is not available with the free version. Please upgrade to pro to get all the advanced features.', 'fluentform'),
492 'image' => fluentformMix('img/pro-fields/accordion-tab.png'),
493 'video' => '',
494 ];
495 }
496
497 $disabled = apply_filters_deprecated(
498 'fluentform_disabled_components',
499 [
500 $disabled
501 ],
502 FLUENTFORM_FRAMEWORK_UPGRADE,
503 'fluentform/disabled_components',
504 'Use fluentform/disabled_components instead of fluentform_disabled_components.'
505 );
506
507 return $this->app->applyFilters('fluentform/disabled_components', $disabled);
508 }
509
510 public function fields($id)
511 {
512 return $this->fields->get($id);
513 }
514
515 public function shortcodes($id)
516 {
517 return fluentFormGetAllEditorShortCodes($id);
518 }
519
520 public function pages()
521 {
522 return fluentformGetPages();
523 }
524
525 public function getInputsAndLabels($formId, $with = ['admin_label', 'raw'])
526 {
527 try {
528 $form = $this->model->findOrFail($formId);
529
530 $inputs = FormFieldsParser::getEntryInputs($form, $with);
531 $labels = FormFieldsParser::getAdminLabels($form, $inputs);
532
533 $labels = apply_filters_deprecated(
534 'fluentfoform_entry_lists_labels',
535 [
536 $labels,
537 $form
538 ],
539 FLUENTFORM_FRAMEWORK_UPGRADE,
540 'fluentform/entry_lists_labels',
541 'Use fluentform/entry_lists_labels instead of fluentfoform_entry_lists_labels.'
542 );
543 $labels = apply_filters('fluentform/entry_lists_labels', $labels, $form);
544
545 $labels = apply_filters_deprecated(
546 'fluentform_all_entry_labels',
547 [
548 $labels,
549 $formId
550 ],
551 FLUENTFORM_FRAMEWORK_UPGRADE,
552 'fluentform/all_entry_labels',
553 'Use fluentform/all_entry_labels instead of fluentform_all_entry_labels.'
554 );
555 $labels = apply_filters('fluentform/all_entry_labels', $labels, $formId);
556
557 if ($form->has_payment) {
558 $labels = apply_filters_deprecated(
559 'fluentform_all_entry_labels_with_payment',
560 [
561 $labels,
562 false,
563 $form
564 ],
565 FLUENTFORM_FRAMEWORK_UPGRADE,
566 'fluentform/all_entry_labels_with_payment',
567 'Use fluentform/all_entry_labels_with_payment instead of fluentform_all_entry_labels_with_payment.'
568 );
569
570 $labels = apply_filters('fluentform/all_entry_labels_with_payment', $labels, false, $form);
571 }
572
573 return [
574 'inputs' => $inputs,
575 'labels' => $labels,
576 ];
577 } catch (Exception $e) {
578 throw new Exception(
579 esc_html__("The form couldn't be found.", 'fluentform')
580 );
581 }
582 }
583
584 public function findShortCodePage($formId)
585 {
586 $excluded = ['attachment'];
587 $post_types = get_post_types(['show_in_menu' => true], 'objects', 'or');
588 $postTypes = [];
589 foreach ($post_types as $post_type) {
590 $postTypeName = $post_type->name;
591 if (in_array($postTypeName, $excluded)) {
592 continue;
593 }
594 $postTypes[] = $postTypeName;
595 }
596
597 global $wpdb;
598 $placeholders = implode(', ', array_fill(0, count($postTypes), '%s'));
599 $args = array_merge($postTypes, ['%fluentform%']);
600 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $placeholders is safe: generated from array_fill with %s format strings
601 $matchingIds = $wpdb->get_col($wpdb->prepare(
602 "SELECT ID FROM {$wpdb->posts} WHERE post_type IN ({$placeholders}) AND post_status != 'trash' AND post_content LIKE %s",
603 $args
604 ));
605
606 if (empty($matchingIds)) {
607 return [
608 'locations' => [],
609 'status' => false,
610 ];
611 }
612
613 $params = array(
614 'post_type' => $postTypes,
615 'posts_per_page' => -1,
616 'post__in' => $matchingIds,
617 );
618
619 $params = apply_filters_deprecated(
620 'fluentform_find_shortcode_params',
621 [
622 $params
623 ],
624 FLUENTFORM_FRAMEWORK_UPGRADE,
625 'fluentform/find_shortcode_params',
626 'Use fluentform/find_shortcode_params instead of fluentform_find_shortcode_params.'
627 );
628 $params = apply_filters('fluentform/find_shortcode_params', $params);
629
630 $formLocations = [];
631 $posts = get_posts($params);
632 foreach ($posts as $post) {
633 $formIds = self::getShortCodeId($post->post_content);
634 if (!empty($formIds) && in_array($formId, $formIds)) {
635 $postType = get_post_type_object($post->post_type);
636 $formLocations[] = [
637 'id' => $post->ID,
638 'name' => $postType->labels->singular_name,
639 'title' => (empty($post->post_title) ? $post->ID : $post->post_title),
640 'edit_link' => sprintf("%spost.php?post=%s&action=edit", admin_url(), $post->ID),
641 ];
642 }
643 }
644 return [
645 'locations' => $formLocations,
646 'status' => !empty($formLocations),
647 ];
648 }
649
650 public static function getShortCodeId($content, $shortcodeTag = 'fluentform')
651 {
652 $ids = [];
653 $selector = 'id';
654 $formId = '';
655 if (!function_exists('parse_blocks')) {
656 return $ids;
657 }
658 $parsedBlocks = parse_blocks($content);
659
660 foreach ($parsedBlocks as $block) {
661 if (!array_key_exists('blockName', $block) || !array_key_exists('attrs',
662 $block) || !array_key_exists('formId', $block['attrs'])) {
663 continue;
664 }
665 $hasBlock = strpos($block['blockName'], 'fluentfom/guten-block') === 0;
666 if (!$hasBlock) {
667 continue;
668 }
669 $ids[] = (int)$block['attrs']['formId'];
670 }
671 // Define the regex pattern with a placeholder for any number
672 $hasFormWidgets = false;
673 $pattern = '/<form data-form_id="(\d+)" id="fluentform_(\d+)" data-form_instance="ff_form_instance_(\d+)_(\d+)" method="POST" ><fieldset /';
674 // Perform the regex match
675 if (preg_match($pattern, $content, $matches)) {
676 $hasFormWidgets = isset($matches[0]);
677 $ids[] = isset($matches[1]) ? $matches[1] : '';
678 }
679
680 if (!has_shortcode($content, $shortcodeTag) && !$hasFormWidgets) {
681 return $ids;
682 }
683
684 preg_match_all('/' . get_shortcode_regex() . '/', $content, $matches, PREG_SET_ORDER);
685
686 if (empty($matches)) {
687 return $ids;
688 }
689
690 foreach ($matches as $shortcode) {
691 if (count($shortcode) >= 2 && $shortcodeTag === $shortcode[2]) {
692 $parsedCode = str_replace(['[', ']', '&#91;', '&#93;'], '', $shortcode[0]);
693
694 $result = shortcode_parse_atts($parsedCode);
695
696 if (!empty($result[$selector])) {
697 $ids[] = $result[$selector];
698 }
699 }
700 }
701 return $ids;
702 }
703 }
704