]> scripts.mit.edu Git - autoinstalls/wordpress.git/blob - wp-admin/import/wordpress.php
Wordpress 2.9
[autoinstalls/wordpress.git] / wp-admin / import / wordpress.php
1 <?php
2 /**
3  * WordPress Importer
4  *
5  * @package WordPress
6  * @subpackage Importer
7  */
8
9 /**
10  * WordPress Importer
11  *
12  * Will process the WordPress eXtended RSS files that you upload from the export
13  * file.
14  *
15  * @since unknown
16  */
17 class WP_Import {
18
19         var $post_ids_processed = array ();
20         var $orphans = array ();
21         var $file;
22         var $id;
23         var $mtnames = array ();
24         var $newauthornames = array ();
25         var $allauthornames = array ();
26
27         var $author_ids = array ();
28         var $tags = array ();
29         var $categories = array ();
30         var $terms = array ();
31
32         var $j = -1;
33         var $fetch_attachments = false;
34         var $url_remap = array ();
35
36         function header() {
37                 echo '<div class="wrap">';
38                 screen_icon();
39                 echo '<h2>'.__('Import WordPress').'</h2>';
40         }
41
42         function footer() {
43                 echo '</div>';
44         }
45
46         function unhtmlentities($string) { // From php.net for < 4.3 compat
47                 $trans_tbl = get_html_translation_table(HTML_ENTITIES);
48                 $trans_tbl = array_flip($trans_tbl);
49                 return strtr($string, $trans_tbl);
50         }
51
52         function greet() {
53                 echo '<div class="narrow">';
54                 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 blog.').'</p>';
55                 echo '<p>'.__('Choose a WordPress WXR file to upload, then click Upload file and import.').'</p>';
56                 wp_import_upload_form("admin.php?import=wordpress&amp;step=1");
57                 echo '</div>';
58         }
59
60         function get_tag( $string, $tag ) {
61                 global $wpdb;
62                 preg_match("|<$tag.*?>(.*?)</$tag>|is", $string, $return);
63                 $return = preg_replace('|^<!\[CDATA\[(.*)\]\]>$|s', '$1', $return[1]);
64                 $return = $wpdb->escape( trim( $return ) );
65                 return $return;
66         }
67
68         function has_gzip() {
69                 return is_callable('gzopen');
70         }
71
72         function fopen($filename, $mode='r') {
73                 if ( $this->has_gzip() )
74                         return gzopen($filename, $mode);
75                 return fopen($filename, $mode);
76         }
77
78         function feof($fp) {
79                 if ( $this->has_gzip() )
80                         return gzeof($fp);
81                 return feof($fp);
82         }
83
84         function fgets($fp, $len=8192) {
85                 if ( $this->has_gzip() )
86                         return gzgets($fp, $len);
87                 return fgets($fp, $len);
88         }
89
90         function fclose($fp) {
91                 if ( $this->has_gzip() )
92                         return gzclose($fp);
93                 return fclose($fp);
94         }
95
96         function get_entries($process_post_func=NULL) {
97                 set_magic_quotes_runtime(0);
98
99                 $doing_entry = false;
100                 $is_wxr_file = false;
101
102                 $fp = $this->fopen($this->file, 'r');
103                 if ($fp) {
104                         while ( !$this->feof($fp) ) {
105                                 $importline = rtrim($this->fgets($fp));
106
107                                 // this doesn't check that the file is perfectly valid but will at least confirm that it's not the wrong format altogether
108                                 if ( !$is_wxr_file && preg_match('|xmlns:wp="http://wordpress[.]org/export/\d+[.]\d+/"|', $importline) )
109                                         $is_wxr_file = true;
110
111                                 if ( false !== strpos($importline, '<wp:base_site_url>') ) {
112                                         preg_match('|<wp:base_site_url>(.*?)</wp:base_site_url>|is', $importline, $url);
113                                         $this->base_url = $url[1];
114                                         continue;
115                                 }
116                                 if ( false !== strpos($importline, '<wp:category>') ) {
117                                         preg_match('|<wp:category>(.*?)</wp:category>|is', $importline, $category);
118                                         $this->categories[] = $category[1];
119                                         continue;
120                                 }
121                                 if ( false !== strpos($importline, '<wp:tag>') ) {
122                                         preg_match('|<wp:tag>(.*?)</wp:tag>|is', $importline, $tag);
123                                         $this->tags[] = $tag[1];
124                                         continue;
125                                 }
126                                 if ( false !== strpos($importline, '<wp:term>') ) {
127                                         preg_match('|<wp:term>(.*?)</wp:term>|is', $importline, $term);
128                                         $this->terms[] = $term[1];
129                                         continue;
130                                 }
131                                 if ( false !== strpos($importline, '<item>') ) {
132                                         $this->post = '';
133                                         $doing_entry = true;
134                                         continue;
135                                 }
136                                 if ( false !== strpos($importline, '</item>') ) {
137                                         $doing_entry = false;
138                                         if ($process_post_func)
139                                                 call_user_func($process_post_func, $this->post);
140                                         continue;
141                                 }
142                                 if ( $doing_entry ) {
143                                         $this->post .= $importline . "\n";
144                                 }
145                         }
146
147                         $this->fclose($fp);
148                 }
149
150                 return $is_wxr_file;
151
152         }
153
154         function get_wp_authors() {
155                 // We need to find unique values of author names, while preserving the order, so this function emulates the unique_value(); php function, without the sorting.
156                 $temp = $this->allauthornames;
157                 $authors[0] = array_shift($temp);
158                 $y = count($temp) + 1;
159                 for ($x = 1; $x < $y; $x ++) {
160                         $next = array_shift($temp);
161                         if (!(in_array($next, $authors)))
162                                 array_push($authors, "$next");
163                 }
164
165                 return $authors;
166         }
167
168         function get_authors_from_post() {
169                 global $current_user;
170
171                 // this will populate $this->author_ids with a list of author_names => user_ids
172
173                 foreach ( $_POST['author_in'] as $i => $in_author_name ) {
174
175                         if ( !empty($_POST['user_select'][$i]) ) {
176                                 // an existing user was selected in the dropdown list
177                                 $user = get_userdata( intval($_POST['user_select'][$i]) );
178                                 if ( isset($user->ID) )
179                                         $this->author_ids[$in_author_name] = $user->ID;
180                         }
181                         elseif ( $this->allow_create_users() ) {
182                                 // nothing was selected in the dropdown list, so we'll use the name in the text field
183
184                                 $new_author_name = trim($_POST['user_create'][$i]);
185                                 // if the user didn't enter a name, assume they want to use the same name as in the import file
186                                 if ( empty($new_author_name) )
187                                         $new_author_name = $in_author_name;
188
189                                 $user_id = username_exists($new_author_name);
190                                 if ( !$user_id ) {
191                                         $user_id = wp_create_user($new_author_name, wp_generate_password());
192                                 }
193
194                                 $this->author_ids[$in_author_name] = $user_id;
195                         }
196
197                         // failsafe: if the user_id was invalid, default to the current user
198                         if ( empty($this->author_ids[$in_author_name]) ) {
199                                 $this->author_ids[$in_author_name] = intval($current_user->ID);
200                         }
201                 }
202
203         }
204
205         function wp_authors_form() {
206 ?>
207 <h2><?php _e('Assign Authors'); ?></h2>
208 <p><?php _e('To make it easier for you to edit and save the imported posts and drafts, you may want to change the name of the author of the posts. For example, you may want to import all the entries as <code>admin</code>s entries.'); ?></p>
209 <?php
210         if ( $this->allow_create_users() ) {
211                 echo '<p>'.__('If a new user is created by WordPress, a password will be randomly generated. Manually change the user&#8217;s details if necessary.')."</p>\n";
212         }
213
214
215                 $authors = $this->get_wp_authors();
216                 echo '<form action="?import=wordpress&amp;step=2&amp;id=' . $this->id . '" method="post">';
217                 wp_nonce_field('import-wordpress');
218 ?>
219 <ol id="authors">
220 <?php
221                 $j = -1;
222                 foreach ($authors as $author) {
223                         ++ $j;
224                         echo '<li>'.__('Import author:').' <strong>'.$author.'</strong><br />';
225                         $this->users_form($j, $author);
226                         echo '</li>';
227                 }
228
229                 if ( $this->allow_fetch_attachments() ) {
230 ?>
231 </ol>
232 <h2><?php _e('Import Attachments'); ?></h2>
233 <p>
234         <input type="checkbox" value="1" name="attachments" id="import-attachments" />
235         <label for="import-attachments"><?php _e('Download and import file attachments') ?></label>
236 </p>
237
238 <?php
239                 }
240
241                 echo '<p class="submit">';
242                 echo '<input type="submit" class="button" value="'. esc_attr__('Submit') .'" />'.'<br />';
243                 echo '</p>';
244                 echo '</form>';
245
246         }
247
248         function users_form($n, $author) {
249
250                 if ( $this->allow_create_users() ) {
251                         printf('<label>'.__('Create user %1$s or map to existing'), ' <input type="text" value="'. esc_attr($author) .'" name="'.'user_create['.intval($n).']'.'" maxlength="30" /></label> <br />');
252                 }
253                 else {
254                         echo __('Map to existing').'<br />';
255                 }
256
257                 // keep track of $n => $author name
258                 echo '<input type="hidden" name="author_in['.intval($n).']" value="' . esc_attr($author).'" />';
259
260                 $users = get_users_of_blog();
261 ?><select name="user_select[<?php echo $n; ?>]">
262         <option value="0"><?php _e('- Select -'); ?></option>
263         <?php
264                 foreach ($users as $user) {
265                         echo '<option value="'.$user->user_id.'">'.$user->user_login.'</option>';
266                 }
267 ?>
268         </select>
269         <?php
270         }
271
272         function select_authors() {
273                 $is_wxr_file = $this->get_entries(array(&$this, 'process_author'));
274                 if ( $is_wxr_file ) {
275                         $this->wp_authors_form();
276                 }
277                 else {
278                         echo '<h2>'.__('Invalid file').'</h2>';
279                         echo '<p>'.__('Please upload a valid WXR (WordPress eXtended RSS) export file.').'</p>';
280                 }
281         }
282
283         // fetch the user ID for a given author name, respecting the mapping preferences
284         function checkauthor($author) {
285                 global $current_user;
286
287                 if ( !empty($this->author_ids[$author]) )
288                         return $this->author_ids[$author];
289
290                 // failsafe: map to the current user
291                 return $current_user->ID;
292         }
293
294
295
296         function process_categories() {
297                 global $wpdb;
298
299                 $cat_names = (array) get_terms('category', 'fields=names');
300
301                 while ( $c = array_shift($this->categories) ) {
302                         $cat_name = trim($this->get_tag( $c, 'wp:cat_name' ));
303
304                         // If the category exists we leave it alone
305                         if ( in_array($cat_name, $cat_names) )
306                                 continue;
307
308                         $category_nicename      = $this->get_tag( $c, 'wp:category_nicename' );
309                         $category_description = $this->get_tag( $c, 'wp:category_description' );
310                         $posts_private          = (int) $this->get_tag( $c, 'wp:posts_private' );
311                         $links_private          = (int) $this->get_tag( $c, 'wp:links_private' );
312
313                         $parent = $this->get_tag( $c, 'wp:category_parent' );
314
315                         if ( empty($parent) )
316                                 $category_parent = '0';
317                         else
318                                 $category_parent = category_exists($parent);
319
320                         $catarr = compact('category_nicename', 'category_parent', 'posts_private', 'links_private', 'posts_private', 'cat_name', 'category_description');
321
322                         $cat_ID = wp_insert_category($catarr);
323                 }
324         }
325
326         function process_tags() {
327                 global $wpdb;
328
329                 $tag_names = (array) get_terms('post_tag', 'fields=names');
330
331                 while ( $c = array_shift($this->tags) ) {
332                         $tag_name = trim($this->get_tag( $c, 'wp:tag_name' ));
333
334                         // If the category exists we leave it alone
335                         if ( in_array($tag_name, $tag_names) )
336                                 continue;
337
338                         $slug = $this->get_tag( $c, 'wp:tag_slug' );
339                         $description = $this->get_tag( $c, 'wp:tag_description' );
340
341                         $tagarr = compact('slug', 'description');
342
343                         $tag_ID = wp_insert_term($tag_name, 'post_tag', $tagarr);
344                 }
345         }
346         
347         function process_terms() {
348                 global $wpdb, $wp_taxonomies;
349                 
350                 $custom_taxonomies = $wp_taxonomies;
351                 // get rid of the standard taxonomies
352                 unset( $custom_taxonomies['category'] );
353                 unset( $custom_taxonomies['post_tag'] );
354                 unset( $custom_taxonomies['link_category'] );
355                 
356                 $custom_taxonomies = array_keys( $custom_taxonomies );
357                 $current_terms = (array) get_terms( $custom_taxonomies, 'get=all' );
358                 $taxonomies = array();
359                 foreach ( $current_terms as $term ) {
360                         if ( isset( $_terms[$term->taxonomy] ) ) {
361                                 $taxonomies[$term->taxonomy] = array_merge( $taxonomies[$term->taxonomy], array($term->name) );
362                         } else {
363                                 $taxonomies[$term->taxonomy] = array($term->name);
364                         }
365                 }
366
367                 while ( $c = array_shift($this->terms) ) {
368                         $term_name = trim($this->get_tag( $c, 'wp:term_name' ));
369                         $term_taxonomy = trim($this->get_tag( $c, 'wp:term_taxonomy' ));
370
371                         // If the term exists in the taxonomy we leave it alone
372                         if ( isset($taxonomies[$term_taxonomy] ) && in_array( $term_name, $taxonomies[$term_taxonomy] ) )
373                                 continue;
374
375                         $slug = $this->get_tag( $c, 'wp:term_slug' );
376                         $description = $this->get_tag( $c, 'wp:term_description' );
377
378                         $termarr = compact('slug', 'description');
379
380                         $term_ID = wp_insert_term($term_name, $this->get_tag( $c, 'wp:term_taxonomy' ), $termarr);
381                 }
382         }
383
384         function process_author($post) {
385                 $author = $this->get_tag( $post, 'dc:creator' );
386                 if ($author)
387                         $this->allauthornames[] = $author;
388         }
389
390         function process_posts() {
391                 echo '<ol>';
392
393                 $this->get_entries(array(&$this, 'process_post'));
394
395                 echo '</ol>';
396
397                 wp_import_cleanup($this->id);
398                 do_action('import_done', 'wordpress');
399
400                 echo '<h3>'.sprintf(__('All done.').' <a href="%s">'.__('Have fun!').'</a>', get_option('home')).'</h3>';
401         }
402
403         function _normalize_tag( $matches ) {
404                 return '<' . strtolower( $matches[1] );
405         }
406
407         function process_post($post) {
408                 global $wpdb;
409
410                 $post_ID = (int) $this->get_tag( $post, 'wp:post_id' );
411                 if ( $post_ID && !empty($this->post_ids_processed[$post_ID]) ) // Processed already
412                         return 0;
413
414                 set_time_limit( 60 );
415
416                 // There are only ever one of these
417                 $post_title     = $this->get_tag( $post, 'title' );
418                 $post_date      = $this->get_tag( $post, 'wp:post_date' );
419                 $post_date_gmt  = $this->get_tag( $post, 'wp:post_date_gmt' );
420                 $comment_status = $this->get_tag( $post, 'wp:comment_status' );
421                 $ping_status    = $this->get_tag( $post, 'wp:ping_status' );
422                 $post_status    = $this->get_tag( $post, 'wp:status' );
423                 $post_name      = $this->get_tag( $post, 'wp:post_name' );
424                 $post_parent    = $this->get_tag( $post, 'wp:post_parent' );
425                 $menu_order     = $this->get_tag( $post, 'wp:menu_order' );
426                 $post_type      = $this->get_tag( $post, 'wp:post_type' );
427                 $post_password  = $this->get_tag( $post, 'wp:post_password' );
428                 $is_sticky              = $this->get_tag( $post, 'wp:is_sticky' );
429                 $guid           = $this->get_tag( $post, 'guid' );
430                 $post_author    = $this->get_tag( $post, 'dc:creator' );
431
432                 $post_excerpt = $this->get_tag( $post, 'excerpt:encoded' );
433                 $post_excerpt = preg_replace_callback('|<(/?[A-Z]+)|', array( &$this, '_normalize_tag' ), $post_excerpt);
434                 $post_excerpt = str_replace('<br>', '<br />', $post_excerpt);
435                 $post_excerpt = str_replace('<hr>', '<hr />', $post_excerpt);
436
437                 $post_content = $this->get_tag( $post, 'content:encoded' );
438                 $post_content = preg_replace_callback('|<(/?[A-Z]+)|', array( &$this, '_normalize_tag' ), $post_content);
439                 $post_content = str_replace('<br>', '<br />', $post_content);
440                 $post_content = str_replace('<hr>', '<hr />', $post_content);
441
442                 preg_match_all('|<category domain="tag">(.*?)</category>|is', $post, $tags);
443                 $tags = $tags[1];
444
445                 $tag_index = 0;
446                 foreach ($tags as $tag) {
447                         $tags[$tag_index] = $wpdb->escape($this->unhtmlentities(str_replace(array ('<![CDATA[', ']]>'), '', $tag)));
448                         $tag_index++;
449                 }
450
451                 preg_match_all('|<category>(.*?)</category>|is', $post, $categories);
452                 $categories = $categories[1];
453
454                 $cat_index = 0;
455                 foreach ($categories as $category) {
456                         $categories[$cat_index] = $wpdb->escape($this->unhtmlentities(str_replace(array ('<![CDATA[', ']]>'), '', $category)));
457                         $cat_index++;
458                 }
459
460                 $post_exists = post_exists($post_title, '', $post_date);
461
462                 if ( $post_exists ) {
463                         echo '<li>';
464                         printf(__('Post <em>%s</em> already exists.'), stripslashes($post_title));
465                         $comment_post_ID = $post_id = $post_exists;
466                 } else {
467
468                         // If it has parent, process parent first.
469                         $post_parent = (int) $post_parent;
470                         if ($post_parent) {
471                                 // if we already know the parent, map it to the local ID
472                                 if ( $parent = $this->post_ids_processed[$post_parent] ) {
473                                         $post_parent = $parent;  // new ID of the parent
474                                 }
475                                 else {
476                                         // record the parent for later
477                                         $this->orphans[intval($post_ID)] = $post_parent;
478                                 }
479                         }
480
481                         echo '<li>';
482
483                         $post_author = $this->checkauthor($post_author); //just so that if a post already exists, new users are not created by checkauthor
484
485                         $postdata = compact('post_author', 'post_date', 'post_date_gmt', 'post_content', 'post_excerpt', 'post_title', 'post_status', 'post_name', 'comment_status', 'ping_status', 'guid', 'post_parent', 'menu_order', 'post_type', 'post_password');
486                         $postdata['import_id'] = $post_ID;
487                         if ($post_type == 'attachment') {
488                                 $remote_url = $this->get_tag( $post, 'wp:attachment_url' );
489                                 if ( !$remote_url )
490                                         $remote_url = $guid;
491
492                                 $comment_post_ID = $post_id = $this->process_attachment($postdata, $remote_url);
493                                 if ( !$post_id or is_wp_error($post_id) )
494                                         return $post_id;
495                         }
496                         else {
497                                 printf(__('Importing post <em>%s</em>...'), stripslashes($post_title));
498                                 $comment_post_ID = $post_id = wp_insert_post($postdata);
499                                 if ( $post_id && $is_sticky == 1 )
500                                         stick_post( $post_id );
501
502                         }
503
504                         if ( is_wp_error( $post_id ) )
505                                 return $post_id;
506
507                         // Memorize old and new ID.
508                         if ( $post_id && $post_ID ) {
509                                 $this->post_ids_processed[intval($post_ID)] = intval($post_id);
510                         }
511
512                         // Add categories.
513                         if (count($categories) > 0) {
514                                 $post_cats = array();
515                                 foreach ($categories as $category) {
516                                         if ( '' == $category )
517                                                 continue;
518                                         $slug = sanitize_term_field('slug', $category, 0, 'category', 'db');
519                                         $cat = get_term_by('slug', $slug, 'category');
520                                         $cat_ID = 0;
521                                         if ( ! empty($cat) )
522                                                 $cat_ID = $cat->term_id;
523                                         if ($cat_ID == 0) {
524                                                 $category = $wpdb->escape($category);
525                                                 $cat_ID = wp_insert_category(array('cat_name' => $category));
526                                                 if ( is_wp_error($cat_ID) )
527                                                         continue;
528                                         }
529                                         $post_cats[] = $cat_ID;
530                                 }
531                                 wp_set_post_categories($post_id, $post_cats);
532                         }
533
534                         // Add tags.
535                         if (count($tags) > 0) {
536                                 $post_tags = array();
537                                 foreach ($tags as $tag) {
538                                         if ( '' == $tag )
539                                                 continue;
540                                         $slug = sanitize_term_field('slug', $tag, 0, 'post_tag', 'db');
541                                         $tag_obj = get_term_by('slug', $slug, 'post_tag');
542                                         $tag_id = 0;
543                                         if ( ! empty($tag_obj) )
544                                                 $tag_id = $tag_obj->term_id;
545                                         if ( $tag_id == 0 ) {
546                                                 $tag = $wpdb->escape($tag);
547                                                 $tag_id = wp_insert_term($tag, 'post_tag');
548                                                 if ( is_wp_error($tag_id) )
549                                                         continue;
550                                                 $tag_id = $tag_id['term_id'];
551                                         }
552                                         $post_tags[] = intval($tag_id);
553                                 }
554                                 wp_set_post_tags($post_id, $post_tags);
555                         }
556                 }
557
558                 // Now for comments
559                 preg_match_all('|<wp:comment>(.*?)</wp:comment>|is', $post, $comments);
560                 $comments = $comments[1];
561                 $num_comments = 0;
562                 $inserted_comments = array();
563                 if ( $comments) { 
564                         foreach ($comments as $comment) {
565                                 $comment_id     = $this->get_tag( $comment, 'wp:comment_id');
566                                 $newcomments[$comment_id]['comment_post_ID']      = $comment_post_ID;
567                                 $newcomments[$comment_id]['comment_author']       = $this->get_tag( $comment, 'wp:comment_author');
568                                 $newcomments[$comment_id]['comment_author_email'] = $this->get_tag( $comment, 'wp:comment_author_email');
569                                 $newcomments[$comment_id]['comment_author_IP']    = $this->get_tag( $comment, 'wp:comment_author_IP');
570                                 $newcomments[$comment_id]['comment_author_url']   = $this->get_tag( $comment, 'wp:comment_author_url');
571                                 $newcomments[$comment_id]['comment_date']         = $this->get_tag( $comment, 'wp:comment_date');
572                                 $newcomments[$comment_id]['comment_date_gmt']     = $this->get_tag( $comment, 'wp:comment_date_gmt');
573                                 $newcomments[$comment_id]['comment_content']      = $this->get_tag( $comment, 'wp:comment_content');
574                                 $newcomments[$comment_id]['comment_approved']     = $this->get_tag( $comment, 'wp:comment_approved');
575                                 $newcomments[$comment_id]['comment_type']         = $this->get_tag( $comment, 'wp:comment_type');
576                                 $newcomments[$comment_id]['comment_parent']       = $this->get_tag( $comment, 'wp:comment_parent');
577                         }
578                         // Sort by comment ID, to make sure comment parents exist (if there at all)
579                         ksort($newcomments);
580                         foreach ($newcomments as $key => $comment) {
581                                 // if this is a new post we can skip the comment_exists() check
582                                 if ( !$post_exists || !comment_exists($comment['comment_author'], $comment['comment_date']) ) {
583                                         if (isset($inserted_comments[$comment['comment_parent']]))
584                                                 $comment['comment_parent'] = $inserted_comments[$comment['comment_parent']];
585                                         $comment = wp_filter_comment($comment);
586                                         $inserted_comments[$key] = wp_insert_comment($comment);
587                                         $num_comments++;
588                                 }
589                         }
590                 }
591
592                 if ( $num_comments )
593                         printf(' '._n('(%s comment)', '(%s comments)', $num_comments), $num_comments);
594
595                 // Now for post meta
596                 preg_match_all('|<wp:postmeta>(.*?)</wp:postmeta>|is', $post, $postmeta);
597                 $postmeta = $postmeta[1];
598                 if ( $postmeta) { foreach ($postmeta as $p) {
599                         $key   = $this->get_tag( $p, 'wp:meta_key' );
600                         $value = $this->get_tag( $p, 'wp:meta_value' );
601                         $value = stripslashes($value); // add_post_meta() will escape.
602
603                         $this->process_post_meta($post_id, $key, $value);
604
605                 } }
606
607                 do_action('import_post_added', $post_id);
608                 print "</li>\n";
609         }
610
611         function process_post_meta($post_id, $key, $value) {
612                 // the filter can return false to skip a particular metadata key
613                 $_key = apply_filters('import_post_meta_key', $key);
614                 if ( $_key ) {
615                         add_post_meta( $post_id, $_key, $value );
616                         do_action('import_post_meta', $post_id, $_key, $value);
617                 }
618         }
619
620         function process_attachment($postdata, $remote_url) {
621                 if ($this->fetch_attachments and $remote_url) {
622                         printf( __('Importing attachment <em>%s</em>... '), htmlspecialchars($remote_url) );
623
624                         // If the URL is absolute, but does not contain http, upload it assuming the base_site_url variable
625                         if ( preg_match('/^\/[\w\W]+$/', $remote_url) )
626                                 $remote_url = rtrim($this->base_url,'/').$remote_url;
627
628                         $upload = $this->fetch_remote_file($postdata, $remote_url);
629                         if ( is_wp_error($upload) ) {
630                                 printf( __('Remote file error: %s'), htmlspecialchars($upload->get_error_message()) );
631                                 return $upload;
632                         }
633                         else {
634                                 print '('.size_format(filesize($upload['file'])).')';
635                         }
636
637                         if ( $info = wp_check_filetype($upload['file']) ) {
638                                 $postdata['post_mime_type'] = $info['type'];
639                         }
640                         else {
641                                 print __('Invalid file type');
642                                 return;
643                         }
644
645                         $postdata['guid'] = $upload['url'];
646
647                         // as per wp-admin/includes/upload.php
648                         $post_id = wp_insert_attachment($postdata, $upload['file']);
649                         wp_update_attachment_metadata( $post_id, wp_generate_attachment_metadata( $post_id, $upload['file'] ) );
650
651                         // remap the thumbnail url.  this isn't perfect because we're just guessing the original url.
652                         if ( preg_match('@^image/@', $info['type']) && $thumb_url = wp_get_attachment_thumb_url($post_id) ) {
653                                 $parts = pathinfo($remote_url);
654                                 $ext = $parts['extension'];
655                                 $name = basename($parts['basename'], ".{$ext}");
656                                 $this->url_remap[$parts['dirname'] . '/' . $name . '.thumbnail.' . $ext] = $thumb_url;
657                         }
658
659                         return $post_id;
660                 }
661                 else {
662                         printf( __('Skipping attachment <em>%s</em>'), htmlspecialchars($remote_url) );
663                 }
664         }
665
666         function fetch_remote_file($post, $url) {
667                 $upload = wp_upload_dir($post['post_date']);
668
669                 // extract the file name and extension from the url
670                 $file_name = basename($url);
671
672                 // get placeholder file in the upload dir with a unique sanitized filename
673                 $upload = wp_upload_bits( $file_name, 0, '', $post['post_date']);
674                 if ( $upload['error'] ) {
675                         echo $upload['error'];
676                         return new WP_Error( 'upload_dir_error', $upload['error'] );
677                 }
678
679                 // fetch the remote url and write it to the placeholder file
680                 $headers = wp_get_http($url, $upload['file']);
681
682                 //Request failed
683                 if ( ! $headers ) {
684                         @unlink($upload['file']);
685                         return new WP_Error( 'import_file_error', __('Remote server did not respond') );
686                 }
687
688                 // make sure the fetch was successful
689                 if ( $headers['response'] != '200' ) {
690                         @unlink($upload['file']);
691                         return new WP_Error( 'import_file_error', sprintf(__('Remote file returned error response %1$d %2$s'), $headers['response'], get_status_header_desc($headers['response']) ) );
692                 }
693                 elseif ( isset($headers['content-length']) && filesize($upload['file']) != $headers['content-length'] ) {
694                         @unlink($upload['file']);
695                         return new WP_Error( 'import_file_error', __('Remote file is incorrect size') );
696                 }
697
698                 $max_size = $this->max_attachment_size();
699                 if ( !empty($max_size) and filesize($upload['file']) > $max_size ) {
700                         @unlink($upload['file']);
701                         return new WP_Error( 'import_file_error', sprintf(__('Remote file is too large, limit is %s', size_format($max_size))) );
702                 }
703
704                 // keep track of the old and new urls so we can substitute them later
705                 $this->url_remap[$url] = $upload['url'];
706                 // if the remote url is redirected somewhere else, keep track of the destination too
707                 if ( $headers['x-final-location'] != $url )
708                         $this->url_remap[$headers['x-final-location']] = $upload['url'];
709
710                 return $upload;
711
712         }
713
714         // sort by strlen, longest string first
715         function cmpr_strlen($a, $b) {
716                 return strlen($b) - strlen($a);
717         }
718
719         // update url references in post bodies to point to the new local files
720         function backfill_attachment_urls() {
721
722                 // make sure we do the longest urls first, in case one is a substring of another
723                 uksort($this->url_remap, array(&$this, 'cmpr_strlen'));
724
725                 global $wpdb;
726                 foreach ($this->url_remap as $from_url => $to_url) {
727                         // remap urls in post_content
728                         $wpdb->query( $wpdb->prepare("UPDATE {$wpdb->posts} SET post_content = REPLACE(post_content, '%s', '%s')", $from_url, $to_url) );
729                         // remap enclosure urls
730                         $result = $wpdb->query( $wpdb->prepare("UPDATE {$wpdb->postmeta} SET meta_value = REPLACE(meta_value, '%s', '%s') WHERE meta_key='enclosure'", $from_url, $to_url) );
731                 }
732         }
733
734         // update the post_parent of orphans now that we know the local id's of all parents
735         function backfill_parents() {
736                 global $wpdb;
737
738                 foreach ($this->orphans as $child_id => $parent_id) {
739                         $local_child_id = $this->post_ids_processed[$child_id];
740                         $local_parent_id = $this->post_ids_processed[$parent_id];
741                         if ($local_child_id and $local_parent_id) {
742                                 $wpdb->query( $wpdb->prepare("UPDATE {$wpdb->posts} SET post_parent = %d WHERE ID = %d", $local_parent_id, $local_child_id));
743                         }
744                 }
745         }
746
747         function is_valid_meta_key($key) {
748                 // skip attachment metadata since we'll regenerate it from scratch
749                 if ( $key == '_wp_attached_file' || $key == '_wp_attachment_metadata' )
750                         return false;
751                 return $key;
752         }
753
754         // give the user the option of creating new users to represent authors in the import file?
755         function allow_create_users() {
756                 return apply_filters('import_allow_create_users', true);
757         }
758
759         // give the user the option of downloading and importing attached files
760         function allow_fetch_attachments() {
761                 return apply_filters('import_allow_fetch_attachments', true);
762         }
763
764         function max_attachment_size() {
765                 // can be overridden with a filter - 0 means no limit
766                 return apply_filters('import_attachment_size_limit', 0);
767         }
768
769         function import_start() {
770                 wp_defer_term_counting(true);
771                 wp_defer_comment_counting(true);
772                 do_action('import_start');
773         }
774
775         function import_end() {
776                 do_action('import_end');
777
778                 // clear the caches after backfilling
779                 foreach ($this->post_ids_processed as $post_id)
780                         clean_post_cache($post_id);
781
782                 wp_defer_term_counting(false);
783                 wp_defer_comment_counting(false);
784         }
785
786         function import($id, $fetch_attachments = false) {
787                 $this->id = (int) $id;
788                 $this->fetch_attachments = ($this->allow_fetch_attachments() && (bool) $fetch_attachments);
789
790                 add_filter('import_post_meta_key', array($this, 'is_valid_meta_key'));
791                 $file = get_attached_file($this->id);
792                 $this->import_file($file);
793         }
794
795         function import_file($file) {
796                 $this->file = $file;
797
798                 $this->import_start();
799                 $this->get_authors_from_post();
800                 wp_suspend_cache_invalidation(true);
801                 $this->get_entries();
802                 $this->process_categories();
803                 $this->process_tags();
804                 $this->process_terms();
805                 $result = $this->process_posts();
806                 wp_suspend_cache_invalidation(false);
807                 $this->backfill_parents();
808                 $this->backfill_attachment_urls();
809                 $this->import_end();
810
811                 if ( is_wp_error( $result ) )
812                         return $result;
813         }
814
815         function handle_upload() {
816                 $file = wp_import_handle_upload();
817                 if ( isset($file['error']) ) {
818                         echo '<p>'.__('Sorry, there has been an error.').'</p>';
819                         echo '<p><strong>' . $file['error'] . '</strong></p>';
820                         return false;
821                 }
822                 $this->file = $file['file'];
823                 $this->id = (int) $file['id'];
824                 return true;
825         }
826
827         function dispatch() {
828                 if (empty ($_GET['step']))
829                         $step = 0;
830                 else
831                         $step = (int) $_GET['step'];
832
833                 $this->header();
834                 switch ($step) {
835                         case 0 :
836                                 $this->greet();
837                                 break;
838                         case 1 :
839                                 check_admin_referer('import-upload');
840                                 if ( $this->handle_upload() )
841                                         $this->select_authors();
842                                 break;
843                         case 2:
844                                 check_admin_referer('import-wordpress');
845                                 $result = $this->import( $_GET['id'], $_POST['attachments'] );
846                                 if ( is_wp_error( $result ) )
847                                         echo $result->get_error_message();
848                                 break;
849                 }
850                 $this->footer();
851         }
852
853         function WP_Import() {
854                 // Nothing.
855         }
856 }
857
858 /**
859  * Register WordPress Importer
860  *
861  * @since unknown
862  * @var WP_Import
863  * @name $wp_import
864  */
865 $wp_import = new WP_Import();
866
867 register_importer('wordpress', 'WordPress', __('Import <strong>posts, pages, comments, custom fields, categories, and tags</strong> from a WordPress export file.'), array ($wp_import, 'dispatch'));
868
869 ?>