1 <?php |
|
2 /* |
|
3 Plugin Name: WordPress Importer |
|
4 Plugin URI: https://wordpress.org/plugins/wordpress-importer/ |
|
5 Description: Import posts, pages, comments, custom fields, categories, tags and more from a WordPress export file. |
|
6 Author: wordpressdotorg |
|
7 Author URI: https://wordpress.org/ |
|
8 Version: 0.6.4 |
|
9 Text Domain: wordpress-importer |
|
10 License: GPL version 2 or later - http://www.gnu.org/licenses/old-licenses/gpl-2.0.html |
|
11 */ |
|
12 |
|
13 if ( ! defined( 'WP_LOAD_IMPORTERS' ) ) |
|
14 return; |
|
15 |
|
16 /** Display verbose errors */ |
|
17 define( 'IMPORT_DEBUG', false ); |
|
18 |
|
19 // Load Importer API |
|
20 require_once ABSPATH . 'wp-admin/includes/import.php'; |
|
21 |
|
22 if ( ! class_exists( 'WP_Importer' ) ) { |
|
23 $class_wp_importer = ABSPATH . 'wp-admin/includes/class-wp-importer.php'; |
|
24 if ( file_exists( $class_wp_importer ) ) |
|
25 require $class_wp_importer; |
|
26 } |
|
27 |
|
28 // include WXR file parsers |
|
29 require dirname( __FILE__ ) . '/parsers.php'; |
|
30 |
|
31 /** |
|
32 * WordPress Importer class for managing the import process of a WXR file |
|
33 * |
|
34 * @package WordPress |
|
35 * @subpackage Importer |
|
36 */ |
|
37 if ( class_exists( 'WP_Importer' ) ) { |
|
38 class WP_Import extends WP_Importer { |
|
39 var $max_wxr_version = 1.2; // max. supported WXR version |
|
40 |
|
41 var $id; // WXR attachment ID |
|
42 |
|
43 // information to import from WXR file |
|
44 var $version; |
|
45 var $authors = array(); |
|
46 var $posts = array(); |
|
47 var $terms = array(); |
|
48 var $categories = array(); |
|
49 var $tags = array(); |
|
50 var $base_url = ''; |
|
51 |
|
52 // mappings from old information to new |
|
53 var $processed_authors = array(); |
|
54 var $author_mapping = array(); |
|
55 var $processed_terms = array(); |
|
56 var $processed_posts = array(); |
|
57 var $post_orphans = array(); |
|
58 var $processed_menu_items = array(); |
|
59 var $menu_item_orphans = array(); |
|
60 var $missing_menu_items = array(); |
|
61 |
|
62 var $fetch_attachments = false; |
|
63 var $url_remap = array(); |
|
64 var $featured_images = array(); |
|
65 |
|
66 /** |
|
67 * Registered callback function for the WordPress Importer |
|
68 * |
|
69 * Manages the three separate stages of the WXR import process |
|
70 */ |
|
71 function dispatch() { |
|
72 $this->header(); |
|
73 |
|
74 $step = empty( $_GET['step'] ) ? 0 : (int) $_GET['step']; |
|
75 switch ( $step ) { |
|
76 case 0: |
|
77 $this->greet(); |
|
78 break; |
|
79 case 1: |
|
80 check_admin_referer( 'import-upload' ); |
|
81 if ( $this->handle_upload() ) |
|
82 $this->import_options(); |
|
83 break; |
|
84 case 2: |
|
85 check_admin_referer( 'import-wordpress' ); |
|
86 $this->fetch_attachments = ( ! empty( $_POST['fetch_attachments'] ) && $this->allow_fetch_attachments() ); |
|
87 $this->id = (int) $_POST['import_id']; |
|
88 $file = get_attached_file( $this->id ); |
|
89 set_time_limit(0); |
|
90 $this->import( $file ); |
|
91 break; |
|
92 } |
|
93 |
|
94 $this->footer(); |
|
95 } |
|
96 |
|
97 /** |
|
98 * The main controller for the actual import stage. |
|
99 * |
|
100 * @param string $file Path to the WXR file for importing |
|
101 */ |
|
102 function import( $file ) { |
|
103 add_filter( 'import_post_meta_key', array( $this, 'is_valid_meta_key' ) ); |
|
104 add_filter( 'http_request_timeout', array( &$this, 'bump_request_timeout' ) ); |
|
105 |
|
106 $this->import_start( $file ); |
|
107 |
|
108 $this->get_author_mapping(); |
|
109 |
|
110 wp_suspend_cache_invalidation( true ); |
|
111 $this->process_categories(); |
|
112 $this->process_tags(); |
|
113 $this->process_terms(); |
|
114 $this->process_posts(); |
|
115 wp_suspend_cache_invalidation( false ); |
|
116 |
|
117 // update incorrect/missing information in the DB |
|
118 $this->backfill_parents(); |
|
119 $this->backfill_attachment_urls(); |
|
120 $this->remap_featured_images(); |
|
121 |
|
122 $this->import_end(); |
|
123 } |
|
124 |
|
125 /** |
|
126 * Parses the WXR file and prepares us for the task of processing parsed data |
|
127 * |
|
128 * @param string $file Path to the WXR file for importing |
|
129 */ |
|
130 function import_start( $file ) { |
|
131 if ( ! is_file($file) ) { |
|
132 echo '<p><strong>' . __( 'Sorry, there has been an error.', 'wordpress-importer' ) . '</strong><br />'; |
|
133 echo __( 'The file does not exist, please try again.', 'wordpress-importer' ) . '</p>'; |
|
134 $this->footer(); |
|
135 die(); |
|
136 } |
|
137 |
|
138 $import_data = $this->parse( $file ); |
|
139 |
|
140 if ( is_wp_error( $import_data ) ) { |
|
141 echo '<p><strong>' . __( 'Sorry, there has been an error.', 'wordpress-importer' ) . '</strong><br />'; |
|
142 echo esc_html( $import_data->get_error_message() ) . '</p>'; |
|
143 $this->footer(); |
|
144 die(); |
|
145 } |
|
146 |
|
147 $this->version = $import_data['version']; |
|
148 $this->get_authors_from_import( $import_data ); |
|
149 $this->posts = $import_data['posts']; |
|
150 $this->terms = $import_data['terms']; |
|
151 $this->categories = $import_data['categories']; |
|
152 $this->tags = $import_data['tags']; |
|
153 $this->base_url = esc_url( $import_data['base_url'] ); |
|
154 |
|
155 wp_defer_term_counting( true ); |
|
156 wp_defer_comment_counting( true ); |
|
157 |
|
158 do_action( 'import_start' ); |
|
159 } |
|
160 |
|
161 /** |
|
162 * Performs post-import cleanup of files and the cache |
|
163 */ |
|
164 function import_end() { |
|
165 wp_import_cleanup( $this->id ); |
|
166 |
|
167 wp_cache_flush(); |
|
168 foreach ( get_taxonomies() as $tax ) { |
|
169 delete_option( "{$tax}_children" ); |
|
170 _get_term_hierarchy( $tax ); |
|
171 } |
|
172 |
|
173 wp_defer_term_counting( false ); |
|
174 wp_defer_comment_counting( false ); |
|
175 |
|
176 echo '<p>' . __( 'All done.', 'wordpress-importer' ) . ' <a href="' . admin_url() . '">' . __( 'Have fun!', 'wordpress-importer' ) . '</a>' . '</p>'; |
|
177 echo '<p>' . __( 'Remember to update the passwords and roles of imported users.', 'wordpress-importer' ) . '</p>'; |
|
178 |
|
179 do_action( 'import_end' ); |
|
180 } |
|
181 |
|
182 /** |
|
183 * Handles the WXR upload and initial parsing of the file to prepare for |
|
184 * displaying author import options |
|
185 * |
|
186 * @return bool False if error uploading or invalid file, true otherwise |
|
187 */ |
|
188 function handle_upload() { |
|
189 $file = wp_import_handle_upload(); |
|
190 |
|
191 if ( isset( $file['error'] ) ) { |
|
192 echo '<p><strong>' . __( 'Sorry, there has been an error.', 'wordpress-importer' ) . '</strong><br />'; |
|
193 echo esc_html( $file['error'] ) . '</p>'; |
|
194 return false; |
|
195 } else if ( ! file_exists( $file['file'] ) ) { |
|
196 echo '<p><strong>' . __( 'Sorry, there has been an error.', 'wordpress-importer' ) . '</strong><br />'; |
|
197 printf( __( 'The export file could not be found at <code>%s</code>. It is likely that this was caused by a permissions problem.', 'wordpress-importer' ), esc_html( $file['file'] ) ); |
|
198 echo '</p>'; |
|
199 return false; |
|
200 } |
|
201 |
|
202 $this->id = (int) $file['id']; |
|
203 $import_data = $this->parse( $file['file'] ); |
|
204 if ( is_wp_error( $import_data ) ) { |
|
205 echo '<p><strong>' . __( 'Sorry, there has been an error.', 'wordpress-importer' ) . '</strong><br />'; |
|
206 echo esc_html( $import_data->get_error_message() ) . '</p>'; |
|
207 return false; |
|
208 } |
|
209 |
|
210 $this->version = $import_data['version']; |
|
211 if ( $this->version > $this->max_wxr_version ) { |
|
212 echo '<div class="error"><p><strong>'; |
|
213 printf( __( 'This WXR file (version %s) may not be supported by this version of the importer. Please consider updating.', 'wordpress-importer' ), esc_html($import_data['version']) ); |
|
214 echo '</strong></p></div>'; |
|
215 } |
|
216 |
|
217 $this->get_authors_from_import( $import_data ); |
|
218 |
|
219 return true; |
|
220 } |
|
221 |
|
222 /** |
|
223 * Retrieve authors from parsed WXR data |
|
224 * |
|
225 * Uses the provided author information from WXR 1.1 files |
|
226 * or extracts info from each post for WXR 1.0 files |
|
227 * |
|
228 * @param array $import_data Data returned by a WXR parser |
|
229 */ |
|
230 function get_authors_from_import( $import_data ) { |
|
231 if ( ! empty( $import_data['authors'] ) ) { |
|
232 $this->authors = $import_data['authors']; |
|
233 // no author information, grab it from the posts |
|
234 } else { |
|
235 foreach ( $import_data['posts'] as $post ) { |
|
236 $login = sanitize_user( $post['post_author'], true ); |
|
237 if ( empty( $login ) ) { |
|
238 printf( __( 'Failed to import author %s. Their posts will be attributed to the current user.', 'wordpress-importer' ), esc_html( $post['post_author'] ) ); |
|
239 echo '<br />'; |
|
240 continue; |
|
241 } |
|
242 |
|
243 if ( ! isset($this->authors[$login]) ) |
|
244 $this->authors[$login] = array( |
|
245 'author_login' => $login, |
|
246 'author_display_name' => $post['post_author'] |
|
247 ); |
|
248 } |
|
249 } |
|
250 } |
|
251 |
|
252 /** |
|
253 * Display pre-import options, author importing/mapping and option to |
|
254 * fetch attachments |
|
255 */ |
|
256 function import_options() { |
|
257 $j = 0; |
|
258 ?> |
|
259 <form action="<?php echo admin_url( 'admin.php?import=wordpress&step=2' ); ?>" method="post"> |
|
260 <?php wp_nonce_field( 'import-wordpress' ); ?> |
|
261 <input type="hidden" name="import_id" value="<?php echo $this->id; ?>" /> |
|
262 |
|
263 <?php if ( ! empty( $this->authors ) ) : ?> |
|
264 <h3><?php _e( 'Assign Authors', 'wordpress-importer' ); ?></h3> |
|
265 <p><?php _e( 'To make it easier for you to edit and save the imported content, you may want to reassign the author of the imported item to an existing user of this site. For example, you may want to import all the entries as <code>admin</code>s entries.', 'wordpress-importer' ); ?></p> |
|
266 <?php if ( $this->allow_create_users() ) : ?> |
|
267 <p><?php printf( __( 'If a new user is created by WordPress, a new password will be randomly generated and the new user’s role will be set as %s. Manually changing the new user’s details will be necessary.', 'wordpress-importer' ), esc_html( get_option('default_role') ) ); ?></p> |
|
268 <?php endif; ?> |
|
269 <ol id="authors"> |
|
270 <?php foreach ( $this->authors as $author ) : ?> |
|
271 <li><?php $this->author_select( $j++, $author ); ?></li> |
|
272 <?php endforeach; ?> |
|
273 </ol> |
|
274 <?php endif; ?> |
|
275 |
|
276 <?php if ( $this->allow_fetch_attachments() ) : ?> |
|
277 <h3><?php _e( 'Import Attachments', 'wordpress-importer' ); ?></h3> |
|
278 <p> |
|
279 <input type="checkbox" value="1" name="fetch_attachments" id="import-attachments" /> |
|
280 <label for="import-attachments"><?php _e( 'Download and import file attachments', 'wordpress-importer' ); ?></label> |
|
281 </p> |
|
282 <?php endif; ?> |
|
283 |
|
284 <p class="submit"><input type="submit" class="button" value="<?php esc_attr_e( 'Submit', 'wordpress-importer' ); ?>" /></p> |
|
285 </form> |
|
286 <?php |
|
287 } |
|
288 |
|
289 /** |
|
290 * Display import options for an individual author. That is, either create |
|
291 * a new user based on import info or map to an existing user |
|
292 * |
|
293 * @param int $n Index for each author in the form |
|
294 * @param array $author Author information, e.g. login, display name, email |
|
295 */ |
|
296 function author_select( $n, $author ) { |
|
297 _e( 'Import author:', 'wordpress-importer' ); |
|
298 echo ' <strong>' . esc_html( $author['author_display_name'] ); |
|
299 if ( $this->version != '1.0' ) echo ' (' . esc_html( $author['author_login'] ) . ')'; |
|
300 echo '</strong><br />'; |
|
301 |
|
302 if ( $this->version != '1.0' ) |
|
303 echo '<div style="margin-left:18px">'; |
|
304 |
|
305 $create_users = $this->allow_create_users(); |
|
306 if ( $create_users ) { |
|
307 if ( $this->version != '1.0' ) { |
|
308 _e( 'or create new user with login name:', 'wordpress-importer' ); |
|
309 $value = ''; |
|
310 } else { |
|
311 _e( 'as a new user:', 'wordpress-importer' ); |
|
312 $value = esc_attr( sanitize_user( $author['author_login'], true ) ); |
|
313 } |
|
314 |
|
315 echo ' <input type="text" name="user_new['.$n.']" value="'. $value .'" /><br />'; |
|
316 } |
|
317 |
|
318 if ( ! $create_users && $this->version == '1.0' ) |
|
319 _e( 'assign posts to an existing user:', 'wordpress-importer' ); |
|
320 else |
|
321 _e( 'or assign posts to an existing user:', 'wordpress-importer' ); |
|
322 wp_dropdown_users( array( 'name' => "user_map[$n]", 'multi' => true, 'show_option_all' => __( '- Select -', 'wordpress-importer' ) ) ); |
|
323 echo '<input type="hidden" name="imported_authors['.$n.']" value="' . esc_attr( $author['author_login'] ) . '" />'; |
|
324 |
|
325 if ( $this->version != '1.0' ) |
|
326 echo '</div>'; |
|
327 } |
|
328 |
|
329 /** |
|
330 * Map old author logins to local user IDs based on decisions made |
|
331 * in import options form. Can map to an existing user, create a new user |
|
332 * or falls back to the current user in case of error with either of the previous |
|
333 */ |
|
334 function get_author_mapping() { |
|
335 if ( ! isset( $_POST['imported_authors'] ) ) |
|
336 return; |
|
337 |
|
338 $create_users = $this->allow_create_users(); |
|
339 |
|
340 foreach ( (array) $_POST['imported_authors'] as $i => $old_login ) { |
|
341 // Multisite adds strtolower to sanitize_user. Need to sanitize here to stop breakage in process_posts. |
|
342 $santized_old_login = sanitize_user( $old_login, true ); |
|
343 $old_id = isset( $this->authors[$old_login]['author_id'] ) ? intval($this->authors[$old_login]['author_id']) : false; |
|
344 |
|
345 if ( ! empty( $_POST['user_map'][$i] ) ) { |
|
346 $user = get_userdata( intval($_POST['user_map'][$i]) ); |
|
347 if ( isset( $user->ID ) ) { |
|
348 if ( $old_id ) |
|
349 $this->processed_authors[$old_id] = $user->ID; |
|
350 $this->author_mapping[$santized_old_login] = $user->ID; |
|
351 } |
|
352 } else if ( $create_users ) { |
|
353 if ( ! empty($_POST['user_new'][$i]) ) { |
|
354 $user_id = wp_create_user( $_POST['user_new'][$i], wp_generate_password() ); |
|
355 } else if ( $this->version != '1.0' ) { |
|
356 $user_data = array( |
|
357 'user_login' => $old_login, |
|
358 'user_pass' => wp_generate_password(), |
|
359 'user_email' => isset( $this->authors[$old_login]['author_email'] ) ? $this->authors[$old_login]['author_email'] : '', |
|
360 'display_name' => $this->authors[$old_login]['author_display_name'], |
|
361 'first_name' => isset( $this->authors[$old_login]['author_first_name'] ) ? $this->authors[$old_login]['author_first_name'] : '', |
|
362 'last_name' => isset( $this->authors[$old_login]['author_last_name'] ) ? $this->authors[$old_login]['author_last_name'] : '', |
|
363 ); |
|
364 $user_id = wp_insert_user( $user_data ); |
|
365 } |
|
366 |
|
367 if ( ! is_wp_error( $user_id ) ) { |
|
368 if ( $old_id ) |
|
369 $this->processed_authors[$old_id] = $user_id; |
|
370 $this->author_mapping[$santized_old_login] = $user_id; |
|
371 } else { |
|
372 printf( __( 'Failed to create new user for %s. Their posts will be attributed to the current user.', 'wordpress-importer' ), esc_html($this->authors[$old_login]['author_display_name']) ); |
|
373 if ( defined('IMPORT_DEBUG') && IMPORT_DEBUG ) |
|
374 echo ' ' . $user_id->get_error_message(); |
|
375 echo '<br />'; |
|
376 } |
|
377 } |
|
378 |
|
379 // failsafe: if the user_id was invalid, default to the current user |
|
380 if ( ! isset( $this->author_mapping[$santized_old_login] ) ) { |
|
381 if ( $old_id ) |
|
382 $this->processed_authors[$old_id] = (int) get_current_user_id(); |
|
383 $this->author_mapping[$santized_old_login] = (int) get_current_user_id(); |
|
384 } |
|
385 } |
|
386 } |
|
387 |
|
388 /** |
|
389 * Create new categories based on import information |
|
390 * |
|
391 * Doesn't create a new category if its slug already exists |
|
392 */ |
|
393 function process_categories() { |
|
394 $this->categories = apply_filters( 'wp_import_categories', $this->categories ); |
|
395 |
|
396 if ( empty( $this->categories ) ) |
|
397 return; |
|
398 |
|
399 foreach ( $this->categories as $cat ) { |
|
400 // if the category already exists leave it alone |
|
401 $term_id = term_exists( $cat['category_nicename'], 'category' ); |
|
402 if ( $term_id ) { |
|
403 if ( is_array($term_id) ) $term_id = $term_id['term_id']; |
|
404 if ( isset($cat['term_id']) ) |
|
405 $this->processed_terms[intval($cat['term_id'])] = (int) $term_id; |
|
406 continue; |
|
407 } |
|
408 |
|
409 $category_parent = empty( $cat['category_parent'] ) ? 0 : category_exists( $cat['category_parent'] ); |
|
410 $category_description = isset( $cat['category_description'] ) ? $cat['category_description'] : ''; |
|
411 $catarr = array( |
|
412 'category_nicename' => $cat['category_nicename'], |
|
413 'category_parent' => $category_parent, |
|
414 'cat_name' => $cat['cat_name'], |
|
415 'category_description' => $category_description |
|
416 ); |
|
417 $catarr = wp_slash( $catarr ); |
|
418 |
|
419 $id = wp_insert_category( $catarr ); |
|
420 if ( ! is_wp_error( $id ) ) { |
|
421 if ( isset($cat['term_id']) ) |
|
422 $this->processed_terms[intval($cat['term_id'])] = $id; |
|
423 } else { |
|
424 printf( __( 'Failed to import category %s', 'wordpress-importer' ), esc_html($cat['category_nicename']) ); |
|
425 if ( defined('IMPORT_DEBUG') && IMPORT_DEBUG ) |
|
426 echo ': ' . $id->get_error_message(); |
|
427 echo '<br />'; |
|
428 continue; |
|
429 } |
|
430 |
|
431 $this->process_termmeta( $cat, $id['term_id'] ); |
|
432 } |
|
433 |
|
434 unset( $this->categories ); |
|
435 } |
|
436 |
|
437 /** |
|
438 * Create new post tags based on import information |
|
439 * |
|
440 * Doesn't create a tag if its slug already exists |
|
441 */ |
|
442 function process_tags() { |
|
443 $this->tags = apply_filters( 'wp_import_tags', $this->tags ); |
|
444 |
|
445 if ( empty( $this->tags ) ) |
|
446 return; |
|
447 |
|
448 foreach ( $this->tags as $tag ) { |
|
449 // if the tag already exists leave it alone |
|
450 $term_id = term_exists( $tag['tag_slug'], 'post_tag' ); |
|
451 if ( $term_id ) { |
|
452 if ( is_array($term_id) ) $term_id = $term_id['term_id']; |
|
453 if ( isset($tag['term_id']) ) |
|
454 $this->processed_terms[intval($tag['term_id'])] = (int) $term_id; |
|
455 continue; |
|
456 } |
|
457 |
|
458 $tag = wp_slash( $tag ); |
|
459 $tag_desc = isset( $tag['tag_description'] ) ? $tag['tag_description'] : ''; |
|
460 $tagarr = array( 'slug' => $tag['tag_slug'], 'description' => $tag_desc ); |
|
461 |
|
462 $id = wp_insert_term( $tag['tag_name'], 'post_tag', $tagarr ); |
|
463 if ( ! is_wp_error( $id ) ) { |
|
464 if ( isset($tag['term_id']) ) |
|
465 $this->processed_terms[intval($tag['term_id'])] = $id['term_id']; |
|
466 } else { |
|
467 printf( __( 'Failed to import post tag %s', 'wordpress-importer' ), esc_html($tag['tag_name']) ); |
|
468 if ( defined('IMPORT_DEBUG') && IMPORT_DEBUG ) |
|
469 echo ': ' . $id->get_error_message(); |
|
470 echo '<br />'; |
|
471 continue; |
|
472 } |
|
473 |
|
474 $this->process_termmeta( $tag, $id['term_id'] ); |
|
475 } |
|
476 |
|
477 unset( $this->tags ); |
|
478 } |
|
479 |
|
480 /** |
|
481 * Create new terms based on import information |
|
482 * |
|
483 * Doesn't create a term its slug already exists |
|
484 */ |
|
485 function process_terms() { |
|
486 $this->terms = apply_filters( 'wp_import_terms', $this->terms ); |
|
487 |
|
488 if ( empty( $this->terms ) ) |
|
489 return; |
|
490 |
|
491 foreach ( $this->terms as $term ) { |
|
492 // if the term already exists in the correct taxonomy leave it alone |
|
493 $term_id = term_exists( $term['slug'], $term['term_taxonomy'] ); |
|
494 if ( $term_id ) { |
|
495 if ( is_array($term_id) ) $term_id = $term_id['term_id']; |
|
496 if ( isset($term['term_id']) ) |
|
497 $this->processed_terms[intval($term['term_id'])] = (int) $term_id; |
|
498 continue; |
|
499 } |
|
500 |
|
501 if ( empty( $term['term_parent'] ) ) { |
|
502 $parent = 0; |
|
503 } else { |
|
504 $parent = term_exists( $term['term_parent'], $term['term_taxonomy'] ); |
|
505 if ( is_array( $parent ) ) $parent = $parent['term_id']; |
|
506 } |
|
507 $term = wp_slash( $term ); |
|
508 $description = isset( $term['term_description'] ) ? $term['term_description'] : ''; |
|
509 $termarr = array( 'slug' => $term['slug'], 'description' => $description, 'parent' => intval($parent) ); |
|
510 |
|
511 $id = wp_insert_term( $term['term_name'], $term['term_taxonomy'], $termarr ); |
|
512 if ( ! is_wp_error( $id ) ) { |
|
513 if ( isset($term['term_id']) ) |
|
514 $this->processed_terms[intval($term['term_id'])] = $id['term_id']; |
|
515 } else { |
|
516 printf( __( 'Failed to import %s %s', 'wordpress-importer' ), esc_html($term['term_taxonomy']), esc_html($term['term_name']) ); |
|
517 if ( defined('IMPORT_DEBUG') && IMPORT_DEBUG ) |
|
518 echo ': ' . $id->get_error_message(); |
|
519 echo '<br />'; |
|
520 continue; |
|
521 } |
|
522 |
|
523 $this->process_termmeta( $term, $id['term_id'] ); |
|
524 } |
|
525 |
|
526 unset( $this->terms ); |
|
527 } |
|
528 |
|
529 /** |
|
530 * Add metadata to imported term. |
|
531 * |
|
532 * @since 0.6.2 |
|
533 * |
|
534 * @param array $term Term data from WXR import. |
|
535 * @param int $term_id ID of the newly created term. |
|
536 */ |
|
537 protected function process_termmeta( $term, $term_id ) { |
|
538 if ( ! isset( $term['termmeta'] ) ) { |
|
539 $term['termmeta'] = array(); |
|
540 } |
|
541 |
|
542 /** |
|
543 * Filters the metadata attached to an imported term. |
|
544 * |
|
545 * @since 0.6.2 |
|
546 * |
|
547 * @param array $termmeta Array of term meta. |
|
548 * @param int $term_id ID of the newly created term. |
|
549 * @param array $term Term data from the WXR import. |
|
550 */ |
|
551 $term['termmeta'] = apply_filters( 'wp_import_term_meta', $term['termmeta'], $term_id, $term ); |
|
552 |
|
553 if ( empty( $term['termmeta'] ) ) { |
|
554 return; |
|
555 } |
|
556 |
|
557 foreach ( $term['termmeta'] as $meta ) { |
|
558 /** |
|
559 * Filters the meta key for an imported piece of term meta. |
|
560 * |
|
561 * @since 0.6.2 |
|
562 * |
|
563 * @param string $meta_key Meta key. |
|
564 * @param int $term_id ID of the newly created term. |
|
565 * @param array $term Term data from the WXR import. |
|
566 */ |
|
567 $key = apply_filters( 'import_term_meta_key', $meta['key'], $term_id, $term ); |
|
568 if ( ! $key ) { |
|
569 continue; |
|
570 } |
|
571 |
|
572 // Export gets meta straight from the DB so could have a serialized string |
|
573 $value = maybe_unserialize( $meta['value'] ); |
|
574 |
|
575 add_term_meta( $term_id, $key, $value ); |
|
576 |
|
577 /** |
|
578 * Fires after term meta is imported. |
|
579 * |
|
580 * @since 0.6.2 |
|
581 * |
|
582 * @param int $term_id ID of the newly created term. |
|
583 * @param string $key Meta key. |
|
584 * @param mixed $value Meta value. |
|
585 */ |
|
586 do_action( 'import_term_meta', $term_id, $key, $value ); |
|
587 } |
|
588 } |
|
589 |
|
590 /** |
|
591 * Create new posts based on import information |
|
592 * |
|
593 * Posts marked as having a parent which doesn't exist will become top level items. |
|
594 * Doesn't create a new post if: the post type doesn't exist, the given post ID |
|
595 * is already noted as imported or a post with the same title and date already exists. |
|
596 * Note that new/updated terms, comments and meta are imported for the last of the above. |
|
597 */ |
|
598 function process_posts() { |
|
599 $this->posts = apply_filters( 'wp_import_posts', $this->posts ); |
|
600 |
|
601 foreach ( $this->posts as $post ) { |
|
602 $post = apply_filters( 'wp_import_post_data_raw', $post ); |
|
603 |
|
604 if ( ! post_type_exists( $post['post_type'] ) ) { |
|
605 printf( __( 'Failed to import “%s”: Invalid post type %s', 'wordpress-importer' ), |
|
606 esc_html($post['post_title']), esc_html($post['post_type']) ); |
|
607 echo '<br />'; |
|
608 do_action( 'wp_import_post_exists', $post ); |
|
609 continue; |
|
610 } |
|
611 |
|
612 if ( isset( $this->processed_posts[$post['post_id']] ) && ! empty( $post['post_id'] ) ) |
|
613 continue; |
|
614 |
|
615 if ( $post['status'] == 'auto-draft' ) |
|
616 continue; |
|
617 |
|
618 if ( 'nav_menu_item' == $post['post_type'] ) { |
|
619 $this->process_menu_item( $post ); |
|
620 continue; |
|
621 } |
|
622 |
|
623 $post_type_object = get_post_type_object( $post['post_type'] ); |
|
624 |
|
625 $post_exists = post_exists( $post['post_title'], '', $post['post_date'] ); |
|
626 |
|
627 /** |
|
628 * Filter ID of the existing post corresponding to post currently importing. |
|
629 * |
|
630 * Return 0 to force the post to be imported. Filter the ID to be something else |
|
631 * to override which existing post is mapped to the imported post. |
|
632 * |
|
633 * @see post_exists() |
|
634 * @since 0.6.2 |
|
635 * |
|
636 * @param int $post_exists Post ID, or 0 if post did not exist. |
|
637 * @param array $post The post array to be inserted. |
|
638 */ |
|
639 $post_exists = apply_filters( 'wp_import_existing_post', $post_exists, $post ); |
|
640 |
|
641 if ( $post_exists && get_post_type( $post_exists ) == $post['post_type'] ) { |
|
642 printf( __('%s “%s” already exists.', 'wordpress-importer'), $post_type_object->labels->singular_name, esc_html($post['post_title']) ); |
|
643 echo '<br />'; |
|
644 $comment_post_ID = $post_id = $post_exists; |
|
645 $this->processed_posts[ intval( $post['post_id'] ) ] = intval( $post_exists ); |
|
646 } else { |
|
647 $post_parent = (int) $post['post_parent']; |
|
648 if ( $post_parent ) { |
|
649 // if we already know the parent, map it to the new local ID |
|
650 if ( isset( $this->processed_posts[$post_parent] ) ) { |
|
651 $post_parent = $this->processed_posts[$post_parent]; |
|
652 // otherwise record the parent for later |
|
653 } else { |
|
654 $this->post_orphans[intval($post['post_id'])] = $post_parent; |
|
655 $post_parent = 0; |
|
656 } |
|
657 } |
|
658 |
|
659 // map the post author |
|
660 $author = sanitize_user( $post['post_author'], true ); |
|
661 if ( isset( $this->author_mapping[$author] ) ) |
|
662 $author = $this->author_mapping[$author]; |
|
663 else |
|
664 $author = (int) get_current_user_id(); |
|
665 |
|
666 $postdata = array( |
|
667 'import_id' => $post['post_id'], 'post_author' => $author, 'post_date' => $post['post_date'], |
|
668 'post_date_gmt' => $post['post_date_gmt'], 'post_content' => $post['post_content'], |
|
669 'post_excerpt' => $post['post_excerpt'], 'post_title' => $post['post_title'], |
|
670 'post_status' => $post['status'], 'post_name' => $post['post_name'], |
|
671 'comment_status' => $post['comment_status'], 'ping_status' => $post['ping_status'], |
|
672 'guid' => $post['guid'], 'post_parent' => $post_parent, 'menu_order' => $post['menu_order'], |
|
673 'post_type' => $post['post_type'], 'post_password' => $post['post_password'] |
|
674 ); |
|
675 |
|
676 $original_post_ID = $post['post_id']; |
|
677 $postdata = apply_filters( 'wp_import_post_data_processed', $postdata, $post ); |
|
678 |
|
679 $postdata = wp_slash( $postdata ); |
|
680 |
|
681 if ( 'attachment' == $postdata['post_type'] ) { |
|
682 $remote_url = ! empty($post['attachment_url']) ? $post['attachment_url'] : $post['guid']; |
|
683 |
|
684 // try to use _wp_attached file for upload folder placement to ensure the same location as the export site |
|
685 // e.g. location is 2003/05/image.jpg but the attachment post_date is 2010/09, see media_handle_upload() |
|
686 $postdata['upload_date'] = $post['post_date']; |
|
687 if ( isset( $post['postmeta'] ) ) { |
|
688 foreach( $post['postmeta'] as $meta ) { |
|
689 if ( $meta['key'] == '_wp_attached_file' ) { |
|
690 if ( preg_match( '%^[0-9]{4}/[0-9]{2}%', $meta['value'], $matches ) ) |
|
691 $postdata['upload_date'] = $matches[0]; |
|
692 break; |
|
693 } |
|
694 } |
|
695 } |
|
696 |
|
697 $comment_post_ID = $post_id = $this->process_attachment( $postdata, $remote_url ); |
|
698 } else { |
|
699 $comment_post_ID = $post_id = wp_insert_post( $postdata, true ); |
|
700 do_action( 'wp_import_insert_post', $post_id, $original_post_ID, $postdata, $post ); |
|
701 } |
|
702 |
|
703 if ( is_wp_error( $post_id ) ) { |
|
704 printf( __( 'Failed to import %s “%s”', 'wordpress-importer' ), |
|
705 $post_type_object->labels->singular_name, esc_html($post['post_title']) ); |
|
706 if ( defined('IMPORT_DEBUG') && IMPORT_DEBUG ) |
|
707 echo ': ' . $post_id->get_error_message(); |
|
708 echo '<br />'; |
|
709 continue; |
|
710 } |
|
711 |
|
712 if ( $post['is_sticky'] == 1 ) |
|
713 stick_post( $post_id ); |
|
714 } |
|
715 |
|
716 // map pre-import ID to local ID |
|
717 $this->processed_posts[intval($post['post_id'])] = (int) $post_id; |
|
718 |
|
719 if ( ! isset( $post['terms'] ) ) |
|
720 $post['terms'] = array(); |
|
721 |
|
722 $post['terms'] = apply_filters( 'wp_import_post_terms', $post['terms'], $post_id, $post ); |
|
723 |
|
724 // add categories, tags and other terms |
|
725 if ( ! empty( $post['terms'] ) ) { |
|
726 $terms_to_set = array(); |
|
727 foreach ( $post['terms'] as $term ) { |
|
728 // back compat with WXR 1.0 map 'tag' to 'post_tag' |
|
729 $taxonomy = ( 'tag' == $term['domain'] ) ? 'post_tag' : $term['domain']; |
|
730 $term_exists = term_exists( $term['slug'], $taxonomy ); |
|
731 $term_id = is_array( $term_exists ) ? $term_exists['term_id'] : $term_exists; |
|
732 if ( ! $term_id ) { |
|
733 $t = wp_insert_term( $term['name'], $taxonomy, array( 'slug' => $term['slug'] ) ); |
|
734 if ( ! is_wp_error( $t ) ) { |
|
735 $term_id = $t['term_id']; |
|
736 do_action( 'wp_import_insert_term', $t, $term, $post_id, $post ); |
|
737 } else { |
|
738 printf( __( 'Failed to import %s %s', 'wordpress-importer' ), esc_html($taxonomy), esc_html($term['name']) ); |
|
739 if ( defined('IMPORT_DEBUG') && IMPORT_DEBUG ) |
|
740 echo ': ' . $t->get_error_message(); |
|
741 echo '<br />'; |
|
742 do_action( 'wp_import_insert_term_failed', $t, $term, $post_id, $post ); |
|
743 continue; |
|
744 } |
|
745 } |
|
746 $terms_to_set[$taxonomy][] = intval( $term_id ); |
|
747 } |
|
748 |
|
749 foreach ( $terms_to_set as $tax => $ids ) { |
|
750 $tt_ids = wp_set_post_terms( $post_id, $ids, $tax ); |
|
751 do_action( 'wp_import_set_post_terms', $tt_ids, $ids, $tax, $post_id, $post ); |
|
752 } |
|
753 unset( $post['terms'], $terms_to_set ); |
|
754 } |
|
755 |
|
756 if ( ! isset( $post['comments'] ) ) |
|
757 $post['comments'] = array(); |
|
758 |
|
759 $post['comments'] = apply_filters( 'wp_import_post_comments', $post['comments'], $post_id, $post ); |
|
760 |
|
761 // add/update comments |
|
762 if ( ! empty( $post['comments'] ) ) { |
|
763 $num_comments = 0; |
|
764 $inserted_comments = array(); |
|
765 foreach ( $post['comments'] as $comment ) { |
|
766 $comment_id = $comment['comment_id']; |
|
767 $newcomments[$comment_id]['comment_post_ID'] = $comment_post_ID; |
|
768 $newcomments[$comment_id]['comment_author'] = $comment['comment_author']; |
|
769 $newcomments[$comment_id]['comment_author_email'] = $comment['comment_author_email']; |
|
770 $newcomments[$comment_id]['comment_author_IP'] = $comment['comment_author_IP']; |
|
771 $newcomments[$comment_id]['comment_author_url'] = $comment['comment_author_url']; |
|
772 $newcomments[$comment_id]['comment_date'] = $comment['comment_date']; |
|
773 $newcomments[$comment_id]['comment_date_gmt'] = $comment['comment_date_gmt']; |
|
774 $newcomments[$comment_id]['comment_content'] = $comment['comment_content']; |
|
775 $newcomments[$comment_id]['comment_approved'] = $comment['comment_approved']; |
|
776 $newcomments[$comment_id]['comment_type'] = $comment['comment_type']; |
|
777 $newcomments[$comment_id]['comment_parent'] = $comment['comment_parent']; |
|
778 $newcomments[$comment_id]['commentmeta'] = isset( $comment['commentmeta'] ) ? $comment['commentmeta'] : array(); |
|
779 if ( isset( $this->processed_authors[$comment['comment_user_id']] ) ) |
|
780 $newcomments[$comment_id]['user_id'] = $this->processed_authors[$comment['comment_user_id']]; |
|
781 } |
|
782 ksort( $newcomments ); |
|
783 |
|
784 foreach ( $newcomments as $key => $comment ) { |
|
785 // if this is a new post we can skip the comment_exists() check |
|
786 if ( ! $post_exists || ! comment_exists( $comment['comment_author'], $comment['comment_date'] ) ) { |
|
787 if ( isset( $inserted_comments[$comment['comment_parent']] ) ) |
|
788 $comment['comment_parent'] = $inserted_comments[$comment['comment_parent']]; |
|
789 $comment = wp_slash( $comment ); |
|
790 $comment = wp_filter_comment( $comment ); |
|
791 $inserted_comments[$key] = wp_insert_comment( $comment ); |
|
792 do_action( 'wp_import_insert_comment', $inserted_comments[$key], $comment, $comment_post_ID, $post ); |
|
793 |
|
794 foreach( $comment['commentmeta'] as $meta ) { |
|
795 $value = maybe_unserialize( $meta['value'] ); |
|
796 add_comment_meta( $inserted_comments[$key], $meta['key'], $value ); |
|
797 } |
|
798 |
|
799 $num_comments++; |
|
800 } |
|
801 } |
|
802 unset( $newcomments, $inserted_comments, $post['comments'] ); |
|
803 } |
|
804 |
|
805 if ( ! isset( $post['postmeta'] ) ) |
|
806 $post['postmeta'] = array(); |
|
807 |
|
808 $post['postmeta'] = apply_filters( 'wp_import_post_meta', $post['postmeta'], $post_id, $post ); |
|
809 |
|
810 // add/update post meta |
|
811 if ( ! empty( $post['postmeta'] ) ) { |
|
812 foreach ( $post['postmeta'] as $meta ) { |
|
813 $key = apply_filters( 'import_post_meta_key', $meta['key'], $post_id, $post ); |
|
814 $value = false; |
|
815 |
|
816 if ( '_edit_last' == $key ) { |
|
817 if ( isset( $this->processed_authors[intval($meta['value'])] ) ) |
|
818 $value = $this->processed_authors[intval($meta['value'])]; |
|
819 else |
|
820 $key = false; |
|
821 } |
|
822 |
|
823 if ( $key ) { |
|
824 // export gets meta straight from the DB so could have a serialized string |
|
825 if ( ! $value ) |
|
826 $value = maybe_unserialize( $meta['value'] ); |
|
827 |
|
828 add_post_meta( $post_id, $key, $value ); |
|
829 do_action( 'import_post_meta', $post_id, $key, $value ); |
|
830 |
|
831 // if the post has a featured image, take note of this in case of remap |
|
832 if ( '_thumbnail_id' == $key ) |
|
833 $this->featured_images[$post_id] = (int) $value; |
|
834 } |
|
835 } |
|
836 } |
|
837 } |
|
838 |
|
839 unset( $this->posts ); |
|
840 } |
|
841 |
|
842 /** |
|
843 * Attempt to create a new menu item from import data |
|
844 * |
|
845 * Fails for draft, orphaned menu items and those without an associated nav_menu |
|
846 * or an invalid nav_menu term. If the post type or term object which the menu item |
|
847 * represents doesn't exist then the menu item will not be imported (waits until the |
|
848 * end of the import to retry again before discarding). |
|
849 * |
|
850 * @param array $item Menu item details from WXR file |
|
851 */ |
|
852 function process_menu_item( $item ) { |
|
853 // skip draft, orphaned menu items |
|
854 if ( 'draft' == $item['status'] ) |
|
855 return; |
|
856 |
|
857 $menu_slug = false; |
|
858 if ( isset($item['terms']) ) { |
|
859 // loop through terms, assume first nav_menu term is correct menu |
|
860 foreach ( $item['terms'] as $term ) { |
|
861 if ( 'nav_menu' == $term['domain'] ) { |
|
862 $menu_slug = $term['slug']; |
|
863 break; |
|
864 } |
|
865 } |
|
866 } |
|
867 |
|
868 // no nav_menu term associated with this menu item |
|
869 if ( ! $menu_slug ) { |
|
870 _e( 'Menu item skipped due to missing menu slug', 'wordpress-importer' ); |
|
871 echo '<br />'; |
|
872 return; |
|
873 } |
|
874 |
|
875 $menu_id = term_exists( $menu_slug, 'nav_menu' ); |
|
876 if ( ! $menu_id ) { |
|
877 printf( __( 'Menu item skipped due to invalid menu slug: %s', 'wordpress-importer' ), esc_html( $menu_slug ) ); |
|
878 echo '<br />'; |
|
879 return; |
|
880 } else { |
|
881 $menu_id = is_array( $menu_id ) ? $menu_id['term_id'] : $menu_id; |
|
882 } |
|
883 |
|
884 foreach ( $item['postmeta'] as $meta ) |
|
885 ${$meta['key']} = $meta['value']; |
|
886 |
|
887 if ( 'taxonomy' == $_menu_item_type && isset( $this->processed_terms[intval($_menu_item_object_id)] ) ) { |
|
888 $_menu_item_object_id = $this->processed_terms[intval($_menu_item_object_id)]; |
|
889 } else if ( 'post_type' == $_menu_item_type && isset( $this->processed_posts[intval($_menu_item_object_id)] ) ) { |
|
890 $_menu_item_object_id = $this->processed_posts[intval($_menu_item_object_id)]; |
|
891 } else if ( 'custom' != $_menu_item_type ) { |
|
892 // associated object is missing or not imported yet, we'll retry later |
|
893 $this->missing_menu_items[] = $item; |
|
894 return; |
|
895 } |
|
896 |
|
897 if ( isset( $this->processed_menu_items[intval($_menu_item_menu_item_parent)] ) ) { |
|
898 $_menu_item_menu_item_parent = $this->processed_menu_items[intval($_menu_item_menu_item_parent)]; |
|
899 } else if ( $_menu_item_menu_item_parent ) { |
|
900 $this->menu_item_orphans[intval($item['post_id'])] = (int) $_menu_item_menu_item_parent; |
|
901 $_menu_item_menu_item_parent = 0; |
|
902 } |
|
903 |
|
904 // wp_update_nav_menu_item expects CSS classes as a space separated string |
|
905 $_menu_item_classes = maybe_unserialize( $_menu_item_classes ); |
|
906 if ( is_array( $_menu_item_classes ) ) |
|
907 $_menu_item_classes = implode( ' ', $_menu_item_classes ); |
|
908 |
|
909 $args = array( |
|
910 'menu-item-object-id' => $_menu_item_object_id, |
|
911 'menu-item-object' => $_menu_item_object, |
|
912 'menu-item-parent-id' => $_menu_item_menu_item_parent, |
|
913 'menu-item-position' => intval( $item['menu_order'] ), |
|
914 'menu-item-type' => $_menu_item_type, |
|
915 'menu-item-title' => $item['post_title'], |
|
916 'menu-item-url' => $_menu_item_url, |
|
917 'menu-item-description' => $item['post_content'], |
|
918 'menu-item-attr-title' => $item['post_excerpt'], |
|
919 'menu-item-target' => $_menu_item_target, |
|
920 'menu-item-classes' => $_menu_item_classes, |
|
921 'menu-item-xfn' => $_menu_item_xfn, |
|
922 'menu-item-status' => $item['status'] |
|
923 ); |
|
924 |
|
925 $id = wp_update_nav_menu_item( $menu_id, 0, $args ); |
|
926 if ( $id && ! is_wp_error( $id ) ) |
|
927 $this->processed_menu_items[intval($item['post_id'])] = (int) $id; |
|
928 } |
|
929 |
|
930 /** |
|
931 * If fetching attachments is enabled then attempt to create a new attachment |
|
932 * |
|
933 * @param array $post Attachment post details from WXR |
|
934 * @param string $url URL to fetch attachment from |
|
935 * @return int|WP_Error Post ID on success, WP_Error otherwise |
|
936 */ |
|
937 function process_attachment( $post, $url ) { |
|
938 if ( ! $this->fetch_attachments ) |
|
939 return new WP_Error( 'attachment_processing_error', |
|
940 __( 'Fetching attachments is not enabled', 'wordpress-importer' ) ); |
|
941 |
|
942 // if the URL is absolute, but does not contain address, then upload it assuming base_site_url |
|
943 if ( preg_match( '|^/[\w\W]+$|', $url ) ) |
|
944 $url = rtrim( $this->base_url, '/' ) . $url; |
|
945 |
|
946 $upload = $this->fetch_remote_file( $url, $post ); |
|
947 if ( is_wp_error( $upload ) ) |
|
948 return $upload; |
|
949 |
|
950 if ( $info = wp_check_filetype( $upload['file'] ) ) |
|
951 $post['post_mime_type'] = $info['type']; |
|
952 else |
|
953 return new WP_Error( 'attachment_processing_error', __('Invalid file type', 'wordpress-importer') ); |
|
954 |
|
955 $post['guid'] = $upload['url']; |
|
956 |
|
957 // as per wp-admin/includes/upload.php |
|
958 $post_id = wp_insert_attachment( $post, $upload['file'] ); |
|
959 wp_update_attachment_metadata( $post_id, wp_generate_attachment_metadata( $post_id, $upload['file'] ) ); |
|
960 |
|
961 // remap resized image URLs, works by stripping the extension and remapping the URL stub. |
|
962 if ( preg_match( '!^image/!', $info['type'] ) ) { |
|
963 $parts = pathinfo( $url ); |
|
964 $name = basename( $parts['basename'], ".{$parts['extension']}" ); // PATHINFO_FILENAME in PHP 5.2 |
|
965 |
|
966 $parts_new = pathinfo( $upload['url'] ); |
|
967 $name_new = basename( $parts_new['basename'], ".{$parts_new['extension']}" ); |
|
968 |
|
969 $this->url_remap[$parts['dirname'] . '/' . $name] = $parts_new['dirname'] . '/' . $name_new; |
|
970 } |
|
971 |
|
972 return $post_id; |
|
973 } |
|
974 |
|
975 /** |
|
976 * Attempt to download a remote file attachment |
|
977 * |
|
978 * @param string $url URL of item to fetch |
|
979 * @param array $post Attachment details |
|
980 * @return array|WP_Error Local file location details on success, WP_Error otherwise |
|
981 */ |
|
982 function fetch_remote_file( $url, $post ) { |
|
983 // extract the file name and extension from the url |
|
984 $file_name = basename( $url ); |
|
985 |
|
986 // get placeholder file in the upload dir with a unique, sanitized filename |
|
987 $upload = wp_upload_bits( $file_name, 0, '', $post['upload_date'] ); |
|
988 if ( $upload['error'] ) |
|
989 return new WP_Error( 'upload_dir_error', $upload['error'] ); |
|
990 |
|
991 // fetch the remote url and write it to the placeholder file |
|
992 $remote_response = wp_safe_remote_get( $url, array( |
|
993 'timeout' => 300, |
|
994 'stream' => true, |
|
995 'filename' => $upload['file'], |
|
996 ) ); |
|
997 |
|
998 $headers = wp_remote_retrieve_headers( $remote_response ); |
|
999 |
|
1000 // request failed |
|
1001 if ( ! $headers ) { |
|
1002 @unlink( $upload['file'] ); |
|
1003 return new WP_Error( 'import_file_error', __('Remote server did not respond', 'wordpress-importer') ); |
|
1004 } |
|
1005 |
|
1006 $remote_response_code = wp_remote_retrieve_response_code( $remote_response ); |
|
1007 |
|
1008 // make sure the fetch was successful |
|
1009 if ( $remote_response_code != '200' ) { |
|
1010 @unlink( $upload['file'] ); |
|
1011 return new WP_Error( 'import_file_error', sprintf( __('Remote server returned error response %1$d %2$s', 'wordpress-importer'), esc_html($remote_response_code), get_status_header_desc($remote_response_code) ) ); |
|
1012 } |
|
1013 |
|
1014 $filesize = filesize( $upload['file'] ); |
|
1015 |
|
1016 if ( isset( $headers['content-length'] ) && $filesize != $headers['content-length'] ) { |
|
1017 @unlink( $upload['file'] ); |
|
1018 return new WP_Error( 'import_file_error', __('Remote file is incorrect size', 'wordpress-importer') ); |
|
1019 } |
|
1020 |
|
1021 if ( 0 == $filesize ) { |
|
1022 @unlink( $upload['file'] ); |
|
1023 return new WP_Error( 'import_file_error', __('Zero size file downloaded', 'wordpress-importer') ); |
|
1024 } |
|
1025 |
|
1026 $max_size = (int) $this->max_attachment_size(); |
|
1027 if ( ! empty( $max_size ) && $filesize > $max_size ) { |
|
1028 @unlink( $upload['file'] ); |
|
1029 return new WP_Error( 'import_file_error', sprintf(__('Remote file is too large, limit is %s', 'wordpress-importer'), size_format($max_size) ) ); |
|
1030 } |
|
1031 |
|
1032 // keep track of the old and new urls so we can substitute them later |
|
1033 $this->url_remap[$url] = $upload['url']; |
|
1034 $this->url_remap[$post['guid']] = $upload['url']; // r13735, really needed? |
|
1035 // keep track of the destination if the remote url is redirected somewhere else |
|
1036 if ( isset($headers['x-final-location']) && $headers['x-final-location'] != $url ) |
|
1037 $this->url_remap[$headers['x-final-location']] = $upload['url']; |
|
1038 |
|
1039 return $upload; |
|
1040 } |
|
1041 |
|
1042 /** |
|
1043 * Attempt to associate posts and menu items with previously missing parents |
|
1044 * |
|
1045 * An imported post's parent may not have been imported when it was first created |
|
1046 * so try again. Similarly for child menu items and menu items which were missing |
|
1047 * the object (e.g. post) they represent in the menu |
|
1048 */ |
|
1049 function backfill_parents() { |
|
1050 global $wpdb; |
|
1051 |
|
1052 // find parents for post orphans |
|
1053 foreach ( $this->post_orphans as $child_id => $parent_id ) { |
|
1054 $local_child_id = $local_parent_id = false; |
|
1055 if ( isset( $this->processed_posts[$child_id] ) ) |
|
1056 $local_child_id = $this->processed_posts[$child_id]; |
|
1057 if ( isset( $this->processed_posts[$parent_id] ) ) |
|
1058 $local_parent_id = $this->processed_posts[$parent_id]; |
|
1059 |
|
1060 if ( $local_child_id && $local_parent_id ) { |
|
1061 $wpdb->update( $wpdb->posts, array( 'post_parent' => $local_parent_id ), array( 'ID' => $local_child_id ), '%d', '%d' ); |
|
1062 clean_post_cache( $local_child_id ); |
|
1063 } |
|
1064 } |
|
1065 |
|
1066 // all other posts/terms are imported, retry menu items with missing associated object |
|
1067 $missing_menu_items = $this->missing_menu_items; |
|
1068 foreach ( $missing_menu_items as $item ) |
|
1069 $this->process_menu_item( $item ); |
|
1070 |
|
1071 // find parents for menu item orphans |
|
1072 foreach ( $this->menu_item_orphans as $child_id => $parent_id ) { |
|
1073 $local_child_id = $local_parent_id = 0; |
|
1074 if ( isset( $this->processed_menu_items[$child_id] ) ) |
|
1075 $local_child_id = $this->processed_menu_items[$child_id]; |
|
1076 if ( isset( $this->processed_menu_items[$parent_id] ) ) |
|
1077 $local_parent_id = $this->processed_menu_items[$parent_id]; |
|
1078 |
|
1079 if ( $local_child_id && $local_parent_id ) |
|
1080 update_post_meta( $local_child_id, '_menu_item_menu_item_parent', (int) $local_parent_id ); |
|
1081 } |
|
1082 } |
|
1083 |
|
1084 /** |
|
1085 * Use stored mapping information to update old attachment URLs |
|
1086 */ |
|
1087 function backfill_attachment_urls() { |
|
1088 global $wpdb; |
|
1089 // make sure we do the longest urls first, in case one is a substring of another |
|
1090 uksort( $this->url_remap, array(&$this, 'cmpr_strlen') ); |
|
1091 |
|
1092 foreach ( $this->url_remap as $from_url => $to_url ) { |
|
1093 // remap urls in post_content |
|
1094 $wpdb->query( $wpdb->prepare("UPDATE {$wpdb->posts} SET post_content = REPLACE(post_content, %s, %s)", $from_url, $to_url) ); |
|
1095 // remap enclosure urls |
|
1096 $result = $wpdb->query( $wpdb->prepare("UPDATE {$wpdb->postmeta} SET meta_value = REPLACE(meta_value, %s, %s) WHERE meta_key='enclosure'", $from_url, $to_url) ); |
|
1097 } |
|
1098 } |
|
1099 |
|
1100 /** |
|
1101 * Update _thumbnail_id meta to new, imported attachment IDs |
|
1102 */ |
|
1103 function remap_featured_images() { |
|
1104 // cycle through posts that have a featured image |
|
1105 foreach ( $this->featured_images as $post_id => $value ) { |
|
1106 if ( isset( $this->processed_posts[$value] ) ) { |
|
1107 $new_id = $this->processed_posts[$value]; |
|
1108 // only update if there's a difference |
|
1109 if ( $new_id != $value ) |
|
1110 update_post_meta( $post_id, '_thumbnail_id', $new_id ); |
|
1111 } |
|
1112 } |
|
1113 } |
|
1114 |
|
1115 /** |
|
1116 * Parse a WXR file |
|
1117 * |
|
1118 * @param string $file Path to WXR file for parsing |
|
1119 * @return array Information gathered from the WXR file |
|
1120 */ |
|
1121 function parse( $file ) { |
|
1122 $parser = new WXR_Parser(); |
|
1123 return $parser->parse( $file ); |
|
1124 } |
|
1125 |
|
1126 // Display import page title |
|
1127 function header() { |
|
1128 echo '<div class="wrap">'; |
|
1129 echo '<h2>' . __( 'Import WordPress', 'wordpress-importer' ) . '</h2>'; |
|
1130 |
|
1131 $updates = get_plugin_updates(); |
|
1132 $basename = plugin_basename(__FILE__); |
|
1133 if ( isset( $updates[$basename] ) ) { |
|
1134 $update = $updates[$basename]; |
|
1135 echo '<div class="error"><p><strong>'; |
|
1136 printf( __( 'A new version of this importer is available. Please update to version %s to ensure compatibility with newer export files.', 'wordpress-importer' ), $update->update->new_version ); |
|
1137 echo '</strong></p></div>'; |
|
1138 } |
|
1139 } |
|
1140 |
|
1141 // Close div.wrap |
|
1142 function footer() { |
|
1143 echo '</div>'; |
|
1144 } |
|
1145 |
|
1146 /** |
|
1147 * Display introductory text and file upload form |
|
1148 */ |
|
1149 function greet() { |
|
1150 echo '<div class="narrow">'; |
|
1151 echo '<p>'.__( 'Howdy! Upload your WordPress eXtended RSS (WXR) file and we’ll import the posts, pages, comments, custom fields, categories, and tags into this site.', 'wordpress-importer' ).'</p>'; |
|
1152 echo '<p>'.__( 'Choose a WXR (.xml) file to upload, then click Upload file and import.', 'wordpress-importer' ).'</p>'; |
|
1153 wp_import_upload_form( 'admin.php?import=wordpress&step=1' ); |
|
1154 echo '</div>'; |
|
1155 } |
|
1156 |
|
1157 /** |
|
1158 * Decide if the given meta key maps to information we will want to import |
|
1159 * |
|
1160 * @param string $key The meta key to check |
|
1161 * @return string|bool The key if we do want to import, false if not |
|
1162 */ |
|
1163 function is_valid_meta_key( $key ) { |
|
1164 // skip attachment metadata since we'll regenerate it from scratch |
|
1165 // skip _edit_lock as not relevant for import |
|
1166 if ( in_array( $key, array( '_wp_attached_file', '_wp_attachment_metadata', '_edit_lock' ) ) ) |
|
1167 return false; |
|
1168 return $key; |
|
1169 } |
|
1170 |
|
1171 /** |
|
1172 * Decide whether or not the importer is allowed to create users. |
|
1173 * Default is true, can be filtered via import_allow_create_users |
|
1174 * |
|
1175 * @return bool True if creating users is allowed |
|
1176 */ |
|
1177 function allow_create_users() { |
|
1178 return apply_filters( 'import_allow_create_users', true ); |
|
1179 } |
|
1180 |
|
1181 /** |
|
1182 * Decide whether or not the importer should attempt to download attachment files. |
|
1183 * Default is true, can be filtered via import_allow_fetch_attachments. The choice |
|
1184 * made at the import options screen must also be true, false here hides that checkbox. |
|
1185 * |
|
1186 * @return bool True if downloading attachments is allowed |
|
1187 */ |
|
1188 function allow_fetch_attachments() { |
|
1189 return apply_filters( 'import_allow_fetch_attachments', true ); |
|
1190 } |
|
1191 |
|
1192 /** |
|
1193 * Decide what the maximum file size for downloaded attachments is. |
|
1194 * Default is 0 (unlimited), can be filtered via import_attachment_size_limit |
|
1195 * |
|
1196 * @return int Maximum attachment file size to import |
|
1197 */ |
|
1198 function max_attachment_size() { |
|
1199 return apply_filters( 'import_attachment_size_limit', 0 ); |
|
1200 } |
|
1201 |
|
1202 /** |
|
1203 * Added to http_request_timeout filter to force timeout at 60 seconds during import |
|
1204 * @return int 60 |
|
1205 */ |
|
1206 function bump_request_timeout( $val ) { |
|
1207 return 60; |
|
1208 } |
|
1209 |
|
1210 // return the difference in length between two strings |
|
1211 function cmpr_strlen( $a, $b ) { |
|
1212 return strlen($b) - strlen($a); |
|
1213 } |
|
1214 } |
|
1215 |
|
1216 } // class_exists( 'WP_Importer' ) |
|
1217 |
|
1218 function wordpress_importer_init() { |
|
1219 load_plugin_textdomain( 'wordpress-importer' ); |
|
1220 |
|
1221 /** |
|
1222 * WordPress Importer object for registering the import callback |
|
1223 * @global WP_Import $wp_import |
|
1224 */ |
|
1225 $GLOBALS['wp_import'] = new WP_Import(); |
|
1226 register_importer( 'wordpress', 'WordPress', __('Import <strong>posts, pages, comments, custom fields, categories, and tags</strong> from a WordPress export file.', 'wordpress-importer'), array( $GLOBALS['wp_import'], 'dispatch' ) ); |
|
1227 } |
|
1228 add_action( 'admin_init', 'wordpress_importer_init' ); |
|