web/wp-content/plugins/wordpress-importer/wordpress-importer.php
changeset 204 09a1c134465b
equal deleted inserted replaced
203:f507feede89a 204:09a1c134465b
       
     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
       
     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 		if ( empty( $this->categories ) )
       
   397 			return;
       
   398 
       
   399 		foreach ( $this->categories as $cat ) {
       
   400 			// if the category already exists leave it alone
       
   401 			$term_id = term_exists( $cat['category_nicename'], 'category' );
       
   402 			if ( $term_id ) {
       
   403 				if ( is_array($term_id) ) $term_id = $term_id['term_id'];
       
   404 				if ( isset($cat['term_id']) )
       
   405 					$this->processed_terms[intval($cat['term_id'])] = (int) $term_id;
       
   406 				continue;
       
   407 			}
       
   408 
       
   409 			$category_parent = empty( $cat['category_parent'] ) ? 0 : category_exists( $cat['category_parent'] );
       
   410 			$category_description = isset( $cat['category_description'] ) ? $cat['category_description'] : '';
       
   411 			$catarr = array(
       
   412 				'category_nicename' => $cat['category_nicename'],
       
   413 				'category_parent' => $category_parent,
       
   414 				'cat_name' => $cat['cat_name'],
       
   415 				'category_description' => $category_description
       
   416 			);
       
   417 
       
   418 			$id = wp_insert_category( $catarr );
       
   419 			if ( ! is_wp_error( $id ) ) {
       
   420 				if ( isset($cat['term_id']) )
       
   421 					$this->processed_terms[intval($cat['term_id'])] = $id;
       
   422 			} else {
       
   423 				printf( __( 'Failed to import category %s', 'wordpress-importer' ), esc_html($cat['category_nicename']) );
       
   424 				if ( defined('IMPORT_DEBUG') && IMPORT_DEBUG )
       
   425 					echo ': ' . $id->get_error_message();
       
   426 				echo '<br />';
       
   427 				continue;
       
   428 			}
       
   429 		}
       
   430 
       
   431 		unset( $this->categories );
       
   432 	}
       
   433 
       
   434 	/**
       
   435 	 * Create new post tags based on import information
       
   436 	 *
       
   437 	 * Doesn't create a tag if its slug already exists
       
   438 	 */
       
   439 	function process_tags() {
       
   440 		if ( empty( $this->tags ) )
       
   441 			return;
       
   442 
       
   443 		foreach ( $this->tags as $tag ) {
       
   444 			// if the tag already exists leave it alone
       
   445 			$term_id = term_exists( $tag['tag_slug'], 'post_tag' );
       
   446 			if ( $term_id ) {
       
   447 				if ( is_array($term_id) ) $term_id = $term_id['term_id'];
       
   448 				if ( isset($tag['term_id']) )
       
   449 					$this->processed_terms[intval($tag['term_id'])] = (int) $term_id;
       
   450 				continue;
       
   451 			}
       
   452 
       
   453 			$tag_desc = isset( $tag['tag_description'] ) ? $tag['tag_description'] : '';
       
   454 			$tagarr = array( 'slug' => $tag['tag_slug'], 'description' => $tag_desc );
       
   455 
       
   456 			$id = wp_insert_term( $tag['tag_name'], 'post_tag', $tagarr );
       
   457 			if ( ! is_wp_error( $id ) ) {
       
   458 				if ( isset($tag['term_id']) )
       
   459 					$this->processed_terms[intval($tag['term_id'])] = $id['term_id'];
       
   460 			} else {
       
   461 				printf( __( 'Failed to import post tag %s', 'wordpress-importer' ), esc_html($tag['tag_name']) );
       
   462 				if ( defined('IMPORT_DEBUG') && IMPORT_DEBUG )
       
   463 					echo ': ' . $id->get_error_message();
       
   464 				echo '<br />';
       
   465 				continue;
       
   466 			}
       
   467 		}
       
   468 
       
   469 		unset( $this->tags );
       
   470 	}
       
   471 
       
   472 	/**
       
   473 	 * Create new terms based on import information
       
   474 	 *
       
   475 	 * Doesn't create a term its slug already exists
       
   476 	 */
       
   477 	function process_terms() {
       
   478 		if ( empty( $this->terms ) )
       
   479 			return;
       
   480 
       
   481 		foreach ( $this->terms as $term ) {
       
   482 			// if the term already exists in the correct taxonomy leave it alone
       
   483 			$term_id = term_exists( $term['slug'], $term['term_taxonomy'] );
       
   484 			if ( $term_id ) {
       
   485 				if ( is_array($term_id) ) $term_id = $term_id['term_id'];
       
   486 				if ( isset($term['term_id']) )
       
   487 					$this->processed_terms[intval($term['term_id'])] = (int) $term_id;
       
   488 				continue;
       
   489 			}
       
   490 
       
   491 			if ( empty( $term['term_parent'] ) ) {
       
   492 				$parent = 0;
       
   493 			} else {
       
   494 				$parent = term_exists( $term['term_parent'], $term['term_taxonomy'] );
       
   495 				if ( is_array( $parent ) ) $parent = $parent['term_id'];
       
   496 			}
       
   497 			$description = isset( $term['term_description'] ) ? $term['term_description'] : '';
       
   498 			$termarr = array( 'slug' => $term['slug'], 'description' => $description, 'parent' => intval($parent) );
       
   499 
       
   500 			$id = wp_insert_term( $term['term_name'], $term['term_taxonomy'], $termarr );
       
   501 			if ( ! is_wp_error( $id ) ) {
       
   502 				if ( isset($term['term_id']) )
       
   503 					$this->processed_terms[intval($term['term_id'])] = $id['term_id'];
       
   504 			} else {
       
   505 				printf( __( 'Failed to import %s %s', 'wordpress-importer' ), esc_html($term['term_taxonomy']), esc_html($term['term_name']) );
       
   506 				if ( defined('IMPORT_DEBUG') && IMPORT_DEBUG )
       
   507 					echo ': ' . $id->get_error_message();
       
   508 				echo '<br />';
       
   509 				continue;
       
   510 			}
       
   511 		}
       
   512 
       
   513 		unset( $this->terms );
       
   514 	}
       
   515 
       
   516 	/**
       
   517 	 * Create new posts based on import information
       
   518 	 *
       
   519 	 * Posts marked as having a parent which doesn't exist will become top level items.
       
   520 	 * Doesn't create a new post if: the post type doesn't exist, the given post ID
       
   521 	 * is already noted as imported or a post with the same title and date already exists.
       
   522 	 * Note that new/updated terms, comments and meta are imported for the last of the above.
       
   523 	 */
       
   524 	function process_posts() {
       
   525 		foreach ( $this->posts as $post ) {
       
   526 			if ( ! post_type_exists( $post['post_type'] ) ) {
       
   527 				printf( __( 'Failed to import &#8220;%s&#8221;: Invalid post type %s', 'wordpress-importer' ),
       
   528 					esc_html($post['post_title']), esc_html($post['post_type']) );
       
   529 				echo '<br />';
       
   530 				continue;
       
   531 			}
       
   532 
       
   533 			if ( isset( $this->processed_posts[$post['post_id']] ) && ! empty( $post['post_id'] ) )
       
   534 				continue;
       
   535 
       
   536 			if ( $post['status'] == 'auto-draft' )
       
   537 				continue;
       
   538 
       
   539 			if ( 'nav_menu_item' == $post['post_type'] ) {
       
   540 				$this->process_menu_item( $post );
       
   541 				continue;
       
   542 			}
       
   543 
       
   544 			$post_type_object = get_post_type_object( $post['post_type'] );
       
   545 
       
   546 			$post_exists = post_exists( $post['post_title'], '', $post['post_date'] );
       
   547 			if ( $post_exists && get_post_type( $post_exists ) == $post['post_type'] ) {
       
   548 				printf( __('%s &#8220;%s&#8221; already exists.', 'wordpress-importer'), $post_type_object->labels->singular_name, esc_html($post['post_title']) );
       
   549 				echo '<br />';
       
   550 				$comment_post_ID = $post_id = $post_exists;
       
   551 			} else {
       
   552 				$post_parent = (int) $post['post_parent'];
       
   553 				if ( $post_parent ) {
       
   554 					// if we already know the parent, map it to the new local ID
       
   555 					if ( isset( $this->processed_posts[$post_parent] ) ) {
       
   556 						$post_parent = $this->processed_posts[$post_parent];
       
   557 					// otherwise record the parent for later
       
   558 					} else {
       
   559 						$this->post_orphans[intval($post['post_id'])] = $post_parent;
       
   560 						$post_parent = 0;
       
   561 					}
       
   562 				}
       
   563 
       
   564 				// map the post author
       
   565 				$author = sanitize_user( $post['post_author'], true );
       
   566 				if ( isset( $this->author_mapping[$author] ) )
       
   567 					$author = $this->author_mapping[$author];
       
   568 				else
       
   569 					$author = (int) get_current_user_id();
       
   570 
       
   571 				$postdata = array(
       
   572 					'import_id' => $post['post_id'], 'post_author' => $author, 'post_date' => $post['post_date'],
       
   573 					'post_date_gmt' => $post['post_date_gmt'], 'post_content' => $post['post_content'],
       
   574 					'post_excerpt' => $post['post_excerpt'], 'post_title' => $post['post_title'],
       
   575 					'post_status' => $post['status'], 'post_name' => $post['post_name'],
       
   576 					'comment_status' => $post['comment_status'], 'ping_status' => $post['ping_status'],
       
   577 					'guid' => $post['guid'], 'post_parent' => $post_parent, 'menu_order' => $post['menu_order'],
       
   578 					'post_type' => $post['post_type'], 'post_password' => $post['post_password']
       
   579 				);
       
   580 
       
   581 				if ( 'attachment' == $postdata['post_type'] ) {
       
   582 					$remote_url = ! empty($post['attachment_url']) ? $post['attachment_url'] : $post['guid'];
       
   583 
       
   584 					// try to use _wp_attached file for upload folder placement to ensure the same location as the export site
       
   585 					// e.g. location is 2003/05/image.jpg but the attachment post_date is 2010/09, see media_handle_upload()
       
   586 					$postdata['upload_date'] = $post['post_date'];
       
   587 					if ( isset( $post['postmeta'] ) ) {
       
   588 						foreach( $post['postmeta'] as $meta ) {
       
   589 							if ( $meta['key'] == '_wp_attached_file' ) {
       
   590 								if ( preg_match( '%^[0-9]{4}/[0-9]{2}%', $meta['value'], $matches ) )
       
   591 									$postdata['upload_date'] = $matches[0];
       
   592 								break;
       
   593 							}
       
   594 						}
       
   595 					}
       
   596 
       
   597 					$comment_post_ID = $post_id = $this->process_attachment( $postdata, $remote_url );
       
   598 				} else {
       
   599 					$comment_post_ID = $post_id = wp_insert_post( $postdata, true );
       
   600 				}
       
   601 
       
   602 				if ( is_wp_error( $post_id ) ) {
       
   603 					printf( __( 'Failed to import %s &#8220;%s&#8221;', 'wordpress-importer' ),
       
   604 						$post_type_object->labels->singular_name, esc_html($post['post_title']) );
       
   605 					if ( defined('IMPORT_DEBUG') && IMPORT_DEBUG )
       
   606 						echo ': ' . $post_id->get_error_message();
       
   607 					echo '<br />';
       
   608 					continue;
       
   609 				}
       
   610 
       
   611 				if ( $post['is_sticky'] == 1 )
       
   612 					stick_post( $post_id );
       
   613 			}
       
   614 
       
   615 			// map pre-import ID to local ID
       
   616 			$this->processed_posts[intval($post['post_id'])] = (int) $post_id;
       
   617 
       
   618 			// add categories, tags and other terms
       
   619 			if ( ! empty( $post['terms'] ) ) {
       
   620 				$terms_to_set = array();
       
   621 				foreach ( $post['terms'] as $term ) {
       
   622 					// back compat with WXR 1.0 map 'tag' to 'post_tag'
       
   623 					$taxonomy = ( 'tag' == $term['domain'] ) ? 'post_tag' : $term['domain'];
       
   624 					$term_exists = term_exists( $term['slug'], $taxonomy );
       
   625 					$term_id = is_array( $term_exists ) ? $term_exists['term_id'] : $term_exists;
       
   626 					if ( ! $term_id ) {
       
   627 						$t = wp_insert_term( $term['name'], $taxonomy, array( 'slug' => $term['slug'] ) );
       
   628 						if ( ! is_wp_error( $t ) ) {
       
   629 							$term_id = $t['term_id'];
       
   630 						} else {
       
   631 							printf( __( 'Failed to import %s %s', 'wordpress-importer' ), esc_html($taxonomy), esc_html($term['name']) );
       
   632 							if ( defined('IMPORT_DEBUG') && IMPORT_DEBUG )
       
   633 								echo ': ' . $t->get_error_message();
       
   634 							echo '<br />';
       
   635 							continue;
       
   636 						}
       
   637 					}
       
   638 					$terms_to_set[$taxonomy][] = intval( $term_id );
       
   639 				}
       
   640 
       
   641 				foreach ( $terms_to_set as $tax => $ids ) {
       
   642 					$tt_ids = wp_set_post_terms( $post_id, $ids, $tax );
       
   643 				}
       
   644 				unset( $post['terms'], $terms_to_set );
       
   645 			}
       
   646 
       
   647 			// add/update comments
       
   648 			if ( ! empty( $post['comments'] ) ) {
       
   649 				$num_comments = 0;
       
   650 				$inserted_comments = array();
       
   651 				foreach ( $post['comments'] as $comment ) {
       
   652 					$comment_id	= $comment['comment_id'];
       
   653 					$newcomments[$comment_id]['comment_post_ID']      = $comment_post_ID;
       
   654 					$newcomments[$comment_id]['comment_author']       = $comment['comment_author'];
       
   655 					$newcomments[$comment_id]['comment_author_email'] = $comment['comment_author_email'];
       
   656 					$newcomments[$comment_id]['comment_author_IP']    = $comment['comment_author_IP'];
       
   657 					$newcomments[$comment_id]['comment_author_url']   = $comment['comment_author_url'];
       
   658 					$newcomments[$comment_id]['comment_date']         = $comment['comment_date'];
       
   659 					$newcomments[$comment_id]['comment_date_gmt']     = $comment['comment_date_gmt'];
       
   660 					$newcomments[$comment_id]['comment_content']      = $comment['comment_content'];
       
   661 					$newcomments[$comment_id]['comment_approved']     = $comment['comment_approved'];
       
   662 					$newcomments[$comment_id]['comment_type']         = $comment['comment_type'];
       
   663 					$newcomments[$comment_id]['comment_parent'] 	  = $comment['comment_parent'];
       
   664 					$newcomments[$comment_id]['commentmeta']          = isset( $comment['commentmeta'] ) ? $comment['commentmeta'] : array();
       
   665 					if ( isset( $this->processed_authors[$comment['comment_user_id']] ) )
       
   666 						$newcomments[$comment_id]['user_id'] = $this->processed_authors[$comment['comment_user_id']];
       
   667 				}
       
   668 				ksort( $newcomments );
       
   669 
       
   670 				foreach ( $newcomments as $key => $comment ) {
       
   671 					// if this is a new post we can skip the comment_exists() check
       
   672 					if ( ! $post_exists || ! comment_exists( $comment['comment_author'], $comment['comment_date'] ) ) {
       
   673 						if ( isset( $inserted_comments[$comment['comment_parent']] ) )
       
   674 							$comment['comment_parent'] = $inserted_comments[$comment['comment_parent']];
       
   675 						$comment = wp_filter_comment( $comment );
       
   676 						$inserted_comments[$key] = wp_insert_comment( $comment );
       
   677 
       
   678 						foreach( $comment['commentmeta'] as $meta ) {
       
   679 							$value = maybe_unserialize( $meta['value'] );
       
   680 							add_comment_meta( $inserted_comments[$key], $meta['key'], $value );
       
   681 						}
       
   682 
       
   683 						$num_comments++;
       
   684 					}
       
   685 				}
       
   686 				unset( $newcomments, $inserted_comments, $post['comments'] );
       
   687 			}
       
   688 
       
   689 			// add/update post meta
       
   690 			if ( isset( $post['postmeta'] ) ) {
       
   691 				foreach ( $post['postmeta'] as $meta ) {
       
   692 					$key = apply_filters( 'import_post_meta_key', $meta['key'] );
       
   693 					$value = false;
       
   694 
       
   695 					if ( '_edit_last' == $key ) {
       
   696 						if ( isset( $this->processed_authors[intval($meta['value'])] ) )
       
   697 							$value = $this->processed_authors[intval($meta['value'])];
       
   698 						else
       
   699 							$key = false;
       
   700 					}
       
   701 
       
   702 					if ( $key ) {
       
   703 						// export gets meta straight from the DB so could have a serialized string
       
   704 						if ( ! $value )
       
   705 							$value = maybe_unserialize( $meta['value'] );
       
   706 
       
   707 						add_post_meta( $post_id, $key, $value );
       
   708 						do_action( 'import_post_meta', $post_id, $key, $value );
       
   709 
       
   710 						// if the post has a featured image, take note of this in case of remap
       
   711 						if ( '_thumbnail_id' == $key )
       
   712 							$this->featured_images[$post_id] = (int) $value;
       
   713 					}
       
   714 				}
       
   715 			}
       
   716 		}
       
   717 
       
   718 		unset( $this->posts );
       
   719 	}
       
   720 
       
   721 	/**
       
   722 	 * Attempt to create a new menu item from import data
       
   723 	 *
       
   724 	 * Fails for draft, orphaned menu items and those without an associated nav_menu
       
   725 	 * or an invalid nav_menu term. If the post type or term object which the menu item
       
   726 	 * represents doesn't exist then the menu item will not be imported (waits until the
       
   727 	 * end of the import to retry again before discarding).
       
   728 	 *
       
   729 	 * @param array $item Menu item details from WXR file
       
   730 	 */
       
   731 	function process_menu_item( $item ) {
       
   732 		// skip draft, orphaned menu items
       
   733 		if ( 'draft' == $item['status'] )
       
   734 			return;
       
   735 
       
   736 		$menu_slug = false;
       
   737 		if ( isset($item['terms']) ) {
       
   738 			// loop through terms, assume first nav_menu term is correct menu
       
   739 			foreach ( $item['terms'] as $term ) {
       
   740 				if ( 'nav_menu' == $term['domain'] ) {
       
   741 					$menu_slug = $term['slug'];
       
   742 					break;
       
   743 				}
       
   744 			}
       
   745 		}
       
   746 
       
   747 		// no nav_menu term associated with this menu item
       
   748 		if ( ! $menu_slug ) {
       
   749 			_e( 'Menu item skipped due to missing menu slug', 'wordpress-importer' );
       
   750 			echo '<br />';
       
   751 			return;
       
   752 		}
       
   753 
       
   754 		$menu_id = term_exists( $menu_slug, 'nav_menu' );
       
   755 		if ( ! $menu_id ) {
       
   756 			printf( __( 'Menu item skipped due to invalid menu slug: %s', 'wordpress-importer' ), esc_html( $menu_slug ) );
       
   757 			echo '<br />';
       
   758 			return;
       
   759 		} else {
       
   760 			$menu_id = is_array( $menu_id ) ? $menu_id['term_id'] : $menu_id;
       
   761 		}
       
   762 
       
   763 		foreach ( $item['postmeta'] as $meta )
       
   764 			$$meta['key'] = $meta['value'];
       
   765 
       
   766 		if ( 'taxonomy' == $_menu_item_type && isset( $this->processed_terms[intval($_menu_item_object_id)] ) ) {
       
   767 			$_menu_item_object_id = $this->processed_terms[intval($_menu_item_object_id)];
       
   768 		} else if ( 'post_type' == $_menu_item_type && isset( $this->processed_posts[intval($_menu_item_object_id)] ) ) {
       
   769 			$_menu_item_object_id = $this->processed_posts[intval($_menu_item_object_id)];
       
   770 		} else if ( 'custom' != $_menu_item_type ) {
       
   771 			// associated object is missing or not imported yet, we'll retry later
       
   772 			$this->missing_menu_items[] = $item;
       
   773 			return;
       
   774 		}
       
   775 
       
   776 		if ( isset( $this->processed_menu_items[intval($_menu_item_menu_item_parent)] ) ) {
       
   777 			$_menu_item_menu_item_parent = $this->processed_menu_items[intval($_menu_item_menu_item_parent)];
       
   778 		} else if ( $_menu_item_menu_item_parent ) {
       
   779 			$this->menu_item_orphans[intval($item['post_id'])] = (int) $_menu_item_menu_item_parent;
       
   780 			$_menu_item_menu_item_parent = 0;
       
   781 		}
       
   782 
       
   783 		// wp_update_nav_menu_item expects CSS classes as a space separated string
       
   784 		$_menu_item_classes = maybe_unserialize( $_menu_item_classes );
       
   785 		if ( is_array( $_menu_item_classes ) )
       
   786 			$_menu_item_classes = implode( ' ', $_menu_item_classes );
       
   787 
       
   788 		$args = array(
       
   789 			'menu-item-object-id' => $_menu_item_object_id,
       
   790 			'menu-item-object' => $_menu_item_object,
       
   791 			'menu-item-parent-id' => $_menu_item_menu_item_parent,
       
   792 			'menu-item-position' => intval( $item['menu_order'] ),
       
   793 			'menu-item-type' => $_menu_item_type,
       
   794 			'menu-item-title' => $item['post_title'],
       
   795 			'menu-item-url' => $_menu_item_url,
       
   796 			'menu-item-description' => $item['post_content'],
       
   797 			'menu-item-attr-title' => $item['post_excerpt'],
       
   798 			'menu-item-target' => $_menu_item_target,
       
   799 			'menu-item-classes' => $_menu_item_classes,
       
   800 			'menu-item-xfn' => $_menu_item_xfn,
       
   801 			'menu-item-status' => $item['status']
       
   802 		);
       
   803 
       
   804 		$id = wp_update_nav_menu_item( $menu_id, 0, $args );
       
   805 		if ( $id && ! is_wp_error( $id ) )
       
   806 			$this->processed_menu_items[intval($item['post_id'])] = (int) $id;
       
   807 	}
       
   808 
       
   809 	/**
       
   810 	 * If fetching attachments is enabled then attempt to create a new attachment
       
   811 	 *
       
   812 	 * @param array $post Attachment post details from WXR
       
   813 	 * @param string $url URL to fetch attachment from
       
   814 	 * @return int|WP_Error Post ID on success, WP_Error otherwise
       
   815 	 */
       
   816 	function process_attachment( $post, $url ) {
       
   817 		if ( ! $this->fetch_attachments )
       
   818 			return new WP_Error( 'attachment_processing_error',
       
   819 				__( 'Fetching attachments is not enabled', 'wordpress-importer' ) );
       
   820 
       
   821 		// if the URL is absolute, but does not contain address, then upload it assuming base_site_url
       
   822 		if ( preg_match( '|^/[\w\W]+$|', $url ) )
       
   823 			$url = rtrim( $this->base_url, '/' ) . $url;
       
   824 
       
   825 		$upload = $this->fetch_remote_file( $url, $post );
       
   826 		if ( is_wp_error( $upload ) )
       
   827 			return $upload;
       
   828 
       
   829 		if ( $info = wp_check_filetype( $upload['file'] ) )
       
   830 			$post['post_mime_type'] = $info['type'];
       
   831 		else
       
   832 			return new WP_Error( 'attachment_processing_error', __('Invalid file type', 'wordpress-importer') );
       
   833 
       
   834 		$post['guid'] = $upload['url'];
       
   835 
       
   836 		// as per wp-admin/includes/upload.php
       
   837 		$post_id = wp_insert_attachment( $post, $upload['file'] );
       
   838 		wp_update_attachment_metadata( $post_id, wp_generate_attachment_metadata( $post_id, $upload['file'] ) );
       
   839 
       
   840 		// remap resized image URLs, works by stripping the extension and remapping the URL stub.
       
   841 		if ( preg_match( '!^image/!', $info['type'] ) ) {
       
   842 			$parts = pathinfo( $url );
       
   843 			$name = basename( $parts['basename'], ".{$parts['extension']}" ); // PATHINFO_FILENAME in PHP 5.2
       
   844 
       
   845 			$parts_new = pathinfo( $upload['url'] );
       
   846 			$name_new = basename( $parts_new['basename'], ".{$parts_new['extension']}" );
       
   847 
       
   848 			$this->url_remap[$parts['dirname'] . '/' . $name] = $parts_new['dirname'] . '/' . $name_new;
       
   849 		}
       
   850 
       
   851 		return $post_id;
       
   852 	}
       
   853 
       
   854 	/**
       
   855 	 * Attempt to download a remote file attachment
       
   856 	 *
       
   857 	 * @param string $url URL of item to fetch
       
   858 	 * @param array $post Attachment details
       
   859 	 * @return array|WP_Error Local file location details on success, WP_Error otherwise
       
   860 	 */
       
   861 	function fetch_remote_file( $url, $post ) {
       
   862 		// extract the file name and extension from the url
       
   863 		$file_name = basename( $url );
       
   864 
       
   865 		// get placeholder file in the upload dir with a unique, sanitized filename
       
   866 		$upload = wp_upload_bits( $file_name, 0, '', $post['upload_date'] );
       
   867 		if ( $upload['error'] )
       
   868 			return new WP_Error( 'upload_dir_error', $upload['error'] );
       
   869 
       
   870 		// fetch the remote url and write it to the placeholder file
       
   871 		$headers = wp_get_http( $url, $upload['file'] );
       
   872 
       
   873 		// request failed
       
   874 		if ( ! $headers ) {
       
   875 			@unlink( $upload['file'] );
       
   876 			return new WP_Error( 'import_file_error', __('Remote server did not respond', 'wordpress-importer') );
       
   877 		}
       
   878 
       
   879 		// make sure the fetch was successful
       
   880 		if ( $headers['response'] != '200' ) {
       
   881 			@unlink( $upload['file'] );
       
   882 			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']) ) );
       
   883 		}
       
   884 
       
   885 		$filesize = filesize( $upload['file'] );
       
   886 
       
   887 		if ( isset( $headers['content-length'] ) && $filesize != $headers['content-length'] ) {
       
   888 			@unlink( $upload['file'] );
       
   889 			return new WP_Error( 'import_file_error', __('Remote file is incorrect size', 'wordpress-importer') );
       
   890 		}
       
   891 
       
   892 		if ( 0 == $filesize ) {
       
   893 			@unlink( $upload['file'] );
       
   894 			return new WP_Error( 'import_file_error', __('Zero size file downloaded', 'wordpress-importer') );
       
   895 		}
       
   896 
       
   897 		$max_size = (int) $this->max_attachment_size();
       
   898 		if ( ! empty( $max_size ) && $filesize > $max_size ) {
       
   899 			@unlink( $upload['file'] );
       
   900 			return new WP_Error( 'import_file_error', sprintf(__('Remote file is too large, limit is %s', 'wordpress-importer'), size_format($max_size) ) );
       
   901 		}
       
   902 
       
   903 		// keep track of the old and new urls so we can substitute them later
       
   904 		$this->url_remap[$url] = $upload['url'];
       
   905 		$this->url_remap[$post['guid']] = $upload['url']; // r13735, really needed?
       
   906 		// keep track of the destination if the remote url is redirected somewhere else
       
   907 		if ( isset($headers['x-final-location']) && $headers['x-final-location'] != $url )
       
   908 			$this->url_remap[$headers['x-final-location']] = $upload['url'];
       
   909 
       
   910 		return $upload;
       
   911 	}
       
   912 
       
   913 	/**
       
   914 	 * Attempt to associate posts and menu items with previously missing parents
       
   915 	 *
       
   916 	 * An imported post's parent may not have been imported when it was first created
       
   917 	 * so try again. Similarly for child menu items and menu items which were missing
       
   918 	 * the object (e.g. post) they represent in the menu
       
   919 	 */
       
   920 	function backfill_parents() {
       
   921 		global $wpdb;
       
   922 
       
   923 		// find parents for post orphans
       
   924 		foreach ( $this->post_orphans as $child_id => $parent_id ) {
       
   925 			$local_child_id = $local_parent_id = false;
       
   926 			if ( isset( $this->processed_posts[$child_id] ) )
       
   927 				$local_child_id = $this->processed_posts[$child_id];
       
   928 			if ( isset( $this->processed_posts[$parent_id] ) )
       
   929 				$local_parent_id = $this->processed_posts[$parent_id];
       
   930 
       
   931 			if ( $local_child_id && $local_parent_id )
       
   932 				$wpdb->update( $wpdb->posts, array( 'post_parent' => $local_parent_id ), array( 'ID' => $local_child_id ), '%d', '%d' );
       
   933 		}
       
   934 
       
   935 		// all other posts/terms are imported, retry menu items with missing associated object
       
   936 		$missing_menu_items = $this->missing_menu_items;
       
   937 		foreach ( $missing_menu_items as $item )
       
   938 			$this->process_menu_item( $item );
       
   939 
       
   940 		// find parents for menu item orphans
       
   941 		foreach ( $this->menu_item_orphans as $child_id => $parent_id ) {
       
   942 			$local_child_id = $local_parent_id = 0;
       
   943 			if ( isset( $this->processed_menu_items[$child_id] ) )
       
   944 				$local_child_id = $this->processed_menu_items[$child_id];
       
   945 			if ( isset( $this->processed_menu_items[$parent_id] ) )
       
   946 				$local_parent_id = $this->processed_menu_items[$parent_id];
       
   947 
       
   948 			if ( $local_child_id && $local_parent_id )
       
   949 				update_post_meta( $local_child_id, '_menu_item_menu_item_parent', (int) $local_parent_id );
       
   950 		}
       
   951 	}
       
   952 
       
   953 	/**
       
   954 	 * Use stored mapping information to update old attachment URLs
       
   955 	 */
       
   956 	function backfill_attachment_urls() {
       
   957 		global $wpdb;
       
   958 		// make sure we do the longest urls first, in case one is a substring of another
       
   959 		uksort( $this->url_remap, array(&$this, 'cmpr_strlen') );
       
   960 
       
   961 		foreach ( $this->url_remap as $from_url => $to_url ) {
       
   962 			// remap urls in post_content
       
   963 			$wpdb->query( $wpdb->prepare("UPDATE {$wpdb->posts} SET post_content = REPLACE(post_content, %s, %s)", $from_url, $to_url) );
       
   964 			// remap enclosure urls
       
   965 			$result = $wpdb->query( $wpdb->prepare("UPDATE {$wpdb->postmeta} SET meta_value = REPLACE(meta_value, %s, %s) WHERE meta_key='enclosure'", $from_url, $to_url) );
       
   966 		}
       
   967 	}
       
   968 
       
   969 	/**
       
   970 	 * Update _thumbnail_id meta to new, imported attachment IDs
       
   971 	 */
       
   972 	function remap_featured_images() {
       
   973 		// cycle through posts that have a featured image
       
   974 		foreach ( $this->featured_images as $post_id => $value ) {
       
   975 			if ( isset( $this->processed_posts[$value] ) ) {
       
   976 				$new_id = $this->processed_posts[$value];
       
   977 				// only update if there's a difference
       
   978 				if ( $new_id != $value )
       
   979 					update_post_meta( $post_id, '_thumbnail_id', $new_id );
       
   980 			}
       
   981 		}
       
   982 	}
       
   983 
       
   984 	/**
       
   985 	 * Parse a WXR file
       
   986 	 *
       
   987 	 * @param string $file Path to WXR file for parsing
       
   988 	 * @return array Information gathered from the WXR file
       
   989 	 */
       
   990 	function parse( $file ) {
       
   991 		$parser = new WXR_Parser();
       
   992 		return $parser->parse( $file );
       
   993 	}
       
   994 
       
   995 	// Display import page title
       
   996 	function header() {
       
   997 		echo '<div class="wrap">';
       
   998 		screen_icon();
       
   999 		echo '<h2>' . __( 'Import WordPress', 'wordpress-importer' ) . '</h2>';
       
  1000 
       
  1001 		$updates = get_plugin_updates();
       
  1002 		$basename = plugin_basename(__FILE__);
       
  1003 		if ( isset( $updates[$basename] ) ) {
       
  1004 			$update = $updates[$basename];
       
  1005 			echo '<div class="error"><p><strong>';
       
  1006 			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 );
       
  1007 			echo '</strong></p></div>';
       
  1008 		}
       
  1009 	}
       
  1010 
       
  1011 	// Close div.wrap
       
  1012 	function footer() {
       
  1013 		echo '</div>';
       
  1014 	}
       
  1015 
       
  1016 	/**
       
  1017 	 * Display introductory text and file upload form
       
  1018 	 */
       
  1019 	function greet() {
       
  1020 		echo '<div class="narrow">';
       
  1021 		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>';
       
  1022 		echo '<p>'.__( 'Choose a WXR (.xml) file to upload, then click Upload file and import.', 'wordpress-importer' ).'</p>';
       
  1023 		wp_import_upload_form( 'admin.php?import=wordpress&amp;step=1' );
       
  1024 		echo '</div>';
       
  1025 	}
       
  1026 
       
  1027 	/**
       
  1028 	 * Decide if the given meta key maps to information we will want to import
       
  1029 	 *
       
  1030 	 * @param string $key The meta key to check
       
  1031 	 * @return string|bool The key if we do want to import, false if not
       
  1032 	 */
       
  1033 	function is_valid_meta_key( $key ) {
       
  1034 		// skip attachment metadata since we'll regenerate it from scratch
       
  1035 		// skip _edit_lock as not relevant for import
       
  1036 		if ( in_array( $key, array( '_wp_attached_file', '_wp_attachment_metadata', '_edit_lock' ) ) )
       
  1037 			return false;
       
  1038 		return $key;
       
  1039 	}
       
  1040 
       
  1041 	/**
       
  1042 	 * Decide whether or not the importer is allowed to create users.
       
  1043 	 * Default is true, can be filtered via import_allow_create_users
       
  1044 	 *
       
  1045 	 * @return bool True if creating users is allowed
       
  1046 	 */
       
  1047 	function allow_create_users() {
       
  1048 		return apply_filters( 'import_allow_create_users', true );
       
  1049 	}
       
  1050 
       
  1051 	/**
       
  1052 	 * Decide whether or not the importer should attempt to download attachment files.
       
  1053 	 * Default is true, can be filtered via import_allow_fetch_attachments. The choice
       
  1054 	 * made at the import options screen must also be true, false here hides that checkbox.
       
  1055 	 *
       
  1056 	 * @return bool True if downloading attachments is allowed
       
  1057 	 */
       
  1058 	function allow_fetch_attachments() {
       
  1059 		return apply_filters( 'import_allow_fetch_attachments', true );
       
  1060 	}
       
  1061 
       
  1062 	/**
       
  1063 	 * Decide what the maximum file size for downloaded attachments is.
       
  1064 	 * Default is 0 (unlimited), can be filtered via import_attachment_size_limit
       
  1065 	 *
       
  1066 	 * @return int Maximum attachment file size to import
       
  1067 	 */
       
  1068 	function max_attachment_size() {
       
  1069 		return apply_filters( 'import_attachment_size_limit', 0 );
       
  1070 	}
       
  1071 
       
  1072 	/**
       
  1073 	 * Added to http_request_timeout filter to force timeout at 60 seconds during import
       
  1074 	 * @return int 60
       
  1075 	 */
       
  1076 	function bump_request_timeout() {
       
  1077 		return 60;
       
  1078 	}
       
  1079 
       
  1080 	// return the difference in length between two strings
       
  1081 	function cmpr_strlen( $a, $b ) {
       
  1082 		return strlen($b) - strlen($a);
       
  1083 	}
       
  1084 }
       
  1085 
       
  1086 } // class_exists( 'WP_Importer' )
       
  1087 
       
  1088 function wordpress_importer_init() {
       
  1089 	load_plugin_textdomain( 'wordpress-importer', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' );
       
  1090 
       
  1091 	/**
       
  1092 	 * WordPress Importer object for registering the import callback
       
  1093 	 * @global WP_Import $wp_import
       
  1094 	 */
       
  1095 	$GLOBALS['wp_import'] = new WP_Import();
       
  1096 	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' ) );
       
  1097 }
       
  1098 add_action( 'admin_init', 'wordpress_importer_init' );