| @@ -1,9 +1,11 @@ | ||
| 1 | 1 | <?php |
| 2 | 2 | |
| 3 | 3 | namespace ABlocks\import; |
| 4 | 4 | |
| 5 | +use ABlocks\Admin\Settings\Base; | |
| 5 | 6 | use ABlocks\Helper; |
| 7 | +use ABlocks\Classes\GlobalClasses; | |
| 6 | 8 | use ABlocks\import\XmlParsers\WXR_Parser; |
| 7 | 9 | use WP_Error; |
| 8 | 10 | |
| 9 | 11 | if ( ! defined( 'ABSPATH' ) ) { |
| @@ -26,8 +28,12 @@ | ||
| 26 | 28 | public $base_url = ''; |
| 27 | 29 | public $show_on_front = 'posts'; |
| 28 | 30 | public $page_on_front = 0; |
| 29 | 31 | public $page_for_posts = 0; |
| 32 | + public $storeengine_pages = []; | |
| 33 | + public $academy_pages = []; | |
| 34 | + public $ablocks_pages = []; | |
| 35 | + public $ablocks_options = []; | |
| 30 | 36 | |
| 31 | 37 | public $processed_authors = array(); |
| 32 | 38 | public $author_mapping = array(); |
| 33 | 39 | public $processed_terms = array(); |
| @@ -68,8 +74,9 @@ | ||
| 68 | 74 | // update incorrect/missing information in the DB |
| 69 | 75 | $this->backfill_parents(); |
| 70 | 76 | $this->backfill_attachment_urls(); |
| 71 | 77 | $this->remap_featured_images(); |
| 78 | + $this->save_global_settings(); | |
| 72 | 79 | |
| 73 | 80 | $this->import_end(); |
| 74 | 81 | |
| 75 | 82 | return true; |
| @@ -85,9 +92,9 @@ | ||
| 85 | 92 | return new WP_Error( 'file_not_found', __( 'File not found', 'ablocks' ) ); |
| 86 | 93 | } |
| 87 | 94 | |
| 88 | 95 | Helper::emit_sse_message( [ |
| 89 | - 'action' => 'log', | |
| 96 | + 'action' => 'log', | |
| 90 | 97 | 'message' => __( 'Import process started...', 'ablocks' ) |
| 91 | 98 | ] ); |
| 92 | 99 | |
| 93 | 100 | $import_data = $this->parse( $file ); |
| @@ -97,16 +104,20 @@ | ||
| 97 | 104 | } |
| 98 | 105 | |
| 99 | 106 | $this->version = $import_data['version']; |
| 100 | 107 | $this->get_authors_from_import( $import_data ); |
| 101 | - $this->posts = $import_data['posts']; | |
| 102 | - $this->terms = $import_data['terms']; | |
| 103 | - $this->categories = $import_data['categories']; | |
| 104 | - $this->tags = $import_data['tags']; | |
| 105 | - $this->base_url = esc_url( $import_data['base_url'] ); | |
| 106 | - $this->show_on_front = $import_data['show_on_front']; | |
| 107 | - $this->page_on_front = $import_data['page_on_front']; | |
| 108 | - $this->page_for_posts = $import_data['page_for_posts']; | |
| 108 | + $this->posts = $import_data['posts']; | |
| 109 | + $this->terms = $import_data['terms']; | |
| 110 | + $this->categories = $import_data['categories']; | |
| 111 | + $this->tags = $import_data['tags']; | |
| 112 | + $this->base_url = esc_url( $import_data['base_url'] ); | |
| 113 | + $this->show_on_front = $import_data['show_on_front']; | |
| 114 | + $this->page_on_front = $import_data['page_on_front']; | |
| 115 | + $this->page_for_posts = $import_data['page_for_posts']; | |
| 116 | + $this->storeengine_pages = $import_data['storeengine_pages']; | |
| 117 | + $this->academy_pages = $import_data['academy_pages']; | |
| 118 | + $this->ablocks_pages = $import_data['ablocks_pages']; | |
| 119 | + $this->ablocks_options = $import_data['ablocks_options']; | |
| 109 | 120 | |
| 110 | 121 | wp_defer_term_counting( true ); |
| 111 | 122 | wp_defer_comment_counting( true ); |
| 112 | 123 | |
| @@ -132,10 +143,10 @@ | ||
| 132 | 143 | |
| 133 | 144 | do_action( 'ablocks/template_import_end' ); |
| 134 | 145 | |
| 135 | 146 | Helper::emit_sse_message( [ |
| 136 | - 'action' => 'log', | |
| 137 | - 'level' => 'info', | |
| 147 | + 'action' => 'log', | |
| 148 | + 'level' => 'info', | |
| 138 | 149 | 'message' => __( 'Import process Finished.', 'ablocks' ), |
| 139 | 150 | ] ); |
| 140 | 151 | } |
| 141 | 152 | |
| @@ -240,10 +251,10 @@ | ||
| 240 | 251 | $this->process_termmeta( $cat, $id ); |
| 241 | 252 | }//end foreach |
| 242 | 253 | |
| 243 | 254 | Helper::emit_sse_message( [ |
| 244 | - 'action' => 'log', | |
| 245 | - 'level' => 'info', | |
| 255 | + 'action' => 'log', | |
| 256 | + 'level' => 'info', | |
| 246 | 257 | 'message' => __( 'Categories imported', 'ablocks' ), |
| 247 | 258 | ] ); |
| 248 | 259 | |
| 249 | 260 | unset( $this->categories ); |
| @@ -292,10 +303,10 @@ | ||
| 292 | 303 | $this->process_termmeta( $tag, $id['term_id'] ); |
| 293 | 304 | }//end foreach |
| 294 | 305 | |
| 295 | 306 | Helper::emit_sse_message( [ |
| 296 | - 'action' => 'log', | |
| 297 | - 'level' => 'info', | |
| 307 | + 'action' => 'log', | |
| 308 | + 'level' => 'info', | |
| 298 | 309 | 'message' => __( 'Tags imported', 'ablocks' ), |
| 299 | 310 | ] ); |
| 300 | 311 | |
| 301 | 312 | unset( $this->tags ); |
| @@ -354,10 +365,10 @@ | ||
| 354 | 365 | $this->process_termmeta( $term, $id['term_id'] ); |
| 355 | 366 | }//end foreach |
| 356 | 367 | |
| 357 | 368 | Helper::emit_sse_message( [ |
| 358 | - 'action' => 'log', | |
| 359 | - 'level' => 'info', | |
| 369 | + 'action' => 'log', | |
| 370 | + 'level' => 'info', | |
| 360 | 371 | 'message' => __( 'Terms imported', 'ablocks' ), |
| 361 | 372 | ] ); |
| 362 | 373 | |
| 363 | 374 | unset( $this->terms ); |
| @@ -455,12 +466,15 @@ | ||
| 455 | 466 | $this->process_menu_item( $post ); |
| 456 | 467 | continue; |
| 457 | 468 | } |
| 458 | 469 | |
| 459 | - $post_type_object = get_post_type_object( $post['post_type'] ); | |
| 470 | + $post_exists = post_exists( $post['post_title'], '', '', $post['post_type'] ); | |
| 471 | + if ( $post_exists && in_array( $post['post_type'], [ 'wp_template', 'wp_template_part' ], true ) ) { | |
| 472 | + // remove existence template. | |
| 473 | + wp_delete_post( $post_exists, true ); | |
| 474 | + $post_exists = false; | |
| 475 | + } | |
| 460 | 476 | |
| 461 | - $post_exists = post_exists( $post['post_title'], '', $post['post_date'], $post['post_type'] ); | |
| 462 | - | |
| 463 | 477 | /** |
| 464 | 478 | * Filter ID of the existing post corresponding to post currently importing. |
| 465 | 479 | * |
| 466 | 480 | * Return 0 to force the post to be imported. Filter the ID to be something else |
| @@ -473,9 +487,9 @@ | ||
| 473 | 487 | * @since 0.6.2 |
| 474 | 488 | */ |
| 475 | 489 | $post_exists = apply_filters( 'ablocks/template_import_existing_post', $post_exists, $post ); |
| 476 | 490 | |
| 477 | - if ( $post_exists && get_post_type( $post_exists ) === $post['post_type'] ) { | |
| 491 | + if ( ! $this->check_for_known_page( $post ) && $post_exists ) { | |
| 478 | 492 | $comment_post_id = $post_exists; |
| 479 | 493 | $post_id = $post_exists; |
| 480 | 494 | $this->processed_posts[ intval( $post['post_id'] ) ] = intval( $post_exists ); |
| 481 | 495 | } else { |
| @@ -527,9 +541,9 @@ | ||
| 527 | 541 | $postdata = apply_filters( 'ablocks/template_import_post_data_processed', $postdata, $post ); |
| 528 | 542 | |
| 529 | 543 | $postdata = wp_slash( $postdata ); |
| 530 | 544 | |
| 531 | - if ( 'attachment' === $postdata['post_type'] ) { | |
| 545 | + if ( 'attachment' === $postdata['post_type'] && ! $post_exists ) { | |
| 532 | 546 | if ( ! $this->fetch_attachments ) { |
| 533 | 547 | continue; |
| 534 | 548 | } |
| 535 | 549 | $remote_url = ! empty( $post['attachment_url'] ) ? $post['attachment_url'] : $post['guid']; |
| @@ -550,17 +564,21 @@ | ||
| 550 | 564 | |
| 551 | 565 | $comment_post_id = $this->process_attachment( $postdata, $remote_url ); |
| 552 | 566 | $post_id = $comment_post_id; |
| 553 | 567 | } else { |
| 554 | - $comment_post_id = wp_insert_post( $postdata, true ); | |
| 555 | - $post_id = $comment_post_id; | |
| 568 | + if ( $post_exists ) { | |
| 569 | + $comment_post_id = wp_update_post( array_merge( $postdata, array( 'ID' => $post_exists ) ) ); | |
| 570 | + } else { | |
| 571 | + $comment_post_id = wp_insert_post( $postdata, true ); | |
| 572 | + } | |
| 573 | + $post_id = $comment_post_id; | |
| 556 | 574 | do_action( 'ablocks/template_import_insert_post', $post_id, $original_post_id, $postdata, $post ); |
| 557 | 575 | }//end if |
| 558 | 576 | |
| 559 | 577 | if ( is_wp_error( $post_id ) ) { |
| 560 | 578 | Helper::emit_sse_message( [ |
| 561 | - 'action' => 'log', | |
| 562 | - 'level' => 'warning', | |
| 579 | + 'action' => 'log', | |
| 580 | + 'level' => 'warning', | |
| 563 | 581 | 'message' => "Failed to import: {$post['post_type']} - {$post['post_title']}", |
| 564 | 582 | ] ); |
| 565 | 583 | continue; |
| 566 | 584 | } |
| @@ -569,10 +587,10 @@ | ||
| 569 | 587 | stick_post( $post_id ); |
| 570 | 588 | } |
| 571 | 589 | |
| 572 | 590 | Helper::emit_sse_message( [ |
| 573 | - 'action' => 'log', | |
| 574 | - 'level' => 'info', | |
| 591 | + 'action' => 'log', | |
| 592 | + 'level' => 'info', | |
| 575 | 593 | 'message' => "{$post['post_type']} - {$post['post_title']} imported.", |
| 576 | 594 | ] ); |
| 577 | 595 | }//end if |
| 578 | 596 | |
| @@ -581,22 +599,52 @@ | ||
| 581 | 599 | update_option( 'show_on_front', 'page' ); |
| 582 | 600 | if ( $this->page_on_front === $post['post_id'] ) { |
| 583 | 601 | update_option( 'page_on_front', $post_id ); |
| 584 | 602 | Helper::emit_sse_message( [ |
| 585 | - 'action' => 'log', | |
| 586 | - 'level' => 'info', | |
| 603 | + 'action' => 'log', | |
| 604 | + 'level' => 'info', | |
| 587 | 605 | 'message' => __( 'Front page setting\'s updated.', 'ablocks' ), |
| 588 | 606 | ] ); |
| 589 | 607 | } elseif ( $post['post_id'] === $this->page_for_posts ) { |
| 590 | 608 | update_option( 'page_for_posts', $post_id ); |
| 591 | 609 | Helper::emit_sse_message( [ |
| 592 | - 'action' => 'log', | |
| 593 | - 'level' => 'info', | |
| 610 | + 'action' => 'log', | |
| 611 | + 'level' => 'info', | |
| 594 | 612 | 'message' => __( 'Posts page setting\'s updated.', 'ablocks' ), |
| 595 | 613 | ] ); |
| 596 | 614 | } |
| 597 | 615 | }//end if |
| 598 | 616 | |
| 617 | + // update storeengine page settings | |
| 618 | + if ( ! empty( $this->storeengine_pages ) && class_exists( 'StoreEngine' ) ) { | |
| 619 | + $se_page = array_search( $post['post_id'], $this->storeengine_pages, true ); | |
| 620 | + if ( $se_page ) { | |
| 621 | + \StoreEngine\Admin\Settings\Base::save_settings( [ | |
| 622 | + $se_page => $post_id | |
| 623 | + ] ); | |
| 624 | + } | |
| 625 | + } | |
| 626 | + | |
| 627 | + // update academy page settings | |
| 628 | + if ( ! empty( $this->academy_pages ) && class_exists( 'Academy' ) ) { | |
| 629 | + $academy_page = array_search( $post['post_id'], $this->academy_pages, true ); | |
| 630 | + if ( $academy_page ) { | |
| 631 | + \Academy\Admin\Settings\Base::save_settings( [ | |
| 632 | + $academy_page => $post_id | |
| 633 | + ] ); | |
| 634 | + } | |
| 635 | + } | |
| 636 | + | |
| 637 | + // update ablock page settings | |
| 638 | + if ( ! empty( $this->ablocks_pages ) ) { | |
| 639 | + $ablocks_page = array_search( $post['post_id'], $this->ablocks_pages, true ); | |
| 640 | + if ( $ablocks_page ) { | |
| 641 | + Base::save_settings( [ | |
| 642 | + $ablocks_page => $post_id | |
| 643 | + ] ); | |
| 644 | + } | |
| 645 | + } | |
| 646 | + | |
| 599 | 647 | // map pre-import ID to local ID |
| 600 | 648 | $this->processed_posts[ intval( $post['post_id'] ) ] = (int) $post_id; |
| 601 | 649 | |
| 602 | 650 | if ( ! isset( $post['terms'] ) ) { |
| @@ -609,9 +657,9 @@ | ||
| 609 | 657 | if ( ! empty( $post['terms'] ) ) { |
| 610 | 658 | $terms_to_set = array(); |
| 611 | 659 | foreach ( $post['terms'] as $term ) { |
| 612 | 660 | // back compat with WXR 1.0 map 'tag' to 'post_tag' |
| 613 | - $taxonomy = ( 'tag' === $term['domain'] ) ? 'post_tag' : $term['domain']; | |
| 661 | + $taxonomy = ( 'tag' === $term['domain'] ) ? 'post_tag' : $term['domain']; | |
| 614 | 662 | if ( 'wp_theme' === $taxonomy ) { |
| 615 | 663 | $term['name'] = wp_get_theme()->get_stylesheet(); |
| 616 | 664 | $term['slug'] = wp_get_theme()->get_stylesheet(); |
| 617 | 665 | } |
| @@ -748,14 +796,30 @@ | ||
| 748 | 796 | foreach ( $styles as $style ) { |
| 749 | 797 | wp_delete_post( $style ); |
| 750 | 798 | } |
| 751 | 799 | Helper::emit_sse_message( [ |
| 752 | - 'action' => 'log', | |
| 753 | - 'level' => 'info', | |
| 800 | + 'action' => 'log', | |
| 801 | + 'level' => 'info', | |
| 754 | 802 | 'message' => __( 'Existence gutenberg styles removed.', 'ablocks' ), |
| 755 | 803 | ] ); |
| 756 | 804 | } |
| 757 | 805 | |
| 806 | + private function check_for_known_page( array $post ) { | |
| 807 | + if ( ! empty( $this->storeengine_pages ) && class_exists( 'StoreEngine' ) ) { | |
| 808 | + return (bool) array_search( $post['post_id'], $this->storeengine_pages, true ); | |
| 809 | + } | |
| 810 | + | |
| 811 | + if ( ! empty( $this->academy_pages ) && class_exists( 'Academy' ) ) { | |
| 812 | + return (bool) array_search( $post['post_id'], $this->academy_pages, true ); | |
| 813 | + } | |
| 814 | + | |
| 815 | + if ( ! empty( $this->ablocks_pages ) ) { | |
| 816 | + return (bool) array_search( $post['post_id'], $this->ablocks_pages, true ); | |
| 817 | + } | |
| 818 | + | |
| 819 | + return false; | |
| 820 | + } | |
| 821 | + | |
| 758 | 822 | /** |
| 759 | 823 | * Attempt to create a new menu item from import data |
| 760 | 824 | * |
| 761 | 825 | * Fails for draft, orphaned menu items and those without an associated nav_menu |
| @@ -932,9 +996,9 @@ | ||
| 932 | 996 | ) |
| 933 | 997 | ); |
| 934 | 998 | |
| 935 | 999 | if ( is_wp_error( $remote_response ) ) { |
| 936 | - // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged | |
| 1000 | + // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged, WordPress.WP.AlternativeFunctions.unlink_unlink | |
| 937 | 1001 | @unlink( $tmp_file_name ); |
| 938 | 1002 | |
| 939 | 1003 | return new WP_Error( |
| 940 | 1004 | 'import_file_error', |
| @@ -951,8 +1015,9 @@ | ||
| 951 | 1015 | |
| 952 | 1016 | // Make sure the fetch was successful. |
| 953 | 1017 | if ( 200 !== $remote_response_code ) { |
| 954 | 1018 | if ( file_exists( $tmp_file_name ) ) { |
| 1019 | + // phpcs:ignore WordPress.WP.AlternativeFunctions.unlink_unlink | |
| 955 | 1020 | unlink( $tmp_file_name ); |
| 956 | 1021 | } |
| 957 | 1022 | |
| 958 | 1023 | return new WP_Error( |
| @@ -970,8 +1035,9 @@ | ||
| 970 | 1035 | |
| 971 | 1036 | // Request failed. |
| 972 | 1037 | if ( ! $headers ) { |
| 973 | 1038 | if ( file_exists( $tmp_file_name ) ) { |
| 1039 | + // phpcs:ignore WordPress.WP.AlternativeFunctions.unlink_unlink | |
| 974 | 1040 | unlink( $tmp_file_name ); |
| 975 | 1041 | } |
| 976 | 1042 | |
| 977 | 1043 | return new WP_Error( 'import_file_error', __( 'Remote server did not respond', 'ablocks' ) ); |
| @@ -980,8 +1046,9 @@ | ||
| 980 | 1046 | $filesize = (int) filesize( $tmp_file_name ); |
| 981 | 1047 | |
| 982 | 1048 | if ( 0 === $filesize ) { |
| 983 | 1049 | if ( file_exists( $tmp_file_name ) ) { |
| 1050 | + // phpcs:ignore WordPress.WP.AlternativeFunctions.unlink_unlink | |
| 984 | 1051 | unlink( $tmp_file_name ); |
| 985 | 1052 | } |
| 986 | 1053 | |
| 987 | 1054 | return new WP_Error( 'import_file_error', __( 'Zero size file downloaded', 'ablocks' ) ); |
| @@ -988,8 +1055,9 @@ | ||
| 988 | 1055 | } |
| 989 | 1056 | |
| 990 | 1057 | if ( ! isset( $headers['content-encoding'] ) && isset( $headers['content-length'] ) && $filesize !== (int) $headers['content-length'] ) { |
| 991 | 1058 | if ( file_exists( $tmp_file_name ) ) { |
| 1059 | + // phpcs:ignore WordPress.WP.AlternativeFunctions.unlink_unlink | |
| 992 | 1060 | unlink( $tmp_file_name ); |
| 993 | 1061 | } |
| 994 | 1062 | |
| 995 | 1063 | return new WP_Error( 'import_file_error', __( 'Downloaded file has incorrect size', 'ablocks' ) ); |
| @@ -997,8 +1065,9 @@ | ||
| 997 | 1065 | |
| 998 | 1066 | $max_size = (int) $this->max_attachment_size(); |
| 999 | 1067 | if ( ! empty( $max_size ) && $filesize > $max_size ) { |
| 1000 | 1068 | if ( file_exists( $tmp_file_name ) ) { |
| 1069 | + // phpcs:ignore WordPress.WP.AlternativeFunctions.unlink_unlink | |
| 1001 | 1070 | unlink( $tmp_file_name ); |
| 1002 | 1071 | } |
| 1003 | 1072 | |
| 1004 | 1073 | // Translators: %s is the file size limit for the remote file import |
| @@ -1048,8 +1117,9 @@ | ||
| 1048 | 1117 | $move_new_file = copy( $tmp_file_name, $new_file ); |
| 1049 | 1118 | |
| 1050 | 1119 | if ( ! $move_new_file ) { |
| 1051 | 1120 | if ( file_exists( $tmp_file_name ) ) { |
| 1121 | + // phpcs:ignore WordPress.WP.AlternativeFunctions.unlink_unlink | |
| 1052 | 1122 | unlink( $tmp_file_name ); |
| 1053 | 1123 | } |
| 1054 | 1124 | |
| 1055 | 1125 | return new WP_Error( 'import_file_error', __( 'The uploaded file could not be moved', 'ablocks' ) ); |
| @@ -1057,8 +1127,9 @@ | ||
| 1057 | 1127 | |
| 1058 | 1128 | // Set correct file permissions. |
| 1059 | 1129 | $stat = stat( dirname( $new_file ) ); |
| 1060 | 1130 | $perms = $stat['mode'] & 0000666; |
| 1131 | + // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_chmod | |
| 1061 | 1132 | chmod( $new_file, $perms ); |
| 1062 | 1133 | |
| 1063 | 1134 | $upload = array( |
| 1064 | 1135 | 'file' => $new_file, |
| @@ -1099,8 +1170,9 @@ | ||
| 1099 | 1170 | $local_parent_id = $this->processed_posts[ $parent_id ]; |
| 1100 | 1171 | } |
| 1101 | 1172 | |
| 1102 | 1173 | if ( $local_child_id && $local_parent_id ) { |
| 1174 | + // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching | |
| 1103 | 1175 | $wpdb->update( $wpdb->posts, array( 'post_parent' => $local_parent_id ), array( 'ID' => $local_child_id ), '%d', '%d' ); |
| 1104 | 1176 | clean_post_cache( $local_child_id ); |
| 1105 | 1177 | } |
| 1106 | 1178 | } |
| @@ -1137,17 +1209,19 @@ | ||
| 1137 | 1209 | uksort( $this->url_remap, array( &$this, 'cmpr_strlen' ) ); |
| 1138 | 1210 | |
| 1139 | 1211 | foreach ( $this->url_remap as $from_url => $to_url ) { |
| 1140 | 1212 | // remap urls in post_content |
| 1213 | + // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching | |
| 1141 | 1214 | $wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->posts} SET post_content = REPLACE(post_content, %s, %s)", $from_url, $to_url ) ); |
| 1142 | 1215 | // remap enclosure urls |
| 1216 | + // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching | |
| 1143 | 1217 | $wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->postmeta} SET meta_value = REPLACE(meta_value, %s, %s) WHERE meta_key='enclosure'", $from_url, $to_url ) ); |
| 1144 | 1218 | } |
| 1145 | 1219 | |
| 1146 | 1220 | if ( ! empty( $this->url_remap ) ) { |
| 1147 | 1221 | Helper::emit_sse_message( [ |
| 1148 | - 'action' => 'log', | |
| 1149 | - 'level' => 'info', | |
| 1222 | + 'action' => 'log', | |
| 1223 | + 'level' => 'info', | |
| 1150 | 1224 | 'message' => __( 'Old attachment URLs have been updated.', 'ablocks' ), |
| 1151 | 1225 | ] ); |
| 1152 | 1226 | } |
| 1153 | 1227 | } |
| @@ -1166,11 +1240,111 @@ | ||
| 1166 | 1240 | } |
| 1167 | 1241 | } |
| 1168 | 1242 | } |
| 1169 | 1243 | Helper::emit_sse_message( [ |
| 1170 | - 'action' => 'log', | |
| 1171 | - 'level' => 'info', | |
| 1244 | + 'action' => 'log', | |
| 1245 | + 'level' => 'info', | |
| 1172 | 1246 | 'message' => __( 'Imported posts `_thumbnail_id` updated.', 'ablocks' ), |
| 1247 | + ] ); | |
| 1248 | + } | |
| 1249 | + | |
| 1250 | + public function save_global_settings() { | |
| 1251 | + if ( ! empty( $this->ablocks_options ) ) { | |
| 1252 | + $settings = $this->ablocks_options; | |
| 1253 | + if ( ! empty( $settings['frontend_dashboard_sub_pages'] ) ) { | |
| 1254 | + update_option( 'ablocks_frontend_dashboard_sub_pages', wp_json_encode( $settings['frontend_dashboard_sub_pages'] ) ); | |
| 1255 | + unset( $settings['frontend_dashboard_sub_pages'] ); | |
| 1256 | + } | |
| 1257 | + | |
| 1258 | + if ( isset( $settings['global_classes'] ) ) { | |
| 1259 | + $this->import_global_classes( $settings['global_classes'] ); | |
| 1260 | + unset( $settings['global_classes'] ); | |
| 1261 | + } | |
| 1262 | + | |
| 1263 | + Base::save_settings( $settings ); | |
| 1264 | + } | |
| 1265 | + } | |
| 1266 | + | |
| 1267 | + /** | |
| 1268 | + * Sanitise one imported class record. | |
| 1269 | + * | |
| 1270 | + * The file is untrusted input, so a record gets the same treatment | |
| 1271 | + * GlobalClasses::upsert() gives one saved from the editor: the id through | |
| 1272 | + * `sanitize_html_class` so it cannot escape the selector it is written | |
| 1273 | + * into, and the legacy raw `css` declaration string stripped of braces and | |
| 1274 | + * angle brackets so it cannot close its own rule and open another. | |
| 1275 | + * | |
| 1276 | + * @param array $class One record from the imported library. | |
| 1277 | + * @return array The sanitised record. | |
| 1278 | + */ | |
| 1279 | + private function sanitize_global_class( $class ) { | |
| 1280 | + $clean = [ | |
| 1281 | + 'id' => sanitize_html_class( $class['id'] ), | |
| 1282 | + 'label' => isset( $class['label'] ) ? sanitize_text_field( $class['label'] ) : '', | |
| 1283 | + ]; | |
| 1284 | + | |
| 1285 | + if ( isset( $class['styles'] ) && is_array( $class['styles'] ) ) { | |
| 1286 | + // Structured buckets are compiled through the styles schema, which | |
| 1287 | + // only emits properties it knows, so they need no extra stripping. | |
| 1288 | + $clean['styles'] = $class['styles']; | |
| 1289 | + } elseif ( isset( $class['css'] ) ) { | |
| 1290 | + $clean['css'] = trim( preg_replace( '/[{}<>]/', '', (string) $class['css'] ) ); | |
| 1291 | + } | |
| 1292 | + | |
| 1293 | + return $clean; | |
| 1294 | + } | |
| 1295 | + | |
| 1296 | + /** | |
| 1297 | + * Merge the imported global-class library into this site's. | |
| 1298 | + * | |
| 1299 | + * A class already on this site wins: overwriting it would silently restyle | |
| 1300 | + * blocks that are already published here, which is a worse surprise than an | |
| 1301 | + * imported block keeping the local definition of a class it names. Skipped | |
| 1302 | + * ids are reported so the collision is visible rather than guessed at. | |
| 1303 | + * | |
| 1304 | + * @param array $incoming Class records from the imported file. | |
| 1305 | + */ | |
| 1306 | + private function import_global_classes( $incoming ) { | |
| 1307 | + if ( ! is_array( $incoming ) || empty( $incoming ) ) { | |
| 1308 | + return; | |
| 1309 | + } | |
| 1310 | + | |
| 1311 | + $existing = GlobalClasses::get_all(); | |
| 1312 | + $known = []; | |
| 1313 | + foreach ( $existing as $class ) { | |
| 1314 | + if ( ! empty( $class['id'] ) ) { | |
| 1315 | + $known[ $class['id'] ] = true; | |
| 1316 | + } | |
| 1317 | + } | |
| 1318 | + | |
| 1319 | + $added = []; | |
| 1320 | + $skipped = []; | |
| 1321 | + foreach ( $incoming as $class ) { | |
| 1322 | + if ( empty( $class['id'] ) || '' === sanitize_html_class( $class['id'] ) ) { | |
| 1323 | + continue; | |
| 1324 | + } | |
| 1325 | + if ( isset( $known[ $class['id'] ] ) ) { | |
| 1326 | + $skipped[] = $class['id']; | |
| 1327 | + continue; | |
| 1328 | + } | |
| 1329 | + $existing[] = $this->sanitize_global_class( $class ); | |
| 1330 | + $added[] = $class['id']; | |
| 1331 | + } | |
| 1332 | + | |
| 1333 | + if ( ! empty( $added ) ) { | |
| 1334 | + update_option( 'ablocks_global_classes', wp_json_encode( array_values( $existing ) ), false ); | |
| 1335 | + GlobalClasses::bump_revision(); | |
| 1336 | + } | |
| 1337 | + | |
| 1338 | + Helper::emit_sse_message( [ | |
| 1339 | + 'action' => 'log', | |
| 1340 | + 'level' => 'info', | |
| 1341 | + 'message' => sprintf( | |
| 1342 | + /* translators: 1: number of imported global classes, 2: number skipped because the id already existed. */ | |
| 1343 | + __( 'Global classes: %1$d imported, %2$d skipped (id already in use).', 'ablocks' ), | |
| 1344 | + count( $added ), | |
| 1345 | + count( $skipped ) | |
| 1346 | + ), | |
| 1173 | 1347 | ] ); |
| 1174 | 1348 | } |
| 1175 | 1349 | |
| 1176 | 1350 | /** |