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