PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / trunk
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More vtrunk
6.35 6.34 6.33.1 6.33 6.32.1 6.32 6.31 6.25 6.25.1 6.26 6.26.1 6.27 6.28 6.29 6.3 6.3.1 6.3.2 6.30 6.4 6.4.1 6.4.2 6.5 6.5.1 6.5.2 6.5.3 All 141 releases
← All changes | classes/helpers/FrmXMLHelper.php +635 -284 6.25.1 → trunk View file →
@@ -9,8 +9,14 @@
9 9 * @var bool true if importing an XML from API, false if importing an XML file manually.
10 10 */
11 11 private static $installing_template = false;
12 12
13 + /**
14 + * @param array|string $opt
15 + * @param string $padding
16 + *
17 + * @return void
18 + */
13 19 public static function get_xml_values( $opt, $padding ) {
14 20 if ( is_array( $opt ) ) {
15 21 foreach ( $opt as $ok => $ov ) {
16 22 echo "\n" . esc_html( $padding );
@@ -16,8 +22,9 @@
16 22 echo "\n" . esc_html( $padding );
17 23 $tag = ( is_numeric( $ok ) ? 'key:' : '' ) . $ok;
18 24 echo '<' . esc_html( $tag ) . '>';
19 25 self::get_xml_values( $ov, $padding . ' ' );
26 +
20 27 if ( is_array( $ov ) ) {
21 28 echo "\n" . esc_html( $padding );
22 29 }
23 30 echo '</' . esc_html( $tag ) . '>';
@@ -28,8 +35,9 @@
28 35 }
29 36
30 37 /**
31 38 * @param string $file
39 + *
32 40 * @return array|WP_Error The items imported
33 41 */
34 42 public static function import_xml( $file ) {
35 43 if ( ! defined( 'WP_IMPORTING' ) ) {
@@ -38,10 +46,10 @@
38 46
39 47 if ( ! class_exists( 'DOMDocument' ) ) {
40 48 $error_message = sprintf(
41 49 /* translators: 1: Documentation link */
42 - __( 'In order to install XML, your server must have DOMDocument installed. Follow our documentation on %1$s to ensure DOMDocument is properly set up and XML support is enabled.', 'formidable' ),
43 - '<a href="https://formidableforms.com/knowledgebase/import-forms-entries-and-views/#kb-your-server-does-not-have-xml-enabled" target="_blank">Importing Forms, Entries, and Views</a>'
50 + __( 'In order to install XML, your server must have DOMDocument installed. Follow our documentation on %1$s to ensure DOMDocument is properly set up and XML support is enabled.', 'formidable' ), // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
51 + '<a href="https://formidableforms.com/knowledgebase/import-forms-entries-and-views/#kb-your-server-does-not-have-xml-enabled" target="_blank">Importing Forms, Entries, and Views</a>' // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
44 52 );
45 53
46 54 return new WP_Error( 'SimpleXML_parse_error', $error_message, libxml_get_errors() );
47 55 }
@@ -53,8 +61,9 @@
53 61
54 62 // LIBXML_COMPACT activates small nodes allocation optimization.
55 63 // Use LIBXML_PARSEHUGE to avoid "parser error : internal error: Huge input lookup" for large (300MB) files.
56 64 $success = $dom->loadXML( $xml_string, LIBXML_COMPACT | LIBXML_PARSEHUGE );
65 +
57 66 if ( ! $success ) {
58 67 return new WP_Error( 'SimpleXML_parse_error', __( 'There was an error when reading this XML file', 'formidable' ), libxml_get_errors() );
59 68 }
60 69
@@ -64,9 +73,9 @@
64 73
65 74 $xml = simplexml_import_dom( $dom );
66 75 unset( $dom );
67 76
68 - // halt if loading produces an error
77 + // Halt if loading produces an error
69 78 if ( ! $xml ) {
70 79 return new WP_Error( 'SimpleXML_parse_error', __( 'There was an error when reading this XML file', 'formidable' ), libxml_get_errors() );
71 80 }
72 81
@@ -76,12 +85,13 @@
76 85 /**
77 86 * @since 6.2.3
78 87 *
79 88 * @param string $xml_string
89 + *
80 90 * @return void
81 91 */
82 92 private static function maybe_fix_xml( &$xml_string ) {
83 - if ( '<?xml' !== substr( $xml_string, 0, 5 ) ) {
93 + if ( ! str_starts_with( $xml_string, '<?xml' ) ) {
84 94 // Some XML files have may have unexpected characters at the start.
85 95 $xml_string = substr( $xml_string, strpos( $xml_string, '<?xml' ) );
86 96 }
87 97
@@ -88,17 +98,20 @@
88 98 // The Equity theme adds a <meta name="generator" content="Equity 1.7.13" /> tag using the "the_generator" filter.
89 99 // Strip that out as it breaks the XML import.
90 100 $channel_start_position = strpos( $xml_string, '<channel>' );
91 101 $content_before_channel_tag = substr( $xml_string, 0, $channel_start_position );
92 - if ( 0 !== strpos( $content_before_channel_tag, '<meta name="generator" ' ) ) {
93 - $content_before_channel_tag = preg_replace(
94 - '/<meta\s+[^>]*name="generator"[^>]*\/>/i',
95 - '',
96 - $content_before_channel_tag,
97 - 1
98 - );
99 - $xml_string = $content_before_channel_tag . substr( $xml_string, $channel_start_position );
102 +
103 + if ( str_starts_with( $content_before_channel_tag, '<meta name="generator" ' ) ) {
104 + return;
100 105 }
106 +
107 + $content_before_channel_tag = preg_replace(
108 + '/<meta\s+[^>]*name="generator"[^>]*\/>/i',
109 + '',
110 + $content_before_channel_tag,
111 + 1
112 + );
113 + $xml_string = $content_before_channel_tag . substr( $xml_string, $channel_start_position );
101 114 }
102 115
103 116 /**
104 117 * Add terms, forms (form and field ids), posts (post ids), and entries to db, in that order
@@ -106,8 +119,9 @@
106 119 * @since 3.06
107 120 *
108 121 * @param object $xml
109 122 * @param bool $installing_template
123 + *
110 124 * @return array The number of items imported
111 125 */
112 126 public static function import_xml_now( $xml, $installing_template = false ) {
113 127 if ( ! defined( 'WP_IMPORTING' ) ) {
@@ -118,13 +132,15 @@
118 132 $imported = self::pre_import_data();
119 133
120 134 foreach ( array( 'term', 'form', 'view' ) as $item_type ) {
121 135 // Grab cats, tags, and terms, or forms or posts.
122 - if ( isset( $xml->{$item_type} ) ) {
123 - $function_name = 'import_xml_' . $item_type . 's';
124 - $imported = self::$function_name( $xml->{$item_type}, $imported );
125 - unset( $function_name, $xml->{$item_type} );
136 + if ( ! isset( $xml->{$item_type} ) ) {
137 + continue;
126 138 }
139 +
140 + $function_name = 'import_xml_' . $item_type . 's';
141 + $imported = self::$function_name( $xml->{$item_type}, $imported );
142 + unset( $function_name, $xml->{$item_type} );
127 143 }
128 144
129 145 $imported = apply_filters( 'frm_importing_xml', $imported, $xml );
130 146
@@ -139,8 +155,9 @@
139 155 }
140 156
141 157 /**
142 158 * @since 3.06
159 + *
143 160 * @return array
144 161 */
145 162 private static function pre_import_data() {
146 163 $defaults = array(
@@ -163,8 +180,9 @@
163 180
164 181 /**
165 182 * @param SimpleXMLElement $terms
166 183 * @param array $imported
184 + *
167 185 * @return array
168 186 */
169 187 public static function import_xml_terms( $terms, $imported ) {
170 188 foreach ( $terms as $t ) {
@@ -179,9 +197,9 @@
179 197 (string) $t->term_taxonomy,
180 198 array(
181 199 'slug' => (string) $t->term_slug,
182 200 'description' => (string) $t->term_description,
183 - 'parent' => empty( $parent ) ? 0 : $parent,
201 + 'parent' => $parent ? $parent : 0,
184 202 )
185 203 );
186 204
187 205 if ( $term && is_array( $term ) ) {
@@ -198,19 +216,17 @@
198 216 /**
199 217 * @since 2.0.8
200 218 *
201 219 * @param object $t
220 + *
202 221 * @return int|string
203 222 */
204 223 private static function get_term_parent_id( $t ) {
205 224 $parent = (string) $t->term_parent;
206 - if ( ! empty( $parent ) ) {
225 +
226 + if ( $parent ) {
207 227 $parent = term_exists( (string) $t->term_parent, (string) $t->term_taxonomy );
208 - if ( $parent ) {
209 - $parent = $parent['term_id'];
210 - } else {
211 - $parent = 0;
212 - }
228 + $parent = $parent ? $parent['term_id'] : 0;
213 229 }
214 230
215 231 return $parent;
216 232 }
@@ -217,8 +233,9 @@
217 233
218 234 /**
219 235 * @param SimpleXMLElement $forms
220 236 * @param array $imported
237 + *
221 238 * @return array
222 239 */
223 240 public static function import_xml_forms( $forms, $imported ) {
224 241 $child_forms = array();
@@ -230,13 +247,13 @@
230 247 $form = self::fill_form( $item );
231 248
232 249 self::update_custom_style_setting_on_import( $form );
233 250
234 - $this_form = self::maybe_get_form( $form );
235 -
251 + $this_form = self::maybe_get_form( $form );
236 252 $old_id = false;
237 253 $form_fields = false;
238 - if ( ! empty( $this_form ) ) {
254 +
255 + if ( $this_form ) {
239 256 $form_id = $this_form->id;
240 257 $old_id = $this_form->id;
241 258 self::update_form( $this_form, $form, $imported );
242 259
@@ -242,8 +259,9 @@
242 259
243 260 $form_fields = self::get_form_fields( $form_id );
244 261 } else {
245 262 $form_id = FrmForm::create( $form );
263 +
246 264 if ( $form_id ) {
247 265 if ( empty( $form['parent_form_id'] ) ) {
248 266 // Don't include the repeater form in the imported count.
249 267 ++$imported['imported']['forms'];
@@ -276,11 +294,31 @@
276 294 }//end foreach
277 295
278 296 self::maybe_update_child_form_parent_id( $imported['forms'], $child_forms );
279 297
298 + /**
299 + * Fires after all forms in the XML have been imported.
300 + *
301 + * Child forms are imported before their parent form, so per-form fix-ups
302 + * cannot resolve conditional logic that references fields in a form
303 + * imported later. Use this action for cross-form fix-ups that require
304 + * the fully populated `$frm_duplicate_ids` map.
305 + *
306 + * @since 6.31
307 + *
308 + * @param array $imported Summary of imported items, including
309 + * 'forms' => array( old_form_id => new_form_id ).
310 + */
311 + do_action( 'frm_after_import_forms', $imported );
312 +
280 313 return $imported;
281 314 }
282 315
316 + /**
317 + * @param object $item
318 + *
319 + * @return array
320 + */
283 321 private static function fill_form( $item ) {
284 322 $form = array(
285 323 'id' => (int) $item->id,
286 324 'form_key' => (string) $item->form_key,
@@ -308,21 +346,27 @@
308 346
309 347 return $form;
310 348 }
311 349
350 + /**
351 + * @param array $form
352 + *
353 + * @return false|object
354 + */
312 355 private static function maybe_get_form( $form ) {
313 - // if template, allow to edit if form keys match, otherwise, creation date must also match
356 + // If template, allow to edit if form keys match, otherwise, creation date must also match
314 357 $edit_query = array(
315 358 'form_key' => $form['form_key'],
316 359 'is_template' => $form['is_template'],
317 360 );
361 +
318 362 if ( ! $form['is_template'] ) {
319 363 $edit_query['created_at'] = $form['created_at'];
320 364 }
321 365
322 366 $edit_query = apply_filters( 'frm_match_xml_form', $edit_query, $form );
367 + $form = FrmForm::getAll( $edit_query, '', 1 );
323 368
324 - $form = FrmForm::getAll( $edit_query, '', 1 );
325 369 if ( is_object( $form ) && $form->status === 'trash' ) {
326 370 FrmForm::destroy( $form->id );
327 371 return false;
328 372 }
@@ -329,11 +373,19 @@
329 373
330 374 return $form;
331 375 }
332 376
377 + /**
378 + * @param object $this_form
379 + * @param array $form
380 + * @param array $imported
381 + *
382 + * @return void
383 + */
333 384 private static function update_form( $this_form, $form, &$imported ) {
334 385 $form_id = $this_form->id;
335 386 FrmForm::update( $form_id, $form );
387 +
336 388 if ( empty( $form['parent_form_id'] ) ) {
337 389 // Don't include the repeater form in the updated count.
338 390 ++$imported['updated']['forms'];
339 391 }
@@ -341,32 +393,43 @@
341 393 // Keep track of whether this specific form was updated or not
342 394 $imported['form_status'][ $form_id ] = 'updated';
343 395 }
344 396
397 + /**
398 + * @param int|string $form_id
399 + *
400 + * @return array
401 + */
345 402 private static function get_form_fields( $form_id ) {
346 403 $form_fields = FrmField::get_all_for_form( $form_id, '', 'exclude', 'exclude' );
347 404 $old_fields = array();
405 +
348 406 foreach ( $form_fields as $f ) {
349 407 $old_fields[ $f->id ] = $f;
350 408 $old_fields[ $f->field_key ] = $f->id;
351 409 unset( $f );
352 410 }
353 - $form_fields = $old_fields;
354 411
355 - return $form_fields;
412 + return $old_fields;
356 413 }
357 414
358 415 /**
359 416 * Delete any fields attached to this form that were not included in the template
417 + *
418 + * @param array $form_fields
419 + *
420 + * @return void
360 421 */
361 422 private static function delete_removed_fields( $form_fields ) {
362 - if ( ! empty( $form_fields ) ) {
363 - foreach ( $form_fields as $field ) {
364 - if ( is_object( $field ) ) {
365 - FrmField::destroy( $field->id );
366 - }
367 - unset( $field );
423 + if ( ! $form_fields ) {
424 + return;
425 + }
426 +
427 + foreach ( $form_fields as $field ) {
428 + if ( is_object( $field ) ) {
429 + FrmField::destroy( $field->id );
368 430 }
431 + unset( $field );
369 432 }
370 433 }
371 434
372 435 /**
@@ -418,14 +481,16 @@
418 481 * @param array $child_forms
419 482 */
420 483 private static function maybe_update_child_form_parent_id( $imported_forms, $child_forms ) {
421 484 foreach ( $child_forms as $child_form_id => $old_parent_form_id ) {
422 - if ( isset( $imported_forms[ $old_parent_form_id ] ) && (int) $imported_forms[ $old_parent_form_id ] !== (int) $old_parent_form_id ) {
423 - // Update all children with this old parent_form_id
424 - $new_parent_form_id = (int) $imported_forms[ $old_parent_form_id ];
425 - FrmForm::update( $child_form_id, array( 'parent_form_id' => $new_parent_form_id ) );
426 - do_action( 'frm_update_child_form_parent_id', $child_form_id, $new_parent_form_id );
485 + if ( ! isset( $imported_forms[ $old_parent_form_id ] ) || (int) $imported_forms[ $old_parent_form_id ] === (int) $old_parent_form_id ) {
486 + continue;
427 487 }
488 +
489 + // Update all children with this old parent_form_id
490 + $new_parent_form_id = (int) $imported_forms[ $old_parent_form_id ];
491 + FrmForm::update( $child_form_id, array( 'parent_form_id' => $new_parent_form_id ) );
492 + do_action( 'frm_update_child_form_parent_id', $child_form_id, $new_parent_form_id );
428 493 }
429 494 }
430 495
431 496 /**
@@ -433,8 +498,14 @@
433 498 *
434 499 * @since 2.0.13
435 500 *
436 501 * TODO: Cut down on params
502 + *
503 + * @param SimpleXMLElement $xml_fields
504 + * @param int|string $form_id
505 + * @param object $this_form
506 + * @param array $form_fields
507 + * @param array $imported
437 508 */
438 509 private static function import_xml_fields( $xml_fields, $form_id, $this_form, &$form_fields, &$imported ) {
439 510 $in_section = 0;
440 511 $keys_by_original_field_id = array();
@@ -448,10 +519,10 @@
448 519 self::maybe_update_form_select( $f, $imported );
449 520 self::maybe_update_get_values_form_setting( $imported, $f );
450 521 self::migrate_placeholders( $f );
451 522
452 - if ( ! empty( $this_form ) ) {
453 - // check for field to edit by field id
523 + if ( $this_form ) {
524 + // Check for field to edit by field id
454 525 if ( isset( $form_fields[ $f['id'] ] ) ) {
455 526 FrmField::update( $f['id'], $f );
456 527 ++$imported['updated']['fields'];
457 528
@@ -462,12 +533,11 @@
462 533 unset( $form_fields[ $f['field_key'] ] );
463 534 }
464 535 } elseif ( isset( $form_fields[ $f['field_key'] ] ) ) {
465 536 $keys_by_original_field_id[ $f['id'] ] = $f['field_key'];
537 + $old_field_id = $f['id'];
466 538
467 - $old_field_id = $f['id'];
468 -
469 - // check for field to edit by field key
539 + // Check for field to edit by field key
470 540 unset( $f['id'] );
471 541
472 542 FrmField::update( $form_fields[ $f['field_key'] ], $f );
473 543 ++$imported['updated']['fields'];
@@ -483,9 +553,8 @@
483 553 // If no matching field id or key in this form, create the field.
484 554 self::create_imported_field( $f, $imported );
485 555 }//end if
486 556 } else {
487 -
488 557 self::create_imported_field( $f, $imported );
489 558 }//end if
490 559 }//end foreach
491 560
@@ -497,8 +566,9 @@
497 566 /**
498 567 * @since 6.8.4
499 568 *
500 569 * @param array $field_array
570 + *
501 571 * @return array
502 572 */
503 573 private static function update_field_options_with_defaults( $field_array ) {
504 574 $defaults = self::default_field_options( $field_array['type'] );
@@ -531,8 +601,14 @@
531 601 */
532 602 do_action( 'frm_after_existing_field_is_imported', $field_array, $form_fields[ $field_array['field_key'] ], $old_field_id );
533 603 }
534 604
605 + /**
606 + * @param object $field
607 + * @param int|string $form_id
608 + *
609 + * @return array
610 + */
535 611 private static function fill_field( $field, $form_id ) {
536 612 return array(
537 613 'id' => (int) $field->id,
538 614 'field_key' => (string) $field->field_key,
@@ -543,14 +619,45 @@
543 619 'field_order' => (int) $field->field_order,
544 620 'form_id' => (int) $form_id,
545 621 'required' => (int) $field->required,
546 622 'options' => FrmAppHelper::maybe_json_decode( (string) $field->options ),
547 - 'field_options' => FrmAppHelper::maybe_json_decode( (string) $field->field_options ),
623 + 'field_options' => self::fill_field_options( $field ),
548 624 );
549 625 }
550 626
551 627 /**
628 + * Reads a field's options out of the file as an array.
629 + *
630 + * Field options are a settings map, and every step of the import reads them
631 + * as one. A file whose value there cannot be read, because it is empty or
632 + * was written by something other than an export, used to end the whole
633 + * import with a fatal error on the first field it reached. An empty set of
634 + * options is recoverable, since the defaults for the field type fill the
635 + * gaps, so prefer that over stopping.
636 + *
637 + * Unserialize is tried as well as JSON so options written by an older
638 + * version are still read rather than thrown away.
639 + *
640 + * @since 6.35
641 + *
642 + * @param object $field Field element from the file.
643 + *
644 + * @return array
645 + */
646 + private static function fill_field_options( $field ) {
647 + $options = (string) $field->field_options;
648 +
649 + FrmAppHelper::unserialize_or_decode( $options );
650 +
651 + return is_array( $options ) ? $options : array();
652 + }
653 +
654 + /**
552 655 * @since 4.06
656 + *
657 + * @param array $f
658 + *
659 + * @return void
553 660 */
554 661 private static function set_default_value( &$f ) {
555 662 $has_default = array(
556 663 'text',
@@ -564,15 +671,17 @@
564 671 'password',
565 672 'tag',
566 673 );
567 674
568 - if ( is_array( $f['default_value'] ) && in_array( $f['type'], $has_default, true ) ) {
569 - if ( count( $f['default_value'] ) === 1 ) {
570 - $f['default_value'] = '[' . reset( $f['default_value'] ) . ']';
571 - } else {
572 - $f['default_value'] = reset( $f['default_value'] );
573 - }
675 + if ( ! is_array( $f['default_value'] ) || ! in_array( $f['type'], $has_default, true ) ) {
676 + return;
574 677 }
678 +
679 + if ( count( $f['default_value'] ) === 1 ) {
680 + $f['default_value'] = '[' . reset( $f['default_value'] ) . ']';
681 + } else {
682 + $f['default_value'] = reset( $f['default_value'] );
683 + }
575 684 }
576 685
577 686 /**
578 687 * Make sure the required indicator is set.
@@ -577,8 +686,12 @@
577 686 /**
578 687 * Make sure the required indicator is set.
579 688 *
580 689 * @since 4.05
690 + *
691 + * @param array $f
692 + *
693 + * @return void
581 694 */
582 695 private static function maybe_add_required( &$f ) {
583 696 if ( $f['required'] && ! isset( $f['field_options']['required_indicator'] ) ) {
584 697 $f['field_options']['required_indicator'] = '*';
@@ -588,14 +701,17 @@
588 701 /**
589 702 * Update the current in_section value at the beginning of the field loop
590 703 *
591 704 * @since 2.0.25
705 + *
592 706 * @param int $in_section
593 707 * @param array $f
708 + *
709 + * @return void
594 710 */
595 711 private static function maybe_update_in_section_variable( &$in_section, &$f ) {
596 712 // If we're at the end of a section, switch $in_section is 0
597 - if ( in_array( $f['type'], array( 'end_divider', 'break', 'form' ) ) ) {
713 + if ( in_array( $f['type'], array( 'end_divider', 'break', 'form' ), true ) ) {
598 714 $in_section = 0;
599 715 }
600 716
601 717 // Update the current field's in_section value
@@ -621,16 +737,21 @@
621 737 if ( ! isset( $imported['forms'] ) ) {
622 738 return;
623 739 }
624 740
625 - if ( $f['type'] === 'form' || ( $f['type'] === 'divider' && FrmField::is_option_true( $f['field_options'], 'repeat' ) ) ) {
626 - if ( FrmField::is_option_true( $f['field_options'], 'form_select' ) ) {
627 - $form_select = (int) $f['field_options']['form_select'];
628 - if ( isset( $imported['forms'][ $form_select ] ) ) {
629 - $f['field_options']['form_select'] = $imported['forms'][ $form_select ];
630 - }
631 - }
741 + if ( $f['type'] !== 'form' && ( $f['type'] !== 'divider' || ! FrmField::is_option_true( $f['field_options'], 'repeat' ) ) ) {
742 + return;
632 743 }
744 +
745 + if ( ! FrmField::is_option_true( $f['field_options'], 'form_select' ) ) {
746 + return;
747 + }
748 +
749 + $form_select = (int) $f['field_options']['form_select'];
750 +
751 + if ( isset( $imported['forms'][ $form_select ] ) ) {
752 + $f['field_options']['form_select'] = $imported['forms'][ $form_select ];
753 + }
633 754 }
634 755
635 756 /**
636 757 * Update the get_values_form setting if the form was imported
@@ -638,8 +759,10 @@
638 759 * @since 2.01.0
639 760 *
640 761 * @param array $imported
641 762 * @param array $f
763 + *
764 + * @return void
642 765 */
643 766 private static function maybe_update_get_values_form_setting( $imported, &$f ) {
644 767 if ( ! isset( $imported['forms'] ) ) {
645 768 return;
@@ -644,36 +767,35 @@
644 767 if ( ! isset( $imported['forms'] ) ) {
645 768 return;
646 769 }
647 770
648 - if ( FrmField::is_option_true_in_array( $f['field_options'], 'get_values_form' ) ) {
649 - $old_form = $f['field_options']['get_values_form'];
650 - if ( isset( $imported['forms'][ $old_form ] ) ) {
651 - $f['field_options']['get_values_form'] = $imported['forms'][ $old_form ];
652 - }
771 + if ( ! FrmField::is_option_true_in_array( $f['field_options'], 'get_values_form' ) ) {
772 + return;
653 773 }
654 - }
655 774
656 - /**
657 - * If field settings have been migrated, update the values during import.
658 - *
659 - * @since 4.0
660 - */
661 - private static function run_field_migrations( &$f ) {
662 - self::migrate_placeholders( $f );
663 - $f = apply_filters( 'frm_import_xml_field', $f );
775 + $old_form = $f['field_options']['get_values_form'];
776 +
777 + if ( isset( $imported['forms'][ $old_form ] ) ) {
778 + $f['field_options']['get_values_form'] = $imported['forms'][ $old_form ];
779 + }
664 780 }
665 781
666 782 /**
667 783 * @since 4.0
784 + *
785 + * @param array $f
786 + *
787 + * @return void
668 788 */
669 789 private static function migrate_placeholders( &$f ) {
670 790 $update_values = self::migrate_field_placeholder( $f, 'clear_on_focus' );
791 +
671 792 foreach ( $update_values as $k => $v ) {
672 793 $f[ $k ] = $v;
673 794 }
674 795
675 796 $update_values = self::migrate_field_placeholder( $f, 'default_blank' );
797 +
676 798 foreach ( $update_values as $k => $v ) {
677 799 $f[ $k ] = $v;
678 800 }
679 801 }
@@ -682,13 +804,18 @@
682 804 * Move clear_on_focus or default_blank to placeholder.
683 805 * Also called during database migration in FrmMigrate.
684 806 *
685 807 * @since 4.0
808 + *
809 + * @param array|object $field
810 + * @param string $type
811 + *
686 812 * @return array
687 813 */
688 814 public static function migrate_field_placeholder( $field, $type ) {
689 815 $field = (array) $field;
690 816 $field_options = $field['field_options'];
817 +
691 818 if ( empty( $field_options[ $type ] ) || empty( $field['default_value'] ) ) {
692 819 return array();
693 820 }
694 821
@@ -701,27 +828,34 @@
701 828 );
702 829
703 830 // If a dropdown placeholder was used, remove the option so it won't be included twice.
704 831 $options = $field['options'];
705 - if ( $type === 'default_blank' && is_array( $options ) ) {
706 - $default_value = $field['default_value'];
707 - if ( is_array( $default_value ) ) {
708 - $default_value = reset( $default_value );
832 +
833 + if ( $type !== 'default_blank' || ! is_array( $options ) ) {
834 + return $changes;
835 + }
836 +
837 + $default_value = $field['default_value'];
838 +
839 + if ( is_array( $default_value ) ) {
840 + $default_value = reset( $default_value );
841 + }
842 +
843 + foreach ( $options as $opt_key => $opt ) {
844 + if ( is_array( $opt ) ) {
845 + $opt = $opt['value'] ?? $opt['label'] ?? reset( $opt );
709 846 }
710 847
711 - foreach ( $options as $opt_key => $opt ) {
712 - if ( is_array( $opt ) ) {
713 - $opt = $opt['value'] ?? $opt['label'] ?? reset( $opt );
714 - }
715 -
716 - if ( $opt == $default_value ) {
717 - unset( $options[ $opt_key ] );
718 - break;
719 - }
848 + // phpcs:ignore Universal.Operators.StrictComparisons
849 + if ( $opt == $default_value ) {
850 + unset( $options[ $opt_key ] );
851 + break;
720 852 }
721 - $changes['options'] = $options;
722 853 }
723 854
855 + $changes['options'] = $options;
856 + // end if
857 +
724 858 return $changes;
725 859 }
726 860
727 861 /**
@@ -730,8 +864,10 @@
730 864 * @since 2.0.25
731 865 *
732 866 * @param array $f
733 867 * @param array $imported
868 + *
869 + * @return void
734 870 */
735 871 private static function create_imported_field( $f, &$imported ) {
736 872 $f = self::update_field_options_with_defaults( $f );
737 873
@@ -739,12 +875,15 @@
739 875 $f = self::maybe_import_images_for_options( $f );
740 876 }
741 877
742 878 $new_id = FrmField::create( $f );
743 - if ( $new_id != false ) {
744 - ++$imported['imported']['fields'];
745 - do_action( 'frm_after_field_is_imported', $f, $new_id );
879 +
880 + if ( ! $new_id ) {
881 + return;
746 882 }
883 +
884 + ++$imported['imported']['fields'];
885 + do_action( 'frm_after_field_is_imported', $f, $new_id );
747 886 }
748 887
749 888 /**
750 889 * Import images for radio buttons and checkboxes from image src if available.
@@ -751,8 +890,9 @@
751 890 *
752 891 * @since 5.5.1
753 892 *
754 893 * @param array $field
894 + *
755 895 * @return array
756 896 */
757 897 private static function maybe_import_images_for_options( $field ) {
758 898 if ( empty( $field['options'] ) || ! is_array( $field['options'] ) ) {
@@ -783,10 +923,13 @@
783 923 /**
784 924 * Fix field ids for fields that already exist prior to import.
785 925 *
786 926 * @since 4.07
927 + *
787 928 * @param int $form_id
788 929 * @param array $keys_by_original_field_id
930 + *
931 + * @return void
789 932 */
790 933 protected static function maybe_update_field_ids( $form_id, $keys_by_original_field_id ) {
791 934 global $frm_duplicate_ids;
792 935
@@ -806,15 +949,17 @@
806 949 $field = (array) $field;
807 950 $frm_duplicate_ids = $keys_by_original_field_id;
808 951 $after = FrmFieldsHelper::switch_field_ids( $field );
809 952
953 + if ( $before['field_options'] === $after['field_options'] ) {
954 + continue;
955 + }
956 +
957 + $frm_duplicate_ids = $field_id_by_key;
958 + $after = FrmFieldsHelper::switch_field_ids( $after );
959 +
810 960 if ( $before['field_options'] !== $after['field_options'] ) {
811 - $frm_duplicate_ids = $field_id_by_key;
812 - $after = FrmFieldsHelper::switch_field_ids( $after );
813 -
814 - if ( $before['field_options'] !== $after['field_options'] ) {
815 - FrmField::update( $field['id'], array( 'field_options' => $after['field_options'] ) );
816 - }
961 + FrmField::update( $field['id'], array( 'field_options' => $after['field_options'] ) );
817 962 }
818 963 }
819 964
820 965 $frm_duplicate_ids = $former_duplicate_ids;
@@ -826,8 +971,10 @@
826 971 *
827 972 * @since 2.0.19
828 973 *
829 974 * @param array $form
975 + *
976 + * @return void
830 977 */
831 978 private static function update_custom_style_setting_on_import( &$form ) {
832 979 if ( ! isset( $form['options']['custom_style'] ) ) {
833 980 return;
@@ -835,29 +982,32 @@
835 982
836 983 if ( is_numeric( $form['options']['custom_style'] ) && 1 === intval( $form['options']['custom_style'] ) ) {
837 984 // Set to default
838 985 $form['options']['custom_style'] = 1;
839 - } else {
840 - // Replace the style name with the style ID on import
841 - global $wpdb;
842 - $table = $wpdb->prefix . 'posts';
843 - $where = array(
844 - 'post_name' => $form['options']['custom_style'],
845 - 'post_type' => 'frm_styles',
846 - );
847 - $select = 'ID';
848 - $style_id = FrmDb::get_var( $table, $where, $select );
849 986
850 - if ( $style_id ) {
851 - $form['options']['custom_style'] = $style_id;
852 - } else {
853 - // save the old style to maybe update after styles import
854 - $form['options']['old_style'] = $form['options']['custom_style'];
987 + return;
988 + }
855 989
856 - // Set to default
857 - $form['options']['custom_style'] = 1;
858 - }
859 - }//end if
990 + // Replace the style name with the style ID on import
991 + global $wpdb;
992 + $table = $wpdb->prefix . 'posts';
993 + $where = array(
994 + 'post_name' => $form['options']['custom_style'],
995 + 'post_type' => 'frm_styles',
996 + );
997 + $select = 'ID';
998 + $style_id = FrmDb::get_var( $table, $where, $select );
999 +
1000 + if ( $style_id ) {
1001 + $form['options']['custom_style'] = $style_id;
1002 + return;
1003 + }
1004 +
1005 + // Save the old style to maybe update after styles import
1006 + $form['options']['old_style'] = $form['options']['custom_style'];
1007 +
1008 + // Set to default
1009 + $form['options']['custom_style'] = 1;
860 1010 }
861 1011
862 1012 /**
863 1013 * After styles are imported, check for any forms that were linked
@@ -863,22 +1013,29 @@
863 1013 * After styles are imported, check for any forms that were linked
864 1014 * and link them back up.
865 1015 *
866 1016 * @since 2.2.7
1017 + *
1018 + * @param int|string $form_id
1019 + *
1020 + * @return void
867 1021 */
868 1022 private static function update_custom_style_setting_after_import( $form_id ) {
869 1023 $form = FrmForm::getOne( $form_id );
870 1024
871 - if ( $form && isset( $form->options['old_style'] ) ) {
872 - $form = (array) $form;
873 - $saved_style = $form['options']['custom_style'];
874 - $form['options']['custom_style'] = $form['options']['old_style'];
875 - self::update_custom_style_setting_on_import( $form );
876 - $has_changed = ( $form['options']['custom_style'] != $saved_style && $form['options']['custom_style'] != $form['options']['old_style'] );
877 - if ( $has_changed ) {
878 - FrmForm::update( $form['id'], $form );
879 - }
1025 + if ( ! $form || ! isset( $form->options['old_style'] ) ) {
1026 + return;
880 1027 }
1028 +
1029 + $form = (array) $form;
1030 + $saved_style = $form['options']['custom_style'];
1031 + $form['options']['custom_style'] = $form['options']['old_style'];
1032 + self::update_custom_style_setting_on_import( $form );
1033 + $has_changed = $form['options']['custom_style'] != $saved_style && $form['options']['custom_style'] != $form['options']['old_style']; // phpcs:ignore Universal.Operators.StrictComparisons, SlevomatCodingStandard.Files.LineLength.LineTooLong
1034 +
1035 + if ( $has_changed ) {
1036 + FrmForm::update( $form['id'], $form );
1037 + }
881 1038 }
882 1039
883 1040 /**
884 1041 * Handle import for all posts. This includes views, styles, pages, and form actions.
@@ -884,11 +1041,12 @@
884 1041 * Handle import for all posts. This includes views, styles, pages, and form actions.
885 1042 *
886 1043 * @param SimpleXMLElement $views
887 1044 * @param array $imported
1045 + *
888 1046 * @return array
889 1047 */
890 - public static function import_xml_views( $views, $imported ) {
1048 + public static function import_xml_views( $views, $imported ) { // phpcs:ignore SlevomatCodingStandard.Complexity.Cognitive.ComplexityTooHigh
891 1049 $imported['posts'] = array();
892 1050 $form_action_type = FrmFormActionsController::$action_post_type;
893 1051
894 1052 $post_types = array(
@@ -936,10 +1094,12 @@
936 1094
937 1095 unset( $item );
938 1096
939 1097 $post_id = false;
1098 +
940 1099 if ( $post['post_type'] === $form_action_type ) {
941 1100 $action_control = FrmFormActionsController::get_form_actions( $post['post_excerpt'] );
1101 +
942 1102 if ( $action_control && is_object( $action_control ) && isset( $imported['form_status'] ) ) {
943 1103 $post_id = $action_control->maybe_create_action( $post, $imported['form_status'] );
944 1104 }
945 1105 unset( $action_control );
@@ -965,9 +1125,9 @@
965 1125 if ( ! is_numeric( $post_id ) ) {
966 1126 continue;
967 1127 }
968 1128
969 - if ( false !== strpos( $post['post_content'], '[display-frm-data' ) || false !== strpos( $post['post_content'], '[formidable' ) ) {
1129 + if ( str_contains( $post['post_content'], '[display-frm-data' ) || str_contains( $post['post_content'], '[formidable' ) ) {
970 1130 $posts_with_shortcodes[ $post_id ] = $post;
971 1131 }
972 1132
973 1133 self::update_postmeta( $post, $post_id );
@@ -973,13 +1133,14 @@
973 1133 self::update_postmeta( $post, $post_id );
974 1134 self::update_layout( $post, $post_id );
975 1135
976 1136 $this_type = 'posts';
1137 +
977 1138 if ( isset( $post_types[ $post['post_type'] ] ) ) {
978 1139 $this_type = $post_types[ $post['post_type'] ];
979 1140 }
980 1141
981 - if ( isset( $post['ID'] ) && $post_id == $post['ID'] ) {
1142 + if ( isset( $post['ID'] ) && (int) $post_id === (int) $post['ID'] ) {
982 1143 ++$imported['updated'][ $this_type ];
983 1144 } else {
984 1145 ++$imported['imported'][ $this_type ];
985 1146 }
@@ -1000,9 +1161,9 @@
1000 1161 }
1001 1162 unset( $posts_with_shortcodes, $view_ids );
1002 1163
1003 1164 if ( ! empty( $imported['forms'] ) ) {
1004 - // clear imported forms style cache to make sure the new styles are applied to the forms
1165 + // Clear imported forms style cache to make sure the new styles are applied to the forms
1005 1166 self::clear_forms_style_caches( $imported['forms'] );
1006 1167 }
1007 1168
1008 1169 self::maybe_update_stylesheet( $imported );
@@ -1015,8 +1176,10 @@
1015 1176 /**
1016 1177 * Clears styles from cache for imported forms
1017 1178 *
1018 1179 * @param array $imported_forms
1180 + *
1181 + * @return void
1019 1182 */
1020 1183 private static function clear_forms_style_caches( $imported_forms ) {
1021 1184 $where = array(
1022 1185 'id' => $imported_forms,
@@ -1025,18 +1188,19 @@
1025 1188 $forms = FrmDb::get_results( 'frm_forms', $where );
1026 1189
1027 1190 foreach ( $forms as $form ) {
1028 1191 FrmAppHelper::unserialize_or_decode( $form->options );
1192 +
1029 1193 if ( ! $form->options ) {
1030 1194 continue;
1031 1195 }
1196 +
1032 1197 $where = array(
1033 1198 'post_name' => $form->options['old_style'],
1034 1199 'post_type' => FrmStylesController::$post_type,
1035 1200 );
1036 1201
1037 - $select = 'ID';
1038 -
1202 + $select = 'ID';
1039 1203 $cache_key = FrmDb::generate_cache_key( $where, array( 'limit' => 1 ), $select, 'var' );
1040 1204 FrmDb::delete_cache_and_transient( $cache_key, 'post' );
1041 1205 }
1042 1206 }
@@ -1045,12 +1209,13 @@
1045 1209 * Replace old form ids with new ones in a string.
1046 1210 *
1047 1211 * @param string $string
1048 1212 * @param array<int> $form_ids new form ids indexed by old form id.
1213 + *
1049 1214 * @return string
1050 1215 */
1051 1216 private static function switch_form_ids( $string, $form_ids ) {
1052 - if ( false === strpos( $string, '[formidable' ) ) {
1217 + if ( ! str_contains( $string, '[formidable' ) ) {
1053 1218 // Skip string replacing if there are no form shortcodes in string.
1054 1219 return $string;
1055 1220 }
1056 1221
@@ -1077,13 +1242,15 @@
1077 1242
1078 1243 /**
1079 1244 * @param array<array> $posts_with_shortcodes indexed by current post id.
1080 1245 * @param array<int> $view_ids new view ids indexed by old view id.
1246 + *
1081 1247 * @return void
1082 1248 */
1083 1249 private static function maybe_switch_view_ids_after_importing_posts( $posts_with_shortcodes, $view_ids ) {
1084 1250 foreach ( $posts_with_shortcodes as $imported_post_id => $post ) {
1085 1251 $post_content = self::switch_view_ids( $post['post_content'], $view_ids );
1252 +
1086 1253 if ( $post_content === $post['post_content'] ) {
1087 1254 continue;
1088 1255 }
1089 1256
@@ -1100,12 +1267,13 @@
1100 1267 * Replace old view ids with new ones in a string.
1101 1268 *
1102 1269 * @param string $string
1103 1270 * @param array<int> $view_ids new view ids indexed by old view id.
1271 + *
1104 1272 * @return string
1105 1273 */
1106 1274 private static function switch_view_ids( $string, $view_ids ) {
1107 - if ( false === strpos( $string, '[display-frm-data' ) ) {
1275 + if ( ! str_contains( $string, '[display-frm-data' ) ) {
1108 1276 // Skip string replacing if there are no view shortcodes in string.
1109 1277 return $string;
1110 1278 }
1111 1279
@@ -1132,30 +1300,40 @@
1132 1300 }
1133 1301
1134 1302 /**
1135 1303 * @param string $content
1304 + *
1136 1305 * @return string
1137 1306 */
1138 1307 private static function maybe_prepare_json_view_content( $content ) {
1139 1308 $maybe_decoded = FrmAppHelper::maybe_json_decode( $content );
1309 +
1140 1310 if ( is_array( $maybe_decoded ) && isset( $maybe_decoded[0] ) && isset( $maybe_decoded[0]['box'] ) ) {
1141 1311 return FrmAppHelper::prepare_and_encode( $maybe_decoded );
1142 1312 }
1313 +
1143 1314 return $content;
1144 1315 }
1145 1316
1317 + /**
1318 + * @param array $post
1319 + * @param object $item
1320 + * @param array $imported
1321 + *
1322 + * @return void
1323 + */
1146 1324 private static function populate_post( &$post, $item, $imported ) {
1147 1325 if ( isset( $item->attachment_url ) ) {
1148 1326 $post['attachment_url'] = (string) $item->attachment_url;
1149 1327 }
1150 1328
1151 - if ( $post['post_type'] == FrmFormActionsController::$action_post_type && isset( $imported['forms'][ (int) $post['menu_order'] ] ) ) {
1152 - // update to new form id
1329 + if ( $post['post_type'] === FrmFormActionsController::$action_post_type && isset( $imported['forms'][ (int) $post['menu_order'] ] ) ) {
1330 + // Update to new form id
1153 1331 $post['menu_order'] = $imported['forms'][ (int) $post['menu_order'] ];
1154 1332 }
1155 1333
1156 1334 // Don't allow default styles to take over a site's default style
1157 - if ( 'frm_styles' == $post['post_type'] ) {
1335 + if ( 'frm_styles' === $post['post_type'] ) {
1158 1336 $post['menu_order'] = 0;
1159 1337 }
1160 1338
1161 1339 foreach ( $item->postmeta as $meta ) {
@@ -1177,9 +1355,9 @@
1177 1355 * @param array $post
1178 1356 * @param stdClass $meta
1179 1357 * @param array $imported
1180 1358 */
1181 - private static function populate_postmeta( &$post, $meta, $imported ) {
1359 + private static function populate_postmeta( &$post, $meta, $imported ) { // phpcs:ignore SlevomatCodingStandard.Complexity.Cognitive.ComplexityTooHigh, Generic.Metrics.CyclomaticComplexity.MaxExceeded, SlevomatCodingStandard.Files.LineLength.LineTooLong
1182 1360 global $frm_duplicate_ids;
1183 1361
1184 1362 $m = array(
1185 1363 'key' => (string) $meta->meta_key,
@@ -1191,14 +1369,13 @@
1191 1369 $m['value'] = $imported['forms'][ (int) $m['value'] ];
1192 1370 } else {
1193 1371 $m['value'] = FrmAppHelper::maybe_json_decode( $m['value'] );
1194 1372
1195 - if ( ! empty( $frm_duplicate_ids ) ) {
1373 + if ( $frm_duplicate_ids ) {
1196 1374 if ( 'frm_dyncontent' === $m['key'] ) {
1197 1375 $m['value'] = self::maybe_prepare_json_view_content( $m['value'] );
1198 1376 $m['value'] = FrmFieldsHelper::switch_field_ids( $m['value'] );
1199 1377 } elseif ( 'frm_options' === $m['key'] ) {
1200 -
1201 1378 foreach ( array( 'date_field_id', 'edate_field_id' ) as $setting_name ) {
1202 1379 if ( isset( $m['value'][ $setting_name ] ) && is_numeric( $m['value'][ $setting_name ] ) && isset( $frm_duplicate_ids[ $m['value'][ $setting_name ] ] ) ) {
1203 1380 $m['value'][ $setting_name ] = $frm_duplicate_ids[ $m['value'][ $setting_name ] ];
1204 1381 }
@@ -1222,8 +1399,9 @@
1222 1399
1223 1400 if ( ! empty( $m['value']['timeline_options'] ) ) {
1224 1401 foreach ( $m['value']['timeline_options'] as $timeline_option_group_key => $timeline_group_option ) {
1225 1402 foreach ( $timeline_group_option as $timeline_option_key => $timeline_option ) {
1403 + // @mago-expect lint:excessive-nesting
1226 1404 if ( isset( $frm_duplicate_ids[ $timeline_option ] ) ) {
1227 1405 $m['value']['timeline_options'][ $timeline_option_group_key ][ $timeline_option_key ] = $frm_duplicate_ids[ $timeline_option ];
1228 1406 }
1229 1407 }
@@ -1230,8 +1408,9 @@
1230 1408 }
1231 1409 }
1232 1410
1233 1411 $check_dup_array = array();
1412 +
1234 1413 if ( ! empty( $m['value']['order_by'] ) ) {
1235 1414 if ( is_numeric( $m['value']['order_by'] ) && isset( $frm_duplicate_ids[ $m['value']['order_by'] ] ) ) {
1236 1415 $m['value']['order_by'] = $frm_duplicate_ids[ $m['value']['order_by'] ];
1237 1416 } elseif ( is_array( $m['value']['order_by'] ) ) {
@@ -1261,8 +1440,14 @@
1261 1440
1262 1441 $post['postmeta'][ (string) $meta->meta_key ] = $m['value'];
1263 1442 }
1264 1443
1444 + /**
1445 + * @param array $post
1446 + * @param object $layout
1447 + *
1448 + * @return void
1449 + */
1265 1450 private static function populate_layout( &$post, $layout ) {
1266 1451 $post['layout'][ (string) $layout->type ] = (string) $layout->data;
1267 1452 }
1268 1453
@@ -1274,16 +1459,19 @@
1274 1459 */
1275 1460 private static function populate_taxonomies( &$post, $item ) {
1276 1461 foreach ( $item->category as $c ) {
1277 1462 $att = $c->attributes();
1463 +
1278 1464 if ( ! isset( $att['nicename'] ) ) {
1279 1465 continue;
1280 1466 }
1281 1467
1282 1468 $taxonomy = (string) $att['domain'];
1469 +
1283 1470 if ( is_taxonomy_hierarchical( $taxonomy ) ) {
1284 1471 $name = (string) $att['nicename'];
1285 1472 $h_term = get_term_by( 'slug', $name, $taxonomy );
1473 +
1286 1474 if ( $h_term ) {
1287 1475 $name = $h_term->term_id;
1288 1476 }
1289 1477 unset( $h_term );
@@ -1301,8 +1489,12 @@
1301 1489 }
1302 1490
1303 1491 /**
1304 1492 * Edit post if the key and created time match.
1493 + *
1494 + * @param array $post By reference.
1495 + *
1496 + * @return void
1305 1497 */
1306 1498 private static function maybe_editing_post( &$post ) {
1307 1499 $match_by = array(
1308 1500 'post_type' => $post['post_type'],
@@ -1317,10 +1509,11 @@
1317 1509 }
1318 1510
1319 1511 $editing = get_posts( $match_by );
1320 1512
1321 - if ( ! empty( $editing ) && current( $editing )->post_date == $post['post_date'] ) {
1322 - // set the id of the post to edit
1513 + // phpcs:ignore Universal.Operators.StrictComparisons
1514 + if ( $editing && current( $editing )->post_date == $post['post_date'] ) {
1515 + // Set the id of the post to edit
1323 1516 $post['ID'] = current( $editing )->ID;
1324 1517 }
1325 1518 }
1326 1519
@@ -1326,8 +1519,9 @@
1326 1519
1327 1520 /**
1328 1521 * @param array $post
1329 1522 * @param int $post_id
1523 + *
1330 1524 * @return void
1331 1525 */
1332 1526 private static function update_postmeta( &$post, $post_id ) {
1333 1527 foreach ( $post['postmeta'] as $k => $v ) {
@@ -1364,29 +1558,41 @@
1364 1558 * @param array $post
1365 1559 * @param int $post_id
1366 1560 */
1367 1561 private static function update_layout( &$post, $post_id ) {
1368 - if ( is_callable( 'FrmViewsLayout::maybe_create_layouts_for_view' ) ) {
1369 - $listing_layout = ! empty( $post['layout']['listing'] ) ? json_decode( $post['layout']['listing'], true ) : array();
1370 - $detail_layout = ! empty( $post['layout']['detail'] ) ? json_decode( $post['layout']['detail'], true ) : array();
1371 - if ( $listing_layout || $detail_layout ) {
1372 - FrmViewsLayout::maybe_create_layouts_for_view( $post_id, $listing_layout, $detail_layout );
1373 - }
1562 + if ( ! is_callable( 'FrmViewsLayout::maybe_create_layouts_for_view' ) ) {
1563 + return;
1374 1564 }
1565 +
1566 + $listing_layout = ! empty( $post['layout']['listing'] ) ? json_decode( $post['layout']['listing'], true ) : array();
1567 + $detail_layout = ! empty( $post['layout']['detail'] ) ? json_decode( $post['layout']['detail'], true ) : array();
1568 +
1569 + if ( $listing_layout || $detail_layout ) {
1570 + FrmViewsLayout::maybe_create_layouts_for_view( $post_id, $listing_layout, $detail_layout );
1571 + }
1375 1572 }
1376 1573
1574 + /**
1575 + * @param array $imported
1576 + *
1577 + * @return void
1578 + */
1377 1579 private static function maybe_update_stylesheet( $imported ) {
1378 1580 $new_styles = ! empty( $imported['imported']['styles'] );
1379 1581 $updated_styles = ! empty( $imported['updated']['styles'] );
1380 - if ( $new_styles || $updated_styles ) {
1381 - if ( is_admin() && function_exists( 'get_filesystem_method' ) ) {
1382 - $frm_style = new FrmStyle();
1383 - $frm_style->update( 'default' );
1384 - }
1385 - foreach ( $imported['forms'] as $form_id ) {
1386 - self::update_custom_style_setting_after_import( $form_id );
1387 - }
1582 +
1583 + if ( ! $new_styles && ! $updated_styles ) {
1584 + return;
1388 1585 }
1586 +
1587 + if ( is_admin() && function_exists( 'get_filesystem_method' ) ) {
1588 + $frm_style = new FrmStyle();
1589 + $frm_style->update( 'default' );
1590 + }
1591 +
1592 + foreach ( $imported['forms'] as $form_id ) {
1593 + self::update_custom_style_setting_after_import( $form_id );
1594 + }
1389 1595 }
1390 1596
1391 1597 /**
1392 1598 * @param mixed $result
@@ -1391,8 +1597,10 @@
1391 1597 /**
1392 1598 * @param mixed $result
1393 1599 * @param string $message
1394 1600 * @param array $errors
1601 + *
1602 + * @return void
1395 1603 */
1396 1604 public static function parse_message( $result, &$message, &$errors ) {
1397 1605 if ( is_wp_error( $result ) ) {
1398 1606 $errors[] = $result->get_error_message();
@@ -1398,15 +1606,16 @@
1398 1606 $errors[] = $result->get_error_message();
1399 1607
1400 1608 // Remove the SimpleXML_parse_error from the WP_Error object to avoid
1401 1609 // displaying duplicate error messages from $result->get_error_message()
1402 - $error_codes = $result->get_error_codes();
1403 1610 $error_details = array();
1404 - foreach ( $error_codes as $error_code ) {
1611 +
1612 + foreach ( $result->get_error_codes() as $error_code ) {
1405 1613 // Clone WP_Error data because WP_Error removes all error messages and data
1406 - // associated with the specified error code when an item is removed.
1614 + // Associated with the specified error code when an item is removed.
1407 1615 // Source: https://developer.wordpress.org/reference/classes/wp_error/remove/#source
1408 1616 $error_details = $result->get_error_data( $error_code );
1617 +
1409 1618 if ( $error_code === 'SimpleXML_parse_error' ) {
1410 1619 $result->remove( $error_code );
1411 1620 break;
1412 1621 }
@@ -1411,9 +1620,9 @@
1411 1620 break;
1412 1621 }
1413 1622 }
1414 1623
1415 - if ( ! empty( $error_details ) ) {
1624 + if ( $error_details ) {
1416 1625 $errors[] = '<br />' . esc_html_x( 'Error details:', 'import xml message', 'formidable' ) . '<br />' . esc_html( print_r( $error_details, 1 ) );
1417 1626 }
1418 1627
1419 1628 return;
@@ -1433,42 +1642,48 @@
1433 1642 'updated' => __( 'Updated', 'formidable' ),
1434 1643 );
1435 1644
1436 1645 $message = '<ul>';
1646 +
1437 1647 foreach ( $result as $type => $results ) {
1438 1648 if ( ! isset( $t_strings[ $type ] ) ) {
1439 - // only print imported and updated
1649 + // Only print imported and updated
1440 1650 continue;
1441 1651 }
1442 1652
1443 1653 $s_message = array();
1654 +
1444 1655 foreach ( $results as $k => $m ) {
1445 1656 self::item_count_message( $m, $k, $s_message );
1446 1657 unset( $k, $m );
1447 1658 }
1448 1659
1449 - if ( ! empty( $s_message ) ) {
1450 - $message .= '<li><strong>' . $t_strings[ $type ] . ':</strong> ';
1451 - $message .= implode( ', ', $s_message );
1452 - $message .= '</li>';
1660 + if ( ! $s_message ) {
1661 + continue;
1453 1662 }
1454 - }
1455 1663
1664 + $message .= '<li><strong>' . $t_strings[ $type ] . ':</strong> ';
1665 + $message .= implode( ', ', $s_message );
1666 + $message .= '</li>';
1667 + }//end foreach
1668 +
1456 1669 if ( $message === '<ul>' ) {
1457 1670 $message = '';
1458 1671 $errors[] = __( 'Nothing was imported or updated', 'formidable' );
1459 - } else {
1460 - self::add_form_link_to_message( $result, $message );
1461 1672
1462 - /**
1463 - * @since 5.3
1464 - *
1465 - * @param string $message
1466 - * @param array $result
1467 - */
1468 - $message = apply_filters( 'frm_xml_parsed_message', $message, $result );
1469 - $message .= '</ul>';
1673 + return;
1470 1674 }
1675 +
1676 + self::add_form_link_to_message( $result, $message );
1677 +
1678 + /**
1679 + * @since 5.3
1680 + *
1681 + * @param string $message
1682 + * @param array $result
1683 + */
1684 + $message = apply_filters( 'frm_xml_parsed_message', $message, $result );
1685 + $message .= '</ul>';
1471 1686 }
1472 1687
1473 1688 /**
1474 1689 * @param int $m
@@ -1473,8 +1688,10 @@
1473 1688 /**
1474 1689 * @param int $m
1475 1690 * @param string $type
1476 1691 * @param array<string> $s_message
1692 + *
1693 + * @return void
1477 1694 */
1478 1695 public static function item_count_message( $m, $type, &$s_message ) {
1479 1696 if ( ! $m ) {
1480 1697 return;
@@ -1500,21 +1717,22 @@
1500 1717 );
1501 1718
1502 1719 if ( isset( $strings[ $type ] ) ) {
1503 1720 $s_message[] = $strings[ $type ];
1504 - } else {
1505 - $string = ' ' . $m . ' ' . ucfirst( $type );
1721 + return;
1722 + }
1506 1723
1507 - /**
1508 - * @since 5.3
1509 - *
1510 - * @param string $string Message string for imported item.
1511 - * @param int $m Number of item that was imported.
1512 - * }
1513 - */
1514 - $string = apply_filters( 'frm_xml_' . $type . '_count_message', $string, $m );
1515 - $s_message[] = $string;
1516 - }
1724 + $string = ' ' . $m . ' ' . ucfirst( $type );
1725 +
1726 + /**
1727 + * @since 5.3
1728 + *
1729 + * @param string $string Message string for imported item.
1730 + * @param int $m Number of item that was imported.
1731 + * }
1732 + */
1733 + $string = apply_filters( 'frm_xml_' . $type . '_count_message', $string, $m );
1734 + $s_message[] = $string;
1517 1735 }
1518 1736
1519 1737 /**
1520 1738 * If a single form was imported, include a link in the success message.
@@ -1519,24 +1737,28 @@
1519 1737 /**
1520 1738 * If a single form was imported, include a link in the success message.
1521 1739 *
1522 1740 * @since 4.0
1741 + *
1523 1742 * @param array $result The response from the XML import.
1524 1743 * @param string $message The response shown on the page after import.
1525 1744 */
1526 1745 private static function add_form_link_to_message( $result, &$message ) {
1527 1746 $total_forms = $result['imported']['forms'] + $result['updated']['forms'];
1747 +
1528 1748 if ( $total_forms > 1 ) {
1529 1749 return;
1530 1750 }
1531 1751
1532 1752 $primary_form = reset( $result['forms'] );
1533 - if ( ! empty( $primary_form ) ) {
1534 - $primary_form = FrmForm::getOne( $primary_form );
1535 - $form_id = empty( $primary_form->parent_form_id ) ? $primary_form->id : $primary_form->parent_form_id;
1536 1753
1537 - $message .= '<li><a href="' . esc_url( FrmForm::get_edit_link( $form_id ) ) . '">' . esc_html__( 'Go to imported form', 'formidable' ) . '</a></li>';
1754 + if ( ! $primary_form ) {
1755 + return;
1538 1756 }
1757 +
1758 + $primary_form = FrmForm::getOne( $primary_form );
1759 + $form_id = ! empty( $primary_form->parent_form_id ) ? $primary_form->parent_form_id : $primary_form->id;
1760 + $message .= '<li><a href="' . esc_url( FrmForm::get_edit_link( $form_id ) ) . '">' . esc_html__( 'Go to imported form', 'formidable' ) . '</a></li>';
1539 1761 }
1540 1762
1541 1763 /**
1542 1764 * Prepare the form options for export
@@ -1549,22 +1771,17 @@
1549 1771 */
1550 1772 public static function prepare_form_options_for_export( $options ) {
1551 1773 FrmAppHelper::unserialize_or_decode( $options );
1552 1774 // Change custom_style to the post_name instead of ID (1 may be a string)
1553 - $not_default = isset( $options['custom_style'] ) && 1 != $options['custom_style'];
1775 + $not_default = isset( $options['custom_style'] ) && 1 != $options['custom_style']; // phpcs:ignore Universal.Operators.StrictComparisons
1776 +
1554 1777 if ( $not_default ) {
1555 1778 global $wpdb;
1556 - $table = $wpdb->prefix . 'posts';
1557 - $where = array( 'ID' => $options['custom_style'] );
1558 - $select = 'post_name';
1559 -
1560 - $style_name = FrmDb::get_var( $table, $where, $select );
1561 -
1562 - if ( $style_name ) {
1563 - $options['custom_style'] = $style_name;
1564 - } else {
1565 - $options['custom_style'] = 1;
1566 - }
1779 + $table = $wpdb->prefix . 'posts';
1780 + $where = array( 'ID' => $options['custom_style'] );
1781 + $select = 'post_name';
1782 + $style_name = FrmDb::get_var( $table, $where, $select );
1783 + $options['custom_style'] = $style_name ? $style_name : 1;
1567 1784 }
1568 1785 self::remove_default_form_options( $options );
1569 1786 $options = serialize( $options );
1570 1787
@@ -1575,11 +1792,16 @@
1575 1792 * If the saved value is the same as the default, remove it from the export
1576 1793 * This keeps file size down and prevents overriding global settings after import
1577 1794 *
1578 1795 * @since 3.06
1796 + *
1797 + * @param array $options By reference.
1798 + *
1799 + * @return void
1579 1800 */
1580 1801 private static function remove_default_form_options( &$options ) {
1581 1802 $defaults = FrmFormsHelper::get_default_opts();
1803 +
1582 1804 if ( is_callable( 'FrmProFormsHelper::get_default_opts' ) ) {
1583 1805 $defaults += FrmProFormsHelper::get_default_opts();
1584 1806 }
1585 1807 self::remove_defaults( $defaults, $options );
@@ -1588,8 +1810,12 @@
1588 1810 /**
1589 1811 * Remove extra settings from field to keep file size down
1590 1812 *
1591 1813 * @since 3.06
1814 + *
1815 + * @param object $field
1816 + *
1817 + * @return void
1592 1818 */
1593 1819 public static function prepare_field_for_export( &$field ) {
1594 1820 self::remove_default_field_options( $field );
1595 1821 self::add_image_src_to_image_options( $field );
@@ -1598,11 +1824,16 @@
1598 1824 /**
1599 1825 * Remove defaults from field options too
1600 1826 *
1601 1827 * @since 3.06
1828 + *
1829 + * @param object $field
1830 + *
1831 + * @return void
1602 1832 */
1603 1833 private static function remove_default_field_options( &$field ) {
1604 1834 $defaults = self::default_field_options( $field->type );
1835 +
1605 1836 if ( empty( $defaults['blank'] ) ) {
1606 1837 $global_settings = new FrmSettings();
1607 1838 $global_defaults = $global_settings->default_options();
1608 1839 $defaults['blank'] = $global_defaults['blank_msg'];
@@ -1630,12 +1861,13 @@
1630 1861 *
1631 1862 * @since 5.5.1
1632 1863 *
1633 1864 * @param stdClass $field
1865 + *
1634 1866 * @return void
1635 1867 */
1636 1868 private static function add_image_src_to_image_options( $field ) {
1637 - if ( empty( $field->options ) || false === strpos( $field->options, 'image' ) ) {
1869 + if ( empty( $field->options ) || ! str_contains( $field->options, 'image' ) ) {
1638 1870 return;
1639 1871 }
1640 1872
1641 1873 $updated = false;
@@ -1646,12 +1878,14 @@
1646 1878 return;
1647 1879 }
1648 1880
1649 1881 foreach ( $options as $key => $option ) {
1650 - if ( is_array( $option ) && ! empty( $option['image'] ) ) {
1651 - $options[ $key ]['src'] = wp_get_attachment_url( $option['image'] );
1652 - $updated = true;
1882 + if ( ! is_array( $option ) || empty( $option['image'] ) ) {
1883 + continue;
1653 1884 }
1885 +
1886 + $options[ $key ]['src'] = wp_get_attachment_url( $option['image'] );
1887 + $updated = true;
1654 1888 }
1655 1889
1656 1890 if ( $updated ) {
1657 1891 $field->options = maybe_serialize( $options );
@@ -1659,14 +1893,20 @@
1659 1893 }
1660 1894
1661 1895 /**
1662 1896 * @since 3.06.03
1897 + *
1898 + * @param string $type
1899 + *
1900 + * @return array
1663 1901 */
1664 1902 private static function default_field_options( $type ) {
1665 1903 $defaults = FrmFieldsHelper::get_default_field_options( $type );
1904 +
1666 1905 if ( empty( $defaults['custom_html'] ) ) {
1667 1906 $defaults['custom_html'] = FrmFieldsHelper::get_default_html( $type );
1668 1907 }
1908 +
1669 1909 return $defaults;
1670 1910 }
1671 1911
1672 1912 /**
@@ -1673,8 +1913,13 @@
1673 1913 * Compare the default array to the saved values and
1674 1914 * remove if they are the same
1675 1915 *
1676 1916 * @since 3.06
1917 + *
1918 + * @param array $defaults
1919 + * @param array $saved
1920 + *
1921 + * @return void
1677 1922 */
1678 1923 private static function remove_defaults( $defaults, &$saved ) {
1679 1924 foreach ( $saved as $key => $value ) {
1680 1925 if ( isset( $defaults[ $key ] ) && $defaults[ $key ] === $value ) {
@@ -1686,8 +1931,14 @@
1686 1931 /**
1687 1932 * The line endings may prevent html from being equal when it should
1688 1933 *
1689 1934 * @since 3.06
1935 + *
1936 + * @param string $html_name
1937 + * @param array $defaults
1938 + * @param array $options
1939 + *
1940 + * @return void
1690 1941 */
1691 1942 private static function remove_default_html( $html_name, $defaults, &$options ) {
1692 1943 if ( ! isset( $options[ $html_name ] ) || ! isset( $defaults[ $html_name ] ) ) {
1693 1944 return;
@@ -1694,23 +1945,31 @@
1694 1945 }
1695 1946
1696 1947 $old_html = str_replace( "\r\n", "\n", $options[ $html_name ] );
1697 1948 $default_html = $defaults[ $html_name ];
1949 +
1950 + // phpcs:ignore Universal.Operators.StrictComparisons
1698 1951 if ( $old_html == $default_html ) {
1699 1952 unset( $options[ $html_name ] );
1700 -
1701 1953 return;
1702 1954 }
1703 1955
1704 1956 // Account for some of the older field default HTML.
1705 1957 $default_html = str_replace( ' id="frm_desc_field_[key]"', '', $default_html );
1706 - if ( $old_html == $default_html ) {
1958 +
1959 + if ( $old_html === $default_html ) {
1707 1960 unset( $options[ $html_name ] );
1708 1961 }
1709 1962 }
1710 1963
1964 + /**
1965 + * @param string $str
1966 + *
1967 + * @return string
1968 + */
1711 1969 public static function cdata( $str ) {
1712 1970 FrmAppHelper::unserialize_or_decode( $str );
1971 +
1713 1972 if ( is_array( $str ) ) {
1714 1973 $str = json_encode( $str );
1715 1974 } elseif ( FrmAppHelper::is_valid_utf8( $str ) === false ) {
1716 1975 $str = FrmAppHelper::maybe_utf8_encode( $str );
@@ -1722,11 +1981,9 @@
1722 1981
1723 1982 self::remove_invalid_characters_from_xml( $str );
1724 1983
1725 1984 // $str = ent2ncr(esc_html( $str));
1726 - $str = '<![CDATA[' . str_replace( ']]>', ']]]]><![CDATA[>', $str ) . ']]>';
1727 -
1728 - return $str;
1985 + return '<![CDATA[' . str_replace( ']]>', ']]]]><![CDATA[>', $str ) . ']]>';
1729 1986 }
1730 1987
1731 1988 /**
1732 1989 * Remove <US> character (unit separator) from exported strings
@@ -1733,8 +1990,10 @@
1733 1990 *
1734 1991 * @since 2.0.22
1735 1992 *
1736 1993 * @param string $str
1994 + *
1995 + * @return void
1737 1996 */
1738 1997 private static function remove_invalid_characters_from_xml( &$str ) {
1739 1998 // Remove <US> character
1740 1999 $str = str_replace( '\x1F', '', $str );
@@ -1739,8 +1998,18 @@
1739 1998 // Remove <US> character
1740 1999 $str = str_replace( '\x1F', '', $str );
1741 2000 }
1742 2001
2002 + /**
2003 + * Migrate form settings to actions
2004 + *
2005 + * @param array $form_options
2006 + * @param int $form_id
2007 + * @param array $imported
2008 + * @param bool $switch
2009 + *
2010 + * @return void
2011 + */
1743 2012 public static function migrate_form_settings_to_actions( $form_options, $form_id, &$imported = array(), $switch = false ) {
1744 2013 // Get post type
1745 2014 $post_type = FrmFormActionsController::$action_post_type;
1746 2015
@@ -1765,9 +2034,9 @@
1765 2034 * @param array $imported
1766 2035 * @param bool $switch
1767 2036 */
1768 2037 private static function migrate_post_settings_to_action( $form_options, $form_id, $post_type, &$imported, $switch ) {
1769 - if ( ! isset( $form_options['create_post'] ) || ! $form_options['create_post'] ) {
2038 + if ( empty( $form_options['create_post'] ) ) {
1770 2039 return;
1771 2040 }
1772 2041
1773 2042 $new_action = array(
@@ -1819,8 +2088,9 @@
1819 2088 $array_fields = array( 'post_category', 'post_custom_fields' );
1820 2089
1821 2090 $new_action['post_content'] = self::switch_action_field_ids( $new_action['post_content'], $basic_fields, $array_fields );
1822 2091 }
2092 +
1823 2093 $new_action['post_content'] = json_encode( $new_action['post_content'] );
1824 2094
1825 2095 $exists = get_posts(
1826 2096 array(
@@ -1830,13 +2100,15 @@
1830 2100 'numberposts' => 1,
1831 2101 )
1832 2102 );
1833 2103
1834 - if ( ! $exists ) {
1835 - // this isn't an email, but we need to use a class that will always be included
1836 - FrmDb::save_json_post( $new_action );
1837 - ++$imported['imported']['actions'];
2104 + if ( $exists ) {
2105 + return;
1838 2106 }
2107 +
2108 + // This isn't an email, but we need to use a class that will always be included
2109 + FrmDb::save_json_post( $new_action );
2110 + ++$imported['imported']['actions'];
1839 2111 }
1840 2112
1841 2113 /**
1842 2114 * Switch old field IDs for new field IDs in emails and post
@@ -1853,9 +2125,9 @@
1853 2125 global $frm_duplicate_ids;
1854 2126
1855 2127 // If there aren't IDs that were switched, end now
1856 2128 if ( ! $frm_duplicate_ids ) {
1857 - return;
2129 + return null;
1858 2130 }
1859 2131
1860 2132 // Get old IDs
1861 2133 $old = array_keys( $frm_duplicate_ids );
@@ -1864,11 +2136,13 @@
1864 2136 $new = array_values( $frm_duplicate_ids );
1865 2137
1866 2138 // Do a str_replace with each item to set the new IDs
1867 2139 foreach ( $post_content as $key => $setting ) {
2140 + // phpcs:ignore WordPress.PHP.StrictInArray.MissingTrueStrict
1868 2141 if ( ! is_array( $setting ) && in_array( $key, $basic_fields ) ) {
1869 2142 // Replace old IDs with new IDs
1870 2143 $post_content[ $key ] = str_replace( $old, $new, $setting );
2144 + // phpcs:ignore WordPress.PHP.StrictInArray.MissingTrueStrict
1871 2145 } elseif ( is_array( $setting ) && in_array( $key, $array_fields ) ) {
1872 2146 foreach ( $setting as $k => $val ) {
1873 2147 // Replace old IDs with new IDs
1874 2148 $post_content[ $key ][ $k ] = str_replace( $old, $new, $val );
@@ -1879,8 +2153,19 @@
1879 2153
1880 2154 return $post_content;
1881 2155 }
1882 2156
2157 + /**
2158 + * Migrate email settings to action
2159 + *
2160 + * @param array $form_options
2161 + * @param int $form_id
2162 + * @param string $post_type
2163 + * @param array $imported
2164 + * @param bool $switch
2165 + *
2166 + * @return void
2167 + */
1883 2168 private static function migrate_email_settings_to_action( $form_options, $form_id, $post_type, &$imported, $switch ) {
1884 2169 // No old notifications or autoresponders to carry over
1885 2170 if ( ! isset( $form_options['auto_responder'] ) && ! isset( $form_options['notification'] ) && ! isset( $form_options['email_to'] ) ) {
1886 2171 return;
@@ -1894,9 +2179,9 @@
1894 2179
1895 2180 // Migrate autoresponders
1896 2181 self::migrate_autoresponder_to_action( $form_options, $form_id, $notifications );
1897 2182
1898 - if ( empty( $notifications ) ) {
2183 + if ( ! $notifications ) {
1899 2184 return;
1900 2185 }
1901 2186
1902 2187 foreach ( $notifications as $new_notification ) {
@@ -1907,9 +2192,8 @@
1907 2192 $new_notification['post_status'] = 'publish';
1908 2193
1909 2194 // Switch field IDs and keys, if needed
1910 2195 if ( $switch ) {
1911 -
1912 2196 // Switch field IDs in email conditional logic
1913 2197 self::switch_email_condition_field_ids( $new_notification['post_content'] );
1914 2198
1915 2199 // Switch all other field IDs in email
@@ -1914,8 +2198,9 @@
1914 2198
1915 2199 // Switch all other field IDs in email
1916 2200 $new_notification['post_content'] = FrmFieldsHelper::switch_field_ids( $new_notification['post_content'] );
1917 2201 }
2202 +
1918 2203 $new_notification['post_content'] = FrmAppHelper::prepare_and_encode( $new_notification['post_content'] );
1919 2204
1920 2205 $exists = get_posts(
1921 2206 array(
@@ -1925,9 +2210,9 @@
1925 2210 'numberposts' => 1,
1926 2211 )
1927 2212 );
1928 2213
1929 - if ( empty( $exists ) ) {
2214 + if ( ! $exists ) {
1930 2215 FrmDb::save_json_post( $new_notification );
1931 2216 ++$imported['imported']['actions'];
1932 2217 }
1933 2218 unset( $new_notification );
@@ -1942,31 +2227,43 @@
1942 2227 * @since 2.05
1943 2228 *
1944 2229 * @param int|string $form_id
1945 2230 * @param array $form_options
2231 + *
2232 + * @return void
1946 2233 */
1947 2234 private static function remove_deprecated_notification_settings( $form_id, $form_options ) {
1948 2235 $delete_settings = array( 'notification', 'autoresponder', 'email_to' );
2236 +
1949 2237 foreach ( $delete_settings as $index ) {
1950 2238 if ( isset( $form_options[ $index ] ) ) {
1951 2239 unset( $form_options[ $index ] );
1952 2240 }
1953 2241 }
2242 +
1954 2243 FrmForm::update( $form_id, array( 'options' => $form_options ) );
1955 2244 }
1956 2245
2246 + /**
2247 + * Migrate notifications to action
2248 + *
2249 + * @param array $form_options
2250 + * @param int $form_id
2251 + * @param array $notifications
2252 + *
2253 + * @return void
2254 + */
1957 2255 private static function migrate_notifications_to_action( $form_options, $form_id, &$notifications ) {
1958 2256 if ( ! isset( $form_options['notification'] ) && ! empty( $form_options['email_to'] ) ) {
1959 - // add old settings into notification array
2257 + // Add old settings into notification array
1960 2258 $form_options['notification'] = array( 0 => $form_options );
1961 2259 } elseif ( isset( $form_options['notification']['email_to'] ) ) {
1962 - // make sure it's in the correct format
2260 + // Make sure it's in the correct format
1963 2261 $form_options['notification'] = array( 0 => $form_options['notification'] );
1964 2262 }
1965 2263
1966 2264 if ( isset( $form_options['notification'] ) && is_array( $form_options['notification'] ) ) {
1967 2265 foreach ( $form_options['notification'] as $email_key => $notification ) {
1968 -
1969 2266 $atts = array(
1970 2267 'email_to' => '',
1971 2268 'reply_to' => '',
1972 2269 'reply_to_name' => '',
@@ -1977,9 +2274,9 @@
1977 2274
1978 2275 // Format the email data
1979 2276 self::format_email_data( $atts, $notification );
1980 2277
1981 - if ( isset( $notification['twilio'] ) && $notification['twilio'] ) {
2278 + if ( ! empty( $notification['twilio'] ) ) {
1982 2279 do_action( 'frm_create_twilio_action', $atts, $notification );
1983 2280 }
1984 2281
1985 2282 // Setup the new notification
@@ -1990,8 +2287,16 @@
1990 2287 }//end foreach
1991 2288 }//end if
1992 2289 }
1993 2290
2291 + /**
2292 + * Format email data
2293 + *
2294 + * @param array $atts
2295 + * @param array $notification
2296 + *
2297 + * @return void
2298 + */
1994 2299 private static function format_email_data( &$atts, $notification ) {
1995 2300 // Format email_to
1996 2301 self::format_email_to_data( $atts, $notification );
1997 2302
@@ -1999,14 +2304,16 @@
1999 2304 $reply_fields = array(
2000 2305 'reply_to' => '',
2001 2306 'reply_to_name' => '',
2002 2307 );
2308 +
2003 2309 foreach ( $reply_fields as $f => $val ) {
2004 2310 if ( isset( $notification[ $f ] ) ) {
2005 2311 $atts[ $f ] = $notification[ $f ];
2006 - if ( 'custom' == $notification[ $f ] ) {
2312 +
2313 + if ( 'custom' === $notification[ $f ] ) {
2007 2314 $atts[ $f ] = $notification[ 'cust_' . $f ];
2008 - } elseif ( is_numeric( $atts[ $f ] ) && ! empty( $atts[ $f ] ) ) {
2315 + } elseif ( is_numeric( $atts[ $f ] ) && $atts[ $f ] ) {
2009 2316 $atts[ $f ] = '[' . $atts[ $f ] . ']';
2010 2317 }
2011 2318 }
2012 2319 unset( $f, $val );
@@ -2013,21 +2320,27 @@
2013 2320 }
2014 2321
2015 2322 // Format event
2016 2323 $atts['event'] = array( 'create' );
2324 +
2325 + // phpcs:ignore Universal.Operators.StrictComparisons
2017 2326 if ( isset( $notification['update_email'] ) && 1 == $notification['update_email'] ) {
2018 2327 $atts['event'][] = 'update';
2019 - } elseif ( isset( $notification['update_email'] ) && 2 == $notification['update_email'] ) {
2328 + } elseif ( isset( $notification['update_email'] ) && 2 == $notification['update_email'] ) { // phpcs:ignore Universal.Operators.StrictComparisons
2020 2329 $atts['event'] = array( 'update' );
2021 2330 }
2022 2331 }
2023 2332
2333 + /**
2334 + * Format email_to data
2335 + *
2336 + * @param array $atts
2337 + * @param array $notification
2338 + *
2339 + * @return void
2340 + */
2024 2341 private static function format_email_to_data( &$atts, $notification ) {
2025 - if ( isset( $notification['email_to'] ) ) {
2026 - $atts['email_to'] = preg_split( '/ (,|;) /', $notification['email_to'] );
2027 - } else {
2028 - $atts['email_to'] = array();
2029 - }
2342 + $atts['email_to'] = isset( $notification['email_to'] ) ? preg_split( '/ (,|;) /', $notification['email_to'] ) : array();
2030 2343
2031 2344 if ( isset( $notification['also_email_to'] ) ) {
2032 2345 $email_fields = (array) $notification['also_email_to'];
2033 2346 $atts['email_to'] = array_merge( $email_fields, $atts['email_to'] );
@@ -2034,24 +2347,36 @@
2034 2347 unset( $email_fields );
2035 2348 }
2036 2349
2037 2350 foreach ( $atts['email_to'] as $key => $email_field ) {
2038 -
2039 2351 if ( is_numeric( $email_field ) ) {
2040 2352 $atts['email_to'][ $key ] = '[' . $email_field . ']';
2041 2353 }
2042 2354
2043 - if ( strpos( $email_field, '|' ) ) {
2044 - $email_opt = explode( '|', $email_field );
2045 - if ( isset( $email_opt[0] ) ) {
2046 - $atts['email_to'][ $key ] = '[' . $email_opt[0] . ' show=' . $email_opt[1] . ']';
2047 - }
2048 - unset( $email_opt );
2355 + if ( ! str_contains( $email_field, '|' ) ) {
2356 + continue;
2049 2357 }
2358 +
2359 + $email_opt = explode( '|', $email_field );
2360 +
2361 + if ( isset( $email_opt[0] ) ) {
2362 + $atts['email_to'][ $key ] = '[' . $email_opt[0] . ' show=' . $email_opt[1] . ']';
2363 + }
2364 + unset( $email_opt );
2050 2365 }
2366 +
2051 2367 $atts['email_to'] = implode( ', ', $atts['email_to'] );
2052 2368 }
2053 2369
2370 + /**
2371 + * Setup new notification
2372 + *
2373 + * @param array $new_notification
2374 + * @param array $notification
2375 + * @param array $atts
2376 + *
2377 + * @return void
2378 + */
2054 2379 private static function setup_new_notification( &$new_notification, $notification, $atts ) {
2055 2380 // Set up new notification
2056 2381 $new_notification = array(
2057 2382 'post_content' => array(
@@ -2062,12 +2387,13 @@
2062 2387 );
2063 2388
2064 2389 // Add more fields to the new notification
2065 2390 $add_fields = array( 'email_message', 'email_subject', 'plain_text', 'inc_user_info', 'conditions' );
2391 +
2066 2392 foreach ( $add_fields as $add_field ) {
2067 2393 if ( isset( $notification[ $add_field ] ) ) {
2068 2394 $new_notification['post_content'][ $add_field ] = $notification[ $add_field ];
2069 - } elseif ( in_array( $add_field, array( 'plain_text', 'inc_user_info' ) ) ) {
2395 + } elseif ( in_array( $add_field, array( 'plain_text', 'inc_user_info' ), true ) ) {
2070 2396 $new_notification['post_content'][ $add_field ] = 0;
2071 2397 } else {
2072 2398 $new_notification['post_content'][ $add_field ] = '';
2073 2399 }
@@ -2078,9 +2404,9 @@
2078 2404 $new_notification['post_content']['reply_to'] = $atts['reply_to'];
2079 2405
2080 2406 // Set from
2081 2407 if ( ! empty( $atts['reply_to'] ) || ! empty( $atts['reply_to_name'] ) ) {
2082 - $new_notification['post_content']['from'] = ( empty( $atts['reply_to_name'] ) ? '[sitename]' : $atts['reply_to_name'] ) . ' <' . ( empty( $atts['reply_to'] ) ? '[admin_email]' : $atts['reply_to'] ) . '>';
2408 + $new_notification['post_content']['from'] = ( ! empty( $atts['reply_to_name'] ) ? $atts['reply_to_name'] : '[sitename]' ) . ' <' . ( ! empty( $atts['reply_to'] ) ? $atts['reply_to'] : '[admin_email]' ) . '>'; // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
2083 2409 }
2084 2410 }
2085 2411
2086 2412 /**
@@ -2086,63 +2412,81 @@
2086 2412 /**
2087 2413 * Switch field IDs in pre-2.0 email conditional logic
2088 2414 *
2089 2415 * @param array $post_content Pass by reference.
2416 + *
2417 + * @return void
2090 2418 */
2091 2419 private static function switch_email_condition_field_ids( &$post_content ) {
2092 2420 // Switch field IDs in conditional logic
2093 - if ( isset( $post_content['conditions'] ) && is_array( $post_content['conditions'] ) ) {
2094 - foreach ( $post_content['conditions'] as $email_key => $val ) {
2095 - if ( is_numeric( $email_key ) ) {
2096 - $post_content['conditions'][ $email_key ] = self::switch_action_field_ids( $val, array( 'hide_field' ) );
2097 - }
2098 - unset( $email_key, $val );
2421 + if ( ! isset( $post_content['conditions'] ) || ! is_array( $post_content['conditions'] ) ) {
2422 + return;
2423 + }
2424 +
2425 + foreach ( $post_content['conditions'] as $email_key => $val ) {
2426 + if ( is_numeric( $email_key ) ) {
2427 + $post_content['conditions'][ $email_key ] = self::switch_action_field_ids( $val, array( 'hide_field' ) );
2099 2428 }
2429 + unset( $email_key, $val );
2100 2430 }
2101 2431 }
2102 2432
2433 + /**
2434 + * Migrate autoresponder to action
2435 + *
2436 + * @param array $form_options
2437 + * @param int $form_id
2438 + * @param array $notifications
2439 + *
2440 + * @return void
2441 + */
2103 2442 private static function migrate_autoresponder_to_action( $form_options, $form_id, &$notifications ) {
2104 - if ( isset( $form_options['auto_responder'] ) && $form_options['auto_responder'] && isset( $form_options['ar_email_message'] ) && $form_options['ar_email_message'] ) {
2105 - // migrate autoresponder
2443 + if ( empty( $form_options['auto_responder'] ) || empty( $form_options['ar_email_message'] ) ) {
2444 + return;
2445 + }
2106 2446
2107 - $email_field = $form_options['ar_email_to'] ?? 0;
2108 - if ( strpos( $email_field, '|' ) ) {
2109 - // data from entries field
2110 - $email_field = explode( '|', $email_field );
2111 - if ( isset( $email_field[1] ) ) {
2112 - $email_field = $email_field[1];
2113 - }
2447 + // Migrate autoresponder
2448 +
2449 + $email_field = $form_options['ar_email_to'] ?? 0;
2450 +
2451 + if ( str_contains( $email_field, '|' ) ) {
2452 + // Data from entries field
2453 + $email_field = explode( '|', $email_field );
2454 +
2455 + if ( isset( $email_field[1] ) ) {
2456 + $email_field = $email_field[1];
2114 2457 }
2115 - if ( is_numeric( $email_field ) && ! empty( $email_field ) ) {
2116 - $email_field = '[' . $email_field . ']';
2117 - }
2458 + }
2118 2459
2119 - $notification = $form_options;
2120 - $new_notification2 = array(
2121 - 'post_content' => array(
2122 - 'email_message' => $notification['ar_email_message'],
2123 - 'email_subject' => $notification['ar_email_subject'] ?? '',
2124 - 'email_to' => $email_field,
2125 - 'plain_text' => $notification['ar_plain_text'] ?? 0,
2126 - 'inc_user_info' => 0,
2127 - ),
2128 - 'post_name' => $form_id . '_email_' . count( $notifications ),
2129 - );
2460 + if ( is_numeric( $email_field ) && $email_field ) {
2461 + $email_field = '[' . $email_field . ']';
2462 + }
2130 2463
2131 - $reply_to = $notification['ar_reply_to'] ?? '';
2132 - $reply_to_name = $notification['ar_reply_to_name'] ?? '';
2464 + $notification = $form_options;
2465 + $new_notification2 = array(
2466 + 'post_content' => array(
2467 + 'email_message' => $notification['ar_email_message'],
2468 + 'email_subject' => $notification['ar_email_subject'] ?? '',
2469 + 'email_to' => $email_field,
2470 + 'plain_text' => $notification['ar_plain_text'] ?? 0,
2471 + 'inc_user_info' => 0,
2472 + ),
2473 + 'post_name' => $form_id . '_email_' . count( $notifications ),
2474 + );
2133 2475
2134 - if ( ! empty( $reply_to ) ) {
2135 - $new_notification2['post_content']['reply_to'] = $reply_to;
2136 - }
2476 + $reply_to = $notification['ar_reply_to'] ?? '';
2477 + $reply_to_name = $notification['ar_reply_to_name'] ?? '';
2137 2478
2138 - if ( ! empty( $reply_to ) || ! empty( $reply_to_name ) ) {
2139 - $new_notification2['post_content']['from'] = ( empty( $reply_to_name ) ? '[sitename]' : $reply_to_name ) . ' <' . ( empty( $reply_to ) ? '[admin_email]' : $reply_to ) . '>';
2140 - }
2479 + if ( $reply_to ) {
2480 + $new_notification2['post_content']['reply_to'] = $reply_to;
2481 + }
2141 2482
2142 - $notifications[] = $new_notification2;
2143 - unset( $new_notification2 );
2144 - }//end if
2483 + if ( $reply_to || $reply_to_name ) {
2484 + $new_notification2['post_content']['from'] = ( $reply_to_name ? $reply_to_name : '[sitename]' ) . ' <' . ( $reply_to ? $reply_to : '[admin_email]' ) . '>'; // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
2485 + }
2486 +
2487 + $notifications[] = $new_notification2;
2488 + unset( $new_notification2 );
2145 2489 }
2146 2490
2147 2491 /**
2148 2492 * PHP 8 backward compatibility for the libxml_disable_entity_loader function
@@ -2158,8 +2502,13 @@
2158 2502
2159 2503 return $loader;
2160 2504 }
2161 2505
2506 + /**
2507 + * PHP 8 backward compatibility for the libxml_disable_entity_loader function
2508 + *
2509 + * @return bool
2510 + */
2162 2511 public static function check_if_libxml_disable_entity_loader_exists() {
2163 2512 return version_compare( phpversion(), '8.0', '<' ) && ! function_exists( 'libxml_disable_entity_loader' );
2164 2513 }
2165 2514
@@ -2172,11 +2521,13 @@
2172 2521 * @return array
2173 2522 */
2174 2523 public static function get_supported_upload_file_types() {
2175 2524 $file_types = array( '.xml' );
2525 +
2176 2526 if ( FrmAppHelper::pro_is_installed() ) {
2177 2527 // CSV Importing is only available in Pro.
2178 2528 $file_types[] = '.csv';
2179 2529 }
2530 +
2180 2531 return $file_types;
2181 2532 }
2182 2533 }