PluginProbe
aBlocks – Gutenberg Blocks, User Dashboard Builder, Popup Builder, Form Builder & Animation Builder / 2.14.0
aBlocks – Gutenberg Blocks, User Dashboard Builder, Popup Builder, Form Builder & Animation Builder v2.14.0
2.14.0 2.13.0 2.13.1 2.12.0 2.11.1 2.11.0 2.10.0 2.9.0 2.7.4 2.7.5 2.7.6 2.7.7 2.8.0 2.8.1 2.9.1 trunk 1.0 1.0-beta1 1.0-beta2 1.0-beta3 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 All 81 releases
← All changes | includes/import/wp-import.php +214 -40 2.9.1 → 2.14.0 View file →
@@ -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 /**