wp/wp-content/plugins/wordpress-importer/wordpress-importer.php
changeset 0 d970ebf37754
child 7 cf61fcea0001
equal deleted inserted replaced
-1:000000000000 0:d970ebf37754
       
     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 	function WP_Import() { /* 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 		screen_icon();
       
  1033 		echo '<h2>' . __( 'Import WordPress', 'wordpress-importer' ) . '</h2>';
       
  1034 
       
  1035 		$updates = get_plugin_updates();
       
  1036 		$basename = plugin_basename(__FILE__);
       
  1037 		if ( isset( $updates[$basename] ) ) {
       
  1038 			$update = $updates[$basename];
       
  1039 			echo '<div class="error"><p><strong>';
       
  1040 			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 );
       
  1041 			echo '</strong></p></div>';
       
  1042 		}
       
  1043 	}
       
  1044 
       
  1045 	// Close div.wrap
       
  1046 	function footer() {
       
  1047 		echo '</div>';
       
  1048 	}
       
  1049 
       
  1050 	/**
       
  1051 	 * Display introductory text and file upload form
       
  1052 	 */
       
  1053 	function greet() {
       
  1054 		echo '<div class="narrow">';
       
  1055 		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>';
       
  1056 		echo '<p>'.__( 'Choose a WXR (.xml) file to upload, then click Upload file and import.', 'wordpress-importer' ).'</p>';
       
  1057 		wp_import_upload_form( 'admin.php?import=wordpress&amp;step=1' );
       
  1058 		echo '</div>';
       
  1059 	}
       
  1060 
       
  1061 	/**
       
  1062 	 * Decide if the given meta key maps to information we will want to import
       
  1063 	 *
       
  1064 	 * @param string $key The meta key to check
       
  1065 	 * @return string|bool The key if we do want to import, false if not
       
  1066 	 */
       
  1067 	function is_valid_meta_key( $key ) {
       
  1068 		// skip attachment metadata since we'll regenerate it from scratch
       
  1069 		// skip _edit_lock as not relevant for import
       
  1070 		if ( in_array( $key, array( '_wp_attached_file', '_wp_attachment_metadata', '_edit_lock' ) ) )
       
  1071 			return false;
       
  1072 		return $key;
       
  1073 	}
       
  1074 
       
  1075 	/**
       
  1076 	 * Decide whether or not the importer is allowed to create users.
       
  1077 	 * Default is true, can be filtered via import_allow_create_users
       
  1078 	 *
       
  1079 	 * @return bool True if creating users is allowed
       
  1080 	 */
       
  1081 	function allow_create_users() {
       
  1082 		return apply_filters( 'import_allow_create_users', true );
       
  1083 	}
       
  1084 
       
  1085 	/**
       
  1086 	 * Decide whether or not the importer should attempt to download attachment files.
       
  1087 	 * Default is true, can be filtered via import_allow_fetch_attachments. The choice
       
  1088 	 * made at the import options screen must also be true, false here hides that checkbox.
       
  1089 	 *
       
  1090 	 * @return bool True if downloading attachments is allowed
       
  1091 	 */
       
  1092 	function allow_fetch_attachments() {
       
  1093 		return apply_filters( 'import_allow_fetch_attachments', true );
       
  1094 	}
       
  1095 
       
  1096 	/**
       
  1097 	 * Decide what the maximum file size for downloaded attachments is.
       
  1098 	 * Default is 0 (unlimited), can be filtered via import_attachment_size_limit
       
  1099 	 *
       
  1100 	 * @return int Maximum attachment file size to import
       
  1101 	 */
       
  1102 	function max_attachment_size() {
       
  1103 		return apply_filters( 'import_attachment_size_limit', 0 );
       
  1104 	}
       
  1105 
       
  1106 	/**
       
  1107 	 * Added to http_request_timeout filter to force timeout at 60 seconds during import
       
  1108 	 * @return int 60
       
  1109 	 */
       
  1110 	function bump_request_timeout() {
       
  1111 		return 60;
       
  1112 	}
       
  1113 
       
  1114 	// return the difference in length between two strings
       
  1115 	function cmpr_strlen( $a, $b ) {
       
  1116 		return strlen($b) - strlen($a);
       
  1117 	}
       
  1118 }
       
  1119 
       
  1120 } // class_exists( 'WP_Importer' )
       
  1121 
       
  1122 function wordpress_importer_init() {
       
  1123 	load_plugin_textdomain( 'wordpress-importer', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' );
       
  1124 
       
  1125 	/**
       
  1126 	 * WordPress Importer object for registering the import callback
       
  1127 	 * @global WP_Import $wp_import
       
  1128 	 */
       
  1129 	$GLOBALS['wp_import'] = new WP_Import();
       
  1130 	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' ) );
       
  1131 }
       
  1132 add_action( 'admin_init', 'wordpress_importer_init' );