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 +306 -211 6.27 → trunk View file →
@@ -73,9 +73,9 @@
73 73
74 74 $xml = simplexml_import_dom( $dom );
75 75 unset( $dom );
76 76
77 - // halt if loading produces an error
77 + // Halt if loading produces an error
78 78 if ( ! $xml ) {
79 79 return new WP_Error( 'SimpleXML_parse_error', __( 'There was an error when reading this XML file', 'formidable' ), libxml_get_errors() );
80 80 }
81 81
@@ -99,17 +99,19 @@
99 99 // Strip that out as it breaks the XML import.
100 100 $channel_start_position = strpos( $xml_string, '<channel>' );
101 101 $content_before_channel_tag = substr( $xml_string, 0, $channel_start_position );
102 102
103 - if ( ! str_starts_with( $content_before_channel_tag, '<meta name="generator" ' ) ) {
104 - $content_before_channel_tag = preg_replace(
105 - '/<meta\s+[^>]*name="generator"[^>]*\/>/i',
106 - '',
107 - $content_before_channel_tag,
108 - 1
109 - );
110 - $xml_string = $content_before_channel_tag . substr( $xml_string, $channel_start_position );
103 + if ( str_starts_with( $content_before_channel_tag, '<meta name="generator" ' ) ) {
104 + return;
111 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 );
112 114 }
113 115
114 116 /**
115 117 * Add terms, forms (form and field ids), posts (post ids), and entries to db, in that order
@@ -130,13 +132,15 @@
130 132 $imported = self::pre_import_data();
131 133
132 134 foreach ( array( 'term', 'form', 'view' ) as $item_type ) {
133 135 // Grab cats, tags, and terms, or forms or posts.
134 - if ( isset( $xml->{$item_type} ) ) {
135 - $function_name = 'import_xml_' . $item_type . 's';
136 - $imported = self::$function_name( $xml->{$item_type}, $imported );
137 - unset( $function_name, $xml->{$item_type} );
136 + if ( ! isset( $xml->{$item_type} ) ) {
137 + continue;
138 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} );
139 143 }
140 144
141 145 $imported = apply_filters( 'frm_importing_xml', $imported, $xml );
142 146
@@ -193,9 +197,9 @@
193 197 (string) $t->term_taxonomy,
194 198 array(
195 199 'slug' => (string) $t->term_slug,
196 200 'description' => (string) $t->term_description,
197 - 'parent' => empty( $parent ) ? 0 : $parent,
201 + 'parent' => $parent ? $parent : 0,
198 202 )
199 203 );
200 204
201 205 if ( $term && is_array( $term ) ) {
@@ -290,8 +294,23 @@
290 294 }//end foreach
291 295
292 296 self::maybe_update_child_form_parent_id( $imported['forms'], $child_forms );
293 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 +
294 313 return $imported;
295 314 }
296 315
297 316 /**
@@ -333,9 +352,9 @@
333 352 *
334 353 * @return false|object
335 354 */
336 355 private static function maybe_get_form( $form ) {
337 - // 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
338 357 $edit_query = array(
339 358 'form_key' => $form['form_key'],
340 359 'is_template' => $form['is_template'],
341 360 );
@@ -400,15 +419,17 @@
400 419 *
401 420 * @return void
402 421 */
403 422 private static function delete_removed_fields( $form_fields ) {
404 - if ( $form_fields ) {
405 - foreach ( $form_fields as $field ) {
406 - if ( is_object( $field ) ) {
407 - FrmField::destroy( $field->id );
408 - }
409 - 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 );
410 430 }
431 + unset( $field );
411 432 }
412 433 }
413 434
414 435 /**
@@ -460,14 +481,16 @@
460 481 * @param array $child_forms
461 482 */
462 483 private static function maybe_update_child_form_parent_id( $imported_forms, $child_forms ) {
463 484 foreach ( $child_forms as $child_form_id => $old_parent_form_id ) {
464 - if ( isset( $imported_forms[ $old_parent_form_id ] ) && (int) $imported_forms[ $old_parent_form_id ] !== (int) $old_parent_form_id ) {
465 - // Update all children with this old parent_form_id
466 - $new_parent_form_id = (int) $imported_forms[ $old_parent_form_id ];
467 - FrmForm::update( $child_form_id, array( 'parent_form_id' => $new_parent_form_id ) );
468 - 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;
469 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 );
470 493 }
471 494 }
472 495
473 496 /**
@@ -497,9 +520,9 @@
497 520 self::maybe_update_get_values_form_setting( $imported, $f );
498 521 self::migrate_placeholders( $f );
499 522
500 523 if ( $this_form ) {
501 - // check for field to edit by field id
524 + // Check for field to edit by field id
502 525 if ( isset( $form_fields[ $f['id'] ] ) ) {
503 526 FrmField::update( $f['id'], $f );
504 527 ++$imported['updated']['fields'];
505 528
@@ -512,9 +535,9 @@
512 535 } elseif ( isset( $form_fields[ $f['field_key'] ] ) ) {
513 536 $keys_by_original_field_id[ $f['id'] ] = $f['field_key'];
514 537 $old_field_id = $f['id'];
515 538
516 - // check for field to edit by field key
539 + // Check for field to edit by field key
517 540 unset( $f['id'] );
518 541
519 542 FrmField::update( $form_fields[ $f['field_key'] ], $f );
520 543 ++$imported['updated']['fields'];
@@ -596,13 +619,40 @@
596 619 'field_order' => (int) $field->field_order,
597 620 'form_id' => (int) $form_id,
598 621 'required' => (int) $field->required,
599 622 'options' => FrmAppHelper::maybe_json_decode( (string) $field->options ),
600 - 'field_options' => FrmAppHelper::maybe_json_decode( (string) $field->field_options ),
623 + 'field_options' => self::fill_field_options( $field ),
601 624 );
602 625 }
603 626
604 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 + /**
605 655 * @since 4.06
606 656 *
607 657 * @param array $f
608 658 *
@@ -621,15 +671,17 @@
621 671 'password',
622 672 'tag',
623 673 );
624 674
625 - if ( is_array( $f['default_value'] ) && in_array( $f['type'], $has_default, true ) ) {
626 - if ( count( $f['default_value'] ) === 1 ) {
627 - $f['default_value'] = '[' . reset( $f['default_value'] ) . ']';
628 - } else {
629 - $f['default_value'] = reset( $f['default_value'] );
630 - }
675 + if ( ! is_array( $f['default_value'] ) || ! in_array( $f['type'], $has_default, true ) ) {
676 + return;
631 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 + }
632 684 }
633 685
634 686 /**
635 687 * Make sure the required indicator is set.
@@ -685,17 +737,21 @@
685 737 if ( ! isset( $imported['forms'] ) ) {
686 738 return;
687 739 }
688 740
689 - if ( $f['type'] === 'form' || ( $f['type'] === 'divider' && FrmField::is_option_true( $f['field_options'], 'repeat' ) ) ) {
690 - if ( FrmField::is_option_true( $f['field_options'], 'form_select' ) ) {
691 - $form_select = (int) $f['field_options']['form_select'];
741 + if ( $f['type'] !== 'form' && ( $f['type'] !== 'divider' || ! FrmField::is_option_true( $f['field_options'], 'repeat' ) ) ) {
742 + return;
743 + }
692 744
693 - if ( isset( $imported['forms'][ $form_select ] ) ) {
694 - $f['field_options']['form_select'] = $imported['forms'][ $form_select ];
695 - }
696 - }
745 + if ( ! FrmField::is_option_true( $f['field_options'], 'form_select' ) ) {
746 + return;
697 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 + }
698 754 }
699 755
700 756 /**
701 757 * Update the get_values_form setting if the form was imported
@@ -711,14 +767,16 @@
711 767 if ( ! isset( $imported['forms'] ) ) {
712 768 return;
713 769 }
714 770
715 - if ( FrmField::is_option_true_in_array( $f['field_options'], 'get_values_form' ) ) {
716 - $old_form = $f['field_options']['get_values_form'];
771 + if ( ! FrmField::is_option_true_in_array( $f['field_options'], 'get_values_form' ) ) {
772 + return;
773 + }
717 774
718 - if ( isset( $imported['forms'][ $old_form ] ) ) {
719 - $f['field_options']['get_values_form'] = $imported['forms'][ $old_form ];
720 - }
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 ];
721 779 }
722 780 }
723 781
724 782 /**
@@ -771,29 +829,32 @@
771 829
772 830 // If a dropdown placeholder was used, remove the option so it won't be included twice.
773 831 $options = $field['options'];
774 832
775 - if ( $type === 'default_blank' && is_array( $options ) ) {
776 - $default_value = $field['default_value'];
833 + if ( $type !== 'default_blank' || ! is_array( $options ) ) {
834 + return $changes;
835 + }
777 836
778 - if ( is_array( $default_value ) ) {
779 - $default_value = reset( $default_value );
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 );
780 846 }
781 847
782 - foreach ( $options as $opt_key => $opt ) {
783 - if ( is_array( $opt ) ) {
784 - $opt = $opt['value'] ?? $opt['label'] ?? reset( $opt );
785 - }
786 -
787 - // phpcs:ignore Universal.Operators.StrictComparisons
788 - if ( $opt == $default_value ) {
789 - unset( $options[ $opt_key ] );
790 - break;
791 - }
848 + // phpcs:ignore Universal.Operators.StrictComparisons
849 + if ( $opt == $default_value ) {
850 + unset( $options[ $opt_key ] );
851 + break;
792 852 }
853 + }
793 854
794 - $changes['options'] = $options;
795 - }//end if
855 + $changes['options'] = $options;
856 + // end if
796 857
797 858 return $changes;
798 859 }
799 860
@@ -815,13 +876,14 @@
815 876 }
816 877
817 878 $new_id = FrmField::create( $f );
818 879
819 - // phpcs:ignore Universal.Operators.StrictComparisons
820 - if ( $new_id != false ) {
821 - ++$imported['imported']['fields'];
822 - do_action( 'frm_after_field_is_imported', $f, $new_id );
880 + if ( ! $new_id ) {
881 + return;
823 882 }
883 +
884 + ++$imported['imported']['fields'];
885 + do_action( 'frm_after_field_is_imported', $f, $new_id );
824 886 }
825 887
826 888 /**
827 889 * Import images for radio buttons and checkboxes from image src if available.
@@ -887,15 +949,17 @@
887 949 $field = (array) $field;
888 950 $frm_duplicate_ids = $keys_by_original_field_id;
889 951 $after = FrmFieldsHelper::switch_field_ids( $field );
890 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 +
891 960 if ( $before['field_options'] !== $after['field_options'] ) {
892 - $frm_duplicate_ids = $field_id_by_key;
893 - $after = FrmFieldsHelper::switch_field_ids( $after );
894 -
895 - if ( $before['field_options'] !== $after['field_options'] ) {
896 - FrmField::update( $field['id'], array( 'field_options' => $after['field_options'] ) );
897 - }
961 + FrmField::update( $field['id'], array( 'field_options' => $after['field_options'] ) );
898 962 }
899 963 }
900 964
901 965 $frm_duplicate_ids = $former_duplicate_ids;
@@ -918,29 +982,32 @@
918 982
919 983 if ( is_numeric( $form['options']['custom_style'] ) && 1 === intval( $form['options']['custom_style'] ) ) {
920 984 // Set to default
921 985 $form['options']['custom_style'] = 1;
922 - } else {
923 - // Replace the style name with the style ID on import
924 - global $wpdb;
925 - $table = $wpdb->prefix . 'posts';
926 - $where = array(
927 - 'post_name' => $form['options']['custom_style'],
928 - 'post_type' => 'frm_styles',
929 - );
930 - $select = 'ID';
931 - $style_id = FrmDb::get_var( $table, $where, $select );
932 986
933 - if ( $style_id ) {
934 - $form['options']['custom_style'] = $style_id;
935 - } else {
936 - // save the old style to maybe update after styles import
937 - $form['options']['old_style'] = $form['options']['custom_style'];
987 + return;
988 + }
938 989
939 - // Set to default
940 - $form['options']['custom_style'] = 1;
941 - }
942 - }//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;
943 1010 }
944 1011
945 1012 /**
946 1013 * After styles are imported, check for any forms that were linked
@@ -954,18 +1021,20 @@
954 1021 */
955 1022 private static function update_custom_style_setting_after_import( $form_id ) {
956 1023 $form = FrmForm::getOne( $form_id );
957 1024
958 - if ( $form && isset( $form->options['old_style'] ) ) {
959 - $form = (array) $form;
960 - $saved_style = $form['options']['custom_style'];
961 - $form['options']['custom_style'] = $form['options']['old_style'];
962 - self::update_custom_style_setting_on_import( $form );
963 - $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
1025 + if ( ! $form || ! isset( $form->options['old_style'] ) ) {
1026 + return;
1027 + }
964 1028
965 - if ( $has_changed ) {
966 - FrmForm::update( $form['id'], $form );
967 - }
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 );
968 1037 }
969 1038 }
970 1039
971 1040 /**
@@ -1092,9 +1161,9 @@
1092 1161 }
1093 1162 unset( $posts_with_shortcodes, $view_ids );
1094 1163
1095 1164 if ( ! empty( $imported['forms'] ) ) {
1096 - // 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
1097 1166 self::clear_forms_style_caches( $imported['forms'] );
1098 1167 }
1099 1168
1100 1169 self::maybe_update_stylesheet( $imported );
@@ -1257,9 +1326,9 @@
1257 1326 $post['attachment_url'] = (string) $item->attachment_url;
1258 1327 }
1259 1328
1260 1329 if ( $post['post_type'] === FrmFormActionsController::$action_post_type && isset( $imported['forms'][ (int) $post['menu_order'] ] ) ) {
1261 - // update to new form id
1330 + // Update to new form id
1262 1331 $post['menu_order'] = $imported['forms'][ (int) $post['menu_order'] ];
1263 1332 }
1264 1333
1265 1334 // Don't allow default styles to take over a site's default style
@@ -1300,9 +1369,9 @@
1300 1369 $m['value'] = $imported['forms'][ (int) $m['value'] ];
1301 1370 } else {
1302 1371 $m['value'] = FrmAppHelper::maybe_json_decode( $m['value'] );
1303 1372
1304 - if ( ! empty( $frm_duplicate_ids ) ) {
1373 + if ( $frm_duplicate_ids ) {
1305 1374 if ( 'frm_dyncontent' === $m['key'] ) {
1306 1375 $m['value'] = self::maybe_prepare_json_view_content( $m['value'] );
1307 1376 $m['value'] = FrmFieldsHelper::switch_field_ids( $m['value'] );
1308 1377 } elseif ( 'frm_options' === $m['key'] ) {
@@ -1330,8 +1399,9 @@
1330 1399
1331 1400 if ( ! empty( $m['value']['timeline_options'] ) ) {
1332 1401 foreach ( $m['value']['timeline_options'] as $timeline_option_group_key => $timeline_group_option ) {
1333 1402 foreach ( $timeline_group_option as $timeline_option_key => $timeline_option ) {
1403 + // @mago-expect lint:excessive-nesting
1334 1404 if ( isset( $frm_duplicate_ids[ $timeline_option ] ) ) {
1335 1405 $m['value']['timeline_options'][ $timeline_option_group_key ][ $timeline_option_key ] = $frm_duplicate_ids[ $timeline_option ];
1336 1406 }
1337 1407 }
@@ -1441,9 +1511,9 @@
1441 1511 $editing = get_posts( $match_by );
1442 1512
1443 1513 // phpcs:ignore Universal.Operators.StrictComparisons
1444 1514 if ( $editing && current( $editing )->post_date == $post['post_date'] ) {
1445 - // set the id of the post to edit
1515 + // Set the id of the post to edit
1446 1516 $post['ID'] = current( $editing )->ID;
1447 1517 }
1448 1518 }
1449 1519
@@ -1488,15 +1558,17 @@
1488 1558 * @param array $post
1489 1559 * @param int $post_id
1490 1560 */
1491 1561 private static function update_layout( &$post, $post_id ) {
1492 - if ( is_callable( 'FrmViewsLayout::maybe_create_layouts_for_view' ) ) {
1493 - $listing_layout = ! empty( $post['layout']['listing'] ) ? json_decode( $post['layout']['listing'], true ) : array();
1494 - $detail_layout = ! empty( $post['layout']['detail'] ) ? json_decode( $post['layout']['detail'], true ) : array();
1562 + if ( ! is_callable( 'FrmViewsLayout::maybe_create_layouts_for_view' ) ) {
1563 + return;
1564 + }
1495 1565
1496 - if ( $listing_layout || $detail_layout ) {
1497 - FrmViewsLayout::maybe_create_layouts_for_view( $post_id, $listing_layout, $detail_layout );
1498 - }
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 );
1499 1571 }
1500 1572 }
1501 1573
1502 1574 /**
@@ -1507,18 +1579,20 @@
1507 1579 private static function maybe_update_stylesheet( $imported ) {
1508 1580 $new_styles = ! empty( $imported['imported']['styles'] );
1509 1581 $updated_styles = ! empty( $imported['updated']['styles'] );
1510 1582
1511 - if ( $new_styles || $updated_styles ) {
1512 - if ( is_admin() && function_exists( 'get_filesystem_method' ) ) {
1513 - $frm_style = new FrmStyle();
1514 - $frm_style->update( 'default' );
1515 - }
1583 + if ( ! $new_styles && ! $updated_styles ) {
1584 + return;
1585 + }
1516 1586
1517 - foreach ( $imported['forms'] as $form_id ) {
1518 - self::update_custom_style_setting_after_import( $form_id );
1519 - }
1587 + if ( is_admin() && function_exists( 'get_filesystem_method' ) ) {
1588 + $frm_style = new FrmStyle();
1589 + $frm_style->update( 'default' );
1520 1590 }
1591 +
1592 + foreach ( $imported['forms'] as $form_id ) {
1593 + self::update_custom_style_setting_after_import( $form_id );
1594 + }
1521 1595 }
1522 1596
1523 1597 /**
1524 1598 * @param mixed $result
@@ -1523,8 +1597,10 @@
1523 1597 /**
1524 1598 * @param mixed $result
1525 1599 * @param string $message
1526 1600 * @param array $errors
1601 + *
1602 + * @return void
1527 1603 */
1528 1604 public static function parse_message( $result, &$message, &$errors ) {
1529 1605 if ( is_wp_error( $result ) ) {
1530 1606 $errors[] = $result->get_error_message();
@@ -1530,14 +1606,13 @@
1530 1606 $errors[] = $result->get_error_message();
1531 1607
1532 1608 // Remove the SimpleXML_parse_error from the WP_Error object to avoid
1533 1609 // displaying duplicate error messages from $result->get_error_message()
1534 - $error_codes = $result->get_error_codes();
1535 1610 $error_details = array();
1536 1611
1537 - foreach ( $error_codes as $error_code ) {
1612 + foreach ( $result->get_error_codes() as $error_code ) {
1538 1613 // Clone WP_Error data because WP_Error removes all error messages and data
1539 - // associated with the specified error code when an item is removed.
1614 + // Associated with the specified error code when an item is removed.
1540 1615 // Source: https://developer.wordpress.org/reference/classes/wp_error/remove/#source
1541 1616 $error_details = $result->get_error_data( $error_code );
1542 1617
1543 1618 if ( $error_code === 'SimpleXML_parse_error' ) {
@@ -1570,9 +1645,9 @@
1570 1645 $message = '<ul>';
1571 1646
1572 1647 foreach ( $result as $type => $results ) {
1573 1648 if ( ! isset( $t_strings[ $type ] ) ) {
1574 - // only print imported and updated
1649 + // Only print imported and updated
1575 1650 continue;
1576 1651 }
1577 1652
1578 1653 $s_message = array();
@@ -1581,30 +1656,34 @@
1581 1656 self::item_count_message( $m, $k, $s_message );
1582 1657 unset( $k, $m );
1583 1658 }
1584 1659
1585 - if ( $s_message ) {
1586 - $message .= '<li><strong>' . $t_strings[ $type ] . ':</strong> ';
1587 - $message .= implode( ', ', $s_message );
1588 - $message .= '</li>';
1660 + if ( ! $s_message ) {
1661 + continue;
1589 1662 }
1590 - }
1591 1663
1664 + $message .= '<li><strong>' . $t_strings[ $type ] . ':</strong> ';
1665 + $message .= implode( ', ', $s_message );
1666 + $message .= '</li>';
1667 + }//end foreach
1668 +
1592 1669 if ( $message === '<ul>' ) {
1593 1670 $message = '';
1594 1671 $errors[] = __( 'Nothing was imported or updated', 'formidable' );
1595 - } else {
1596 - self::add_form_link_to_message( $result, $message );
1597 1672
1598 - /**
1599 - * @since 5.3
1600 - *
1601 - * @param string $message
1602 - * @param array $result
1603 - */
1604 - $message = apply_filters( 'frm_xml_parsed_message', $message, $result );
1605 - $message .= '</ul>';
1673 + return;
1606 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>';
1607 1686 }
1608 1687
1609 1688 /**
1610 1689 * @param int $m
@@ -1609,8 +1688,10 @@
1609 1688 /**
1610 1689 * @param int $m
1611 1690 * @param string $type
1612 1691 * @param array<string> $s_message
1692 + *
1693 + * @return void
1613 1694 */
1614 1695 public static function item_count_message( $m, $type, &$s_message ) {
1615 1696 if ( ! $m ) {
1616 1697 return;
@@ -1636,21 +1717,22 @@
1636 1717 );
1637 1718
1638 1719 if ( isset( $strings[ $type ] ) ) {
1639 1720 $s_message[] = $strings[ $type ];
1640 - } else {
1641 - $string = ' ' . $m . ' ' . ucfirst( $type );
1721 + return;
1722 + }
1642 1723
1643 - /**
1644 - * @since 5.3
1645 - *
1646 - * @param string $string Message string for imported item.
1647 - * @param int $m Number of item that was imported.
1648 - * }
1649 - */
1650 - $string = apply_filters( 'frm_xml_' . $type . '_count_message', $string, $m );
1651 - $s_message[] = $string;
1652 - }
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;
1653 1735 }
1654 1736
1655 1737 /**
1656 1738 * If a single form was imported, include a link in the success message.
@@ -1668,13 +1750,15 @@
1668 1750 }
1669 1751
1670 1752 $primary_form = reset( $result['forms'] );
1671 1753
1672 - if ( $primary_form ) {
1673 - $primary_form = FrmForm::getOne( $primary_form );
1674 - $form_id = empty( $primary_form->parent_form_id ) ? $primary_form->id : $primary_form->parent_form_id;
1675 - $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;
1676 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>';
1677 1761 }
1678 1762
1679 1763 /**
1680 1764 * Prepare the form options for export
@@ -1794,12 +1878,14 @@
1794 1878 return;
1795 1879 }
1796 1880
1797 1881 foreach ( $options as $key => $option ) {
1798 - if ( is_array( $option ) && ! empty( $option['image'] ) ) {
1799 - $options[ $key ]['src'] = wp_get_attachment_url( $option['image'] );
1800 - $updated = true;
1882 + if ( ! is_array( $option ) || empty( $option['image'] ) ) {
1883 + continue;
1801 1884 }
1885 +
1886 + $options[ $key ]['src'] = wp_get_attachment_url( $option['image'] );
1887 + $updated = true;
1802 1888 }
1803 1889
1804 1890 if ( $updated ) {
1805 1891 $field->options = maybe_serialize( $options );
@@ -2014,13 +2100,15 @@
2014 2100 'numberposts' => 1,
2015 2101 )
2016 2102 );
2017 2103
2018 - if ( ! $exists ) {
2019 - // this isn't an email, but we need to use a class that will always be included
2020 - FrmDb::save_json_post( $new_action );
2021 - ++$imported['imported']['actions'];
2104 + if ( $exists ) {
2105 + return;
2022 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'];
2023 2111 }
2024 2112
2025 2113 /**
2026 2114 * Switch old field IDs for new field IDs in emails and post
@@ -2150,8 +2238,9 @@
2150 2238 if ( isset( $form_options[ $index ] ) ) {
2151 2239 unset( $form_options[ $index ] );
2152 2240 }
2153 2241 }
2242 +
2154 2243 FrmForm::update( $form_id, array( 'options' => $form_options ) );
2155 2244 }
2156 2245
2157 2246 /**
@@ -2164,12 +2253,12 @@
2164 2253 * @return void
2165 2254 */
2166 2255 private static function migrate_notifications_to_action( $form_options, $form_id, &$notifications ) {
2167 2256 if ( ! isset( $form_options['notification'] ) && ! empty( $form_options['email_to'] ) ) {
2168 - // add old settings into notification array
2257 + // Add old settings into notification array
2169 2258 $form_options['notification'] = array( 0 => $form_options );
2170 2259 } elseif ( isset( $form_options['notification']['email_to'] ) ) {
2171 - // make sure it's in the correct format
2260 + // Make sure it's in the correct format
2172 2261 $form_options['notification'] = array( 0 => $form_options['notification'] );
2173 2262 }
2174 2263
2175 2264 if ( isset( $form_options['notification'] ) && is_array( $form_options['notification'] ) ) {
@@ -2222,9 +2311,9 @@
2222 2311 $atts[ $f ] = $notification[ $f ];
2223 2312
2224 2313 if ( 'custom' === $notification[ $f ] ) {
2225 2314 $atts[ $f ] = $notification[ 'cust_' . $f ];
2226 - } elseif ( is_numeric( $atts[ $f ] ) && ! empty( $atts[ $f ] ) ) {
2315 + } elseif ( is_numeric( $atts[ $f ] ) && $atts[ $f ] ) {
2227 2316 $atts[ $f ] = '[' . $atts[ $f ] . ']';
2228 2317 }
2229 2318 }
2230 2319 unset( $f, $val );
@@ -2262,16 +2351,18 @@
2262 2351 if ( is_numeric( $email_field ) ) {
2263 2352 $atts['email_to'][ $key ] = '[' . $email_field . ']';
2264 2353 }
2265 2354
2266 - if ( str_contains( $email_field, '|' ) ) {
2267 - $email_opt = explode( '|', $email_field );
2355 + if ( ! str_contains( $email_field, '|' ) ) {
2356 + continue;
2357 + }
2268 2358
2269 - if ( isset( $email_opt[0] ) ) {
2270 - $atts['email_to'][ $key ] = '[' . $email_opt[0] . ' show=' . $email_opt[1] . ']';
2271 - }
2272 - unset( $email_opt );
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] . ']';
2273 2363 }
2364 + unset( $email_opt );
2274 2365 }
2275 2366
2276 2367 $atts['email_to'] = implode( ', ', $atts['email_to'] );
2277 2368 }
@@ -2313,9 +2404,9 @@
2313 2404 $new_notification['post_content']['reply_to'] = $atts['reply_to'];
2314 2405
2315 2406 // Set from
2316 2407 if ( ! empty( $atts['reply_to'] ) || ! empty( $atts['reply_to_name'] ) ) {
2317 - $new_notification['post_content']['from'] = ( empty( $atts['reply_to_name'] ) ? '[sitename]' : $atts['reply_to_name'] ) . ' <' . ( empty( $atts['reply_to'] ) ? '[admin_email]' : $atts['reply_to'] ) . '>'; // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
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
2318 2409 }
2319 2410 }
2320 2411
2321 2412 /**
@@ -2326,15 +2417,17 @@
2326 2417 * @return void
2327 2418 */
2328 2419 private static function switch_email_condition_field_ids( &$post_content ) {
2329 2420 // Switch field IDs in conditional logic
2330 - if ( isset( $post_content['conditions'] ) && is_array( $post_content['conditions'] ) ) {
2331 - foreach ( $post_content['conditions'] as $email_key => $val ) {
2332 - if ( is_numeric( $email_key ) ) {
2333 - $post_content['conditions'][ $email_key ] = self::switch_action_field_ids( $val, array( 'hide_field' ) );
2334 - }
2335 - 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' ) );
2336 2428 }
2429 + unset( $email_key, $val );
2337 2430 }
2338 2431 }
2339 2432
2340 2433 /**
@@ -2346,52 +2439,54 @@
2346 2439 *
2347 2440 * @return void
2348 2441 */
2349 2442 private static function migrate_autoresponder_to_action( $form_options, $form_id, &$notifications ) {
2350 - if ( ! empty( $form_options['auto_responder'] ) && ! empty( $form_options['ar_email_message'] ) ) {
2351 - // migrate autoresponder
2443 + if ( empty( $form_options['auto_responder'] ) || empty( $form_options['ar_email_message'] ) ) {
2444 + return;
2445 + }
2352 2446
2353 - $email_field = $form_options['ar_email_to'] ?? 0;
2447 + // Migrate autoresponder
2354 2448
2355 - if ( str_contains( $email_field, '|' ) ) {
2356 - // data from entries field
2357 - $email_field = explode( '|', $email_field );
2449 + $email_field = $form_options['ar_email_to'] ?? 0;
2358 2450
2359 - if ( isset( $email_field[1] ) ) {
2360 - $email_field = $email_field[1];
2361 - }
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];
2362 2457 }
2458 + }
2363 2459
2364 - if ( is_numeric( $email_field ) && $email_field ) {
2365 - $email_field = '[' . $email_field . ']';
2366 - }
2460 + if ( is_numeric( $email_field ) && $email_field ) {
2461 + $email_field = '[' . $email_field . ']';
2462 + }
2367 2463
2368 - $notification = $form_options;
2369 - $new_notification2 = array(
2370 - 'post_content' => array(
2371 - 'email_message' => $notification['ar_email_message'],
2372 - 'email_subject' => $notification['ar_email_subject'] ?? '',
2373 - 'email_to' => $email_field,
2374 - 'plain_text' => $notification['ar_plain_text'] ?? 0,
2375 - 'inc_user_info' => 0,
2376 - ),
2377 - 'post_name' => $form_id . '_email_' . count( $notifications ),
2378 - );
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 + );
2379 2475
2380 - $reply_to = $notification['ar_reply_to'] ?? '';
2381 - $reply_to_name = $notification['ar_reply_to_name'] ?? '';
2476 + $reply_to = $notification['ar_reply_to'] ?? '';
2477 + $reply_to_name = $notification['ar_reply_to_name'] ?? '';
2382 2478
2383 - if ( $reply_to ) {
2384 - $new_notification2['post_content']['reply_to'] = $reply_to;
2385 - }
2479 + if ( $reply_to ) {
2480 + $new_notification2['post_content']['reply_to'] = $reply_to;
2481 + }
2386 2482
2387 - if ( $reply_to || $reply_to_name ) {
2388 - $new_notification2['post_content']['from'] = ( empty( $reply_to_name ) ? '[sitename]' : $reply_to_name ) . ' <' . ( empty( $reply_to ) ? '[admin_email]' : $reply_to ) . '>'; // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
2389 - }
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 + }
2390 2486
2391 - $notifications[] = $new_notification2;
2392 - unset( $new_notification2 );
2393 - }//end if
2487 + $notifications[] = $new_notification2;
2488 + unset( $new_notification2 );
2394 2489 }
2395 2490
2396 2491 /**
2397 2492 * PHP 8 backward compatibility for the libxml_disable_entity_loader function