| @@ -132,13 +132,15 @@ | ||
| 132 | 132 | $imported = self::pre_import_data(); |
| 133 | 133 | |
| 134 | 134 | foreach ( array( 'term', 'form', 'view' ) as $item_type ) { |
| 135 | 135 | // Grab cats, tags, and terms, or forms or posts. |
| 136 | - if ( isset( $xml->{$item_type} ) ) { | |
| 137 | - $function_name = 'import_xml_' . $item_type . 's'; | |
| 138 | - $imported = self::$function_name( $xml->{$item_type}, $imported ); | |
| 139 | - unset( $function_name, $xml->{$item_type} ); | |
| 136 | + if ( ! isset( $xml->{$item_type} ) ) { | |
| 137 | + continue; | |
| 140 | 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} ); | |
| 141 | 143 | } |
| 142 | 144 | |
| 143 | 145 | $imported = apply_filters( 'frm_importing_xml', $imported, $xml ); |
| 144 | 146 | |
| @@ -292,8 +294,23 @@ | ||
| 292 | 294 | }//end foreach |
| 293 | 295 | |
| 294 | 296 | self::maybe_update_child_form_parent_id( $imported['forms'], $child_forms ); |
| 295 | 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 | + | |
| 296 | 313 | return $imported; |
| 297 | 314 | } |
| 298 | 315 | |
| 299 | 316 | /** |
| @@ -464,14 +481,16 @@ | ||
| 464 | 481 | * @param array $child_forms |
| 465 | 482 | */ |
| 466 | 483 | private static function maybe_update_child_form_parent_id( $imported_forms, $child_forms ) { |
| 467 | 484 | foreach ( $child_forms as $child_form_id => $old_parent_form_id ) { |
| 468 | - if ( isset( $imported_forms[ $old_parent_form_id ] ) && (int) $imported_forms[ $old_parent_form_id ] !== (int) $old_parent_form_id ) { | |
| 469 | - // Update all children with this old parent_form_id | |
| 470 | - $new_parent_form_id = (int) $imported_forms[ $old_parent_form_id ]; | |
| 471 | - FrmForm::update( $child_form_id, array( 'parent_form_id' => $new_parent_form_id ) ); | |
| 472 | - 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; | |
| 473 | 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 ); | |
| 474 | 493 | } |
| 475 | 494 | } |
| 476 | 495 | |
| 477 | 496 | /** |
| @@ -600,13 +619,40 @@ | ||
| 600 | 619 | 'field_order' => (int) $field->field_order, |
| 601 | 620 | 'form_id' => (int) $form_id, |
| 602 | 621 | 'required' => (int) $field->required, |
| 603 | 622 | 'options' => FrmAppHelper::maybe_json_decode( (string) $field->options ), |
| 604 | - 'field_options' => FrmAppHelper::maybe_json_decode( (string) $field->field_options ), | |
| 623 | + 'field_options' => self::fill_field_options( $field ), | |
| 605 | 624 | ); |
| 606 | 625 | } |
| 607 | 626 | |
| 608 | 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 | + /** | |
| 609 | 655 | * @since 4.06 |
| 610 | 656 | * |
| 611 | 657 | * @param array $f |
| 612 | 658 | * |
| @@ -1512,15 +1558,17 @@ | ||
| 1512 | 1558 | * @param array $post |
| 1513 | 1559 | * @param int $post_id |
| 1514 | 1560 | */ |
| 1515 | 1561 | private static function update_layout( &$post, $post_id ) { |
| 1516 | - if ( is_callable( 'FrmViewsLayout::maybe_create_layouts_for_view' ) ) { | |
| 1517 | - $listing_layout = ! empty( $post['layout']['listing'] ) ? json_decode( $post['layout']['listing'], true ) : array(); | |
| 1518 | - $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 | + } | |
| 1519 | 1565 | |
| 1520 | - if ( $listing_layout || $detail_layout ) { | |
| 1521 | - FrmViewsLayout::maybe_create_layouts_for_view( $post_id, $listing_layout, $detail_layout ); | |
| 1522 | - } | |
| 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 ); | |
| 1523 | 1571 | } |
| 1524 | 1572 | } |
| 1525 | 1573 | |
| 1526 | 1574 | /** |
| @@ -1558,12 +1606,11 @@ | ||
| 1558 | 1606 | $errors[] = $result->get_error_message(); |
| 1559 | 1607 | |
| 1560 | 1608 | // Remove the SimpleXML_parse_error from the WP_Error object to avoid |
| 1561 | 1609 | // displaying duplicate error messages from $result->get_error_message() |
| 1562 | - $error_codes = $result->get_error_codes(); | |
| 1563 | 1610 | $error_details = array(); |
| 1564 | 1611 | |
| 1565 | - foreach ( $error_codes as $error_code ) { | |
| 1612 | + foreach ( $result->get_error_codes() as $error_code ) { | |
| 1566 | 1613 | // Clone WP_Error data because WP_Error removes all error messages and data |
| 1567 | 1614 | // Associated with the specified error code when an item is removed. |
| 1568 | 1615 | // Source: https://developer.wordpress.org/reference/classes/wp_error/remove/#source |
| 1569 | 1616 | $error_details = $result->get_error_data( $error_code ); |
| @@ -1831,12 +1878,14 @@ | ||
| 1831 | 1878 | return; |
| 1832 | 1879 | } |
| 1833 | 1880 | |
| 1834 | 1881 | foreach ( $options as $key => $option ) { |
| 1835 | - if ( is_array( $option ) && ! empty( $option['image'] ) ) { | |
| 1836 | - $options[ $key ]['src'] = wp_get_attachment_url( $option['image'] ); | |
| 1837 | - $updated = true; | |
| 1882 | + if ( ! is_array( $option ) || empty( $option['image'] ) ) { | |
| 1883 | + continue; | |
| 1838 | 1884 | } |
| 1885 | + | |
| 1886 | + $options[ $key ]['src'] = wp_get_attachment_url( $option['image'] ); | |
| 1887 | + $updated = true; | |
| 1839 | 1888 | } |
| 1840 | 1889 | |
| 1841 | 1890 | if ( $updated ) { |
| 1842 | 1891 | $field->options = maybe_serialize( $options ); |