Changeset 10475
- Timestamp:
- 01/31/2009 06:41:35 PM (16 years ago)
- Location:
- trunk/wp-admin
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/wp-admin/admin-ajax.php
r10375 r10475 1129 1129 1130 1130 break; 1131 case 'lj-importer' : 1132 check_ajax_referer( 'lj-api-import' ); 1133 if ( !current_user_can( 'publish_posts' ) ) 1134 die('-1'); 1135 if ( empty( $_POST['step'] ) ) 1136 die( '-1' ); 1137 1138 include( ABSPATH . 'wp-admin/import/livejournal.php' ); 1139 $result = $lj_api_import->{ 'step' . ( (int) $_POST['step'] ) }(); 1140 if ( is_wp_error( $result ) ) 1141 echo $result->get_error_message(); 1142 die; 1143 break; 1131 1144 default : 1132 1145 do_action( 'wp_ajax_' . $_POST['action'] ); -
trunk/wp-admin/import/livejournal.php
r10339 r10475 1 1 <?php 2 2 /** 3 * LiveJournal Importer3 * LiveJournal API Importer 4 4 * 5 5 * @package WordPress … … 7 7 */ 8 8 9 // XML-RPC library for communicating with LiveJournal API 10 require_once( ABSPATH . WPINC . '/class-IXR.php' ); 11 12 // Snoopy for getting comments (with cookies) 13 require_once( ABSPATH . WPINC . '/class-snoopy.php' ); 14 9 15 /** 10 * LiveJournal Importer class16 * LiveJournal API Importer class 11 17 * 12 * Imports your LiveJournal XML exported file into WordPress.18 * Imports your LiveJournal contents into WordPress using the LJ API 13 19 * 14 * @since unknown20 * @since 2.7.1 15 21 */ 16 class LJ_Import { 17 18 var $file; 22 class LJ_API_Import { 23 24 var $comments_url = 'http://www.livejournal.com/export_comments.bml'; 25 var $ixr_url = 'http://www.livejournal.com/interface/xmlrpc'; 26 var $ixr; 27 var $username; 28 var $password; 29 var $snoop; 30 var $comment_meta; 31 var $comments; 32 var $usermap; 33 var $postmap; 34 var $pointers = array(); 35 36 // This list taken from LJ, they don't appear to have an API for it 37 var $moods = array( '1' => 'aggravated', 38 '10' => 'discontent', 39 '100' => 'rushed', 40 '101' => 'contemplative', 41 '102' => 'nerdy', 42 '103' => 'geeky', 43 '104' => 'cynical', 44 '105' => 'quixotic', 45 '106' => 'crazy', 46 '107' => 'creative', 47 '108' => 'artistic', 48 '109' => 'pleased', 49 '11' => 'energetic', 50 '110' => 'bitchy', 51 '111' => 'guilty', 52 '112' => 'irritated', 53 '113' => 'blank', 54 '114' => 'apathetic', 55 '115' => 'dorky', 56 '116' => 'impressed', 57 '117' => 'naughty', 58 '118' => 'predatory', 59 '119' => 'dirty', 60 '12' => 'enraged', 61 '120' => 'giddy', 62 '121' => 'surprised', 63 '122' => 'shocked', 64 '123' => 'rejected', 65 '124' => 'numb', 66 '125' => 'cheerful', 67 '126' => 'good', 68 '127' => 'distressed', 69 '128' => 'intimidated', 70 '129' => 'crushed', 71 '13' => 'enthralled', 72 '130' => 'devious', 73 '131' => 'thankful', 74 '132' => 'grateful', 75 '133' => 'jealous', 76 '134' => 'nervous', 77 '14' => 'exhausted', 78 '15' => 'happy', 79 '16' => 'high', 80 '17' => 'horny', 81 '18' => 'hungry', 82 '19' => 'infuriated', 83 '2' => 'angry', 84 '20' => 'irate', 85 '21' => 'jubilant', 86 '22' => 'lonely', 87 '23' => 'moody', 88 '24' => 'pissed off', 89 '25' => 'sad', 90 '26' => 'satisfied', 91 '27' => 'sore', 92 '28' => 'stressed', 93 '29' => 'thirsty', 94 '3' => 'annoyed', 95 '30' => 'thoughtful', 96 '31' => 'tired', 97 '32' => 'touched', 98 '33' => 'lazy', 99 '34' => 'drunk', 100 '35' => 'ditzy', 101 '36' => 'mischievous', 102 '37' => 'morose', 103 '38' => 'gloomy', 104 '39' => 'melancholy', 105 '4' => 'anxious', 106 '40' => 'drained', 107 '41' => 'excited', 108 '42' => 'relieved', 109 '43' => 'hopeful', 110 '44' => 'amused', 111 '45' => 'determined', 112 '46' => 'scared', 113 '47' => 'frustrated', 114 '48' => 'indescribable', 115 '49' => 'sleepy', 116 '5' => 'bored', 117 '51' => 'groggy', 118 '52' => 'hyper', 119 '53' => 'relaxed', 120 '54' => 'restless', 121 '55' => 'disappointed', 122 '56' => 'curious', 123 '57' => 'mellow', 124 '58' => 'peaceful', 125 '59' => 'bouncy', 126 '6' => 'confused', 127 '60' => 'nostalgic', 128 '61' => 'okay', 129 '62' => 'rejuvenated', 130 '63' => 'complacent', 131 '64' => 'content', 132 '65' => 'indifferent', 133 '66' => 'silly', 134 '67' => 'flirty', 135 '68' => 'calm', 136 '69' => 'refreshed', 137 '7' => 'crappy', 138 '70' => 'optimistic', 139 '71' => 'pessimistic', 140 '72' => 'giggly', 141 '73' => 'pensive', 142 '74' => 'uncomfortable', 143 '75' => 'lethargic', 144 '76' => 'listless', 145 '77' => 'recumbent', 146 '78' => 'exanimate', 147 '79' => 'embarrassed', 148 '8' => 'cranky', 149 '80' => 'envious', 150 '81' => 'sympathetic', 151 '82' => 'sick', 152 '83' => 'hot', 153 '84' => 'cold', 154 '85' => 'worried', 155 '86' => 'loved', 156 '87' => 'awake', 157 '88' => 'working', 158 '89' => 'productive', 159 '9' => 'depressed', 160 '90' => 'accomplished', 161 '91' => 'busy', 162 '92' => 'blah', 163 '93' => 'full', 164 '95' => 'grumpy', 165 '96' => 'weird', 166 '97' => 'nauseated', 167 '98' => 'ecstatic', 168 '99' => 'chipper' ); 19 169 20 170 function header() { 21 171 echo '<div class="wrap">'; 22 172 screen_icon(); 23 echo '<h2>' .__('Import LiveJournal').'</h2>';173 echo '<h2>' . __( 'Import LiveJournal' ) . '</h2>'; 24 174 } 25 175 … … 28 178 } 29 179 180 function greet() { 181 ?> 182 <div class="narrow"> 183 <form action="admin.php?import=livejournal" method="post"> 184 <?php wp_nonce_field( 'lj-api-import' ) ?> 185 <?php if ( get_option( 'ljapi_username' ) && get_option( 'ljapi_password' ) ) : ?> 186 <input type="hidden" name="step" value="<?php echo get_option( 'ljapi_step' ) ?>" /> 187 <p><?php _e( 'It looks like you attempted to import your LiveJournal posts previously and got interrupted.' ) ?></p> 188 <p class="submit"> 189 <input type="submit" class="button-primary" value="<?php echo attribute_escape( __( 'Continue previous import' ) ) ?>" /> 190 </p> 191 <p><a href="<?php echo $_SERVER['PHP_SELF'] . '?import=livejournal&step=-1&_wpnonce=' . wp_create_nonce( 'lj-api-import' ) . '&_wp_http_referer=' . attribute_escape( $_SERVER['REQUEST_URI'] ) ?>"><?php _e( 'Cancel & start a new import' ) ?></a></p> 192 <p> 193 <?php else : ?> 194 <input type="hidden" name="step" value="1" /> 195 <p><?php _e( 'Howdy! This importer allows you to connect directly to LiveJournal and download all your entries and comments' ) ?></p> 196 <p><?php _e( 'Enter your LiveJournal username and password below so we can connect to your account:' ) ?></p> 197 198 <table class="form-table"> 199 200 <tr> 201 <th scope="row"><label for="lj_username"><?php _e( 'LiveJournal Username' ) ?></label></th> 202 <td><input type="text" name="lj_username" id="lj_username" class="regular-text" /></td> 203 </tr> 204 205 <tr> 206 <th scope="row"><label for="lj_password"><?php _e( 'LiveJournal Password' ) ?></label></th> 207 <td><input type="password" name="lj_password" id="lj_password" class="regular-text" /></td> 208 </tr> 209 210 </table> 211 212 <p><?php _e( 'If you have any entries on LiveJournal which are marked as private, they will be password-protected when they are imported so that only people who know the password can see them.' ) ?></p> 213 <p><?php _e( "If you don't enter a password, ALL ENTRIES from your LiveJournal will be imported as public posts in WordPress." ) ?></p> 214 <p><?php _e( 'Enter the password you would like to use for all protected entries here:' ) ?></p> 215 <table class="form-table"> 216 217 <tr> 218 <th scope="row"><label for="protected_password"><?php _e( 'Protected Post Password' ) ?></label></th> 219 <td><input type="text" name="protected_password" id="protected_password" class="regular-text" /></td> 220 </tr> 221 222 </table> 223 224 <p><?php _e( "<strong>WARNING:</strong> This can take a really long time if you have a lot of entries in your LiveJournal, or a lot of comments. Ideally, you should only start this process if you can leave your computer alone while it finishes the import." ) ?></p> 225 226 <p class="submit"> 227 <input type="submit" class="button-primary" value="<?php echo attribute_escape( __( 'Connect to LiveJournal and Import' ) ) ?>" /> 228 </p> 229 230 <p><?php _e( '<strong>NOTE:</strong> If the import process is interrupted for <em>any</em> reason, come back to this page and it will continue from where it stopped automatically.' ) ?></p> 231 <?php endif; ?> 232 </form> 233 </div> 234 <?php 235 } 236 30 237 function unhtmlentities($string) { // From php.net for < 4.3 compat 31 238 $trans_tbl = get_html_translation_table(HTML_ENTITIES); … … 33 240 return strtr($string, $trans_tbl); 34 241 } 35 36 function greet() { 37 echo '<div class="narrow">'; 38 echo '<p>'.__('Howdy! Upload your LiveJournal XML export file and we’ll import the posts into this blog.').'</p>'; 39 echo '<p>'.__('Choose a LiveJournal XML file to upload, then click Upload file and import.').'</p>'; 40 wp_import_upload_form("admin.php?import=livejournal&step=1"); 41 echo '</div>'; 42 } 43 242 44 243 function import_posts() { 45 global $wpdb, $current_user; 46 47 set_magic_quotes_runtime(0); 48 $importdata = file($this->file); // Read the file into an array 49 $importdata = implode('', $importdata); // squish it 50 $importdata = str_replace(array ("\r\n", "\r"), "\n", $importdata); 51 52 preg_match_all('|<entry>(.*?)</entry>|is', $importdata, $posts); 53 $posts = $posts[1]; 54 unset($importdata); 244 $total = (int) get_option( 'ljapi_total' ); 245 $count = (int) get_option( 'ljapi_count' ); 246 $lastsync = get_option( 'ljapi_lastsync' ); 247 if ( !$lastsync ) { 248 update_option( 'ljapi_lastsync', '1900-01-01 00:00:00' ); 249 } 250 $sync_item_times = get_option( 'ljapi_sync_item_times' ); 251 if ( !is_array( $sync_item_times ) ) 252 $sync_item_times = array(); 253 254 do { 255 $lastsync = date( 'Y-m-d H:i:s', strtotime( get_option( 'ljapi_lastsync' ) ) ); 256 $synclist = $this->lj_ixr( 'syncitems', array( 'ver' => 1, 'lastsync' => $lastsync ) ); 257 $this->log( $synclist, 'ljimport-items-' . $total . '.txt' ); 258 259 // Keep track of if we've downloaded everything 260 $total = $synclist['total']; 261 $count = $synclist['count']; 262 263 foreach ( $synclist['syncitems'] as $event ) { 264 if ( substr( $event['item'], 0, 2 ) == 'L-' ) { 265 $sync_item_times[ str_replace( 'L-', '', $event['item'] ) ] = $event['time']; 266 if ( $event['time'] > $lastsync ) 267 $lastsync = $event['time']; 268 } 269 } 270 271 update_option( 'ljapi_sync_item_times', $sync_item_times ); 272 update_option( 'ljapi_total', $total ); 273 update_option( 'ljapi_count', $count ); 274 update_option( 'ljapi_lastsync', $lastsync ); 275 } while ( $total > $count ); 276 // endwhile - all post meta is cached locally 277 $this->log( $sync_item_times, 'ljimport-post-mod-times.txt' ); 278 55 279 echo '<ol>'; 56 foreach ($posts as $post) { 57 preg_match('|<subject>(.*?)</subject>|is', $post, $post_title); 58 $post_title = $wpdb->escape(trim($post_title[1])); 59 if ( empty($post_title) ) { 60 preg_match('|<itemid>(.*?)</itemid>|is', $post, $post_title); 61 $post_title = $wpdb->escape(trim($post_title[1])); 62 $post_content = preg_replace('|<lj\s+user\s*=\s*["\']([\w-]+)["\']>|', '<a href="http://$1.livejournal.com/">$1</a>', $post_content); 63 } 64 65 preg_match('|<eventtime>(.*?)</eventtime>|is', $post, $post_date); 66 $post_date = strtotime($post_date[1]); 67 $post_date = date('Y-m-d H:i:s', $post_date); 68 69 preg_match('|<event>(.*?)</event>|is', $post, $post_content); 70 $post_content = str_replace(array ('<![CDATA[', ']]>'), '', trim($post_content[1])); 71 $post_content = $this->unhtmlentities($post_content); 72 73 // Clean up content 74 $post_content = preg_replace_callback('|<(/?[A-Z]+)|', create_function('$match', 'return "<" . strtolower($match[1]);'), $post_content); 75 $post_content = str_replace('<br>', '<br />', $post_content); 76 $post_content = str_replace('<hr>', '<hr />', $post_content); 77 $post_content = $wpdb->escape($post_content); 78 79 $post_author = $current_user->ID; 80 $post_status = 'publish'; 81 280 281 $imported_count = (int) get_option( 'ljapi_imported_count' ); 282 $lastsync = get_option( 'ljapi_lastsync_posts' ); 283 if ( !$lastsync ) 284 update_option( 'ljapi_lastsync_posts', date( 'Y-m-d H:i:s', 0 ) ); 285 286 do { 287 $lastsync = date( 'Y-m-d H:i:s', strtotime( get_option( 'ljapi_lastsync_posts' ) ) ); 288 289 // Get the batch of items that match up with the syncitems list 290 $itemlist = $this->lj_ixr( 'getevents', array( 'ver' => 1, 291 'selecttype' => 'syncitems', 292 'lineendings' => 'pc', 293 'lastsync' => $lastsync ) ); 294 $this->log( $itemlist, 'ljimport-posts-' . $imported_count . '.txt' ); 295 if ( is_wp_error( $itemlist ) ) 296 return $itemlist; 297 if ( $num = count( $itemlist['events'] ) ) { 298 foreach ( $itemlist['events'] as $event ) { 299 $imported_count++; 300 $this->import_post( $event ); 301 if ( $sync_item_times[ $event['itemid'] ] > $lastsync ) 302 $lastsync = $sync_item_times[ $event['itemid'] ]; 303 } 304 update_option( 'ljapi_lastsync_posts', $lastsync ); 305 update_option( 'ljapi_imported_count', $imported_count ); 306 update_option( 'ljapi_last_sync_count', $num ); 307 } 308 } while ( $num > 0 ); 309 310 echo '</ol>'; 311 } 312 313 function import_post( $post ) { 314 global $wpdb; 315 316 // Make sure we haven't already imported this one 317 if ( $this->get_wp_post_ID( $post['itemid'] ) ) 318 return; 319 320 $user = wp_get_current_user(); 321 $post_author = $user->ID; 322 $post_status = ( 'private' == trim( $post['security'] ) ) ? 'private' : 'publish'; // Only me 323 $post_password = ( 'usemask' == trim( $post['security'] ) ) ? $this->protected_password : ''; // "Friends" via password 324 325 // For some reason, LJ sometimes sends a date as "2004-04-1408:38:00" (no space btwn date/time) 326 $post_date = $post['eventtime']; 327 if ( 18 == strlen( $post_date ) ) 328 $post_date = substr( $post_date, 0, 10 ) . ' ' . substr( $post_date, 10 ); 329 330 // Cleaning up and linking the title 331 $post_title = trim( $post['subject'] ); 332 $post_title = $this->translate_lj_user( $post_title ); // Translate it, but then we'll strip the link 333 $post_title = strip_tags( $post_title ); // Can't have tags in the title in WP 334 $post_title = $wpdb->escape( $post_title ); 335 336 // Clean up content 337 $post_content = $post['event']; 338 $post_content = preg_replace_callback( '|<(/?[A-Z]+)|', create_function( '$match', 'return "<" . strtolower( $match[1] );' ), $post_content ); 339 // XHTMLize some tags 340 $post_content = str_replace( '<br>', '<br />', $post_content ); 341 $post_content = str_replace( '<hr>', '<hr />', $post_content ); 342 // lj-cut ==> <!--more--> 343 $post_content = preg_replace( '|<lj-cut text="([^"]*)">|is', '<!--more $1-->', $post_content ); 344 $post_content = str_replace( array( '<lj-cut>', '</lj-cut>' ), array( '<!--more-->', '' ), $post_content ); 345 $first = strpos( $post_content, '<!--more' ); 346 $post_content = substr( $post_content, 0, $first + 1 ) . preg_replace( '|<!--more(.*)?-->|sUi', '', substr( $post_content, $first + 1 ) ); 347 // lj-user ==> a href 348 $post_content = $this->translate_lj_user( $post_content ); 349 $post_content = force_balance_tags( $post_content ); 350 $post_content = $wpdb->escape( $post_content ); 351 352 // Handle any tags associated with the post 353 $tags_input = !empty( $post['props']['taglist'] ) ? $post['props']['taglist'] : ''; 354 355 // Check if comments are closed on this post 356 $comment_status = !empty( $post['props']['opt_nocomments'] ) ? 'closed' : 'open'; 357 358 echo '<li>'; 359 if ( $post_id = post_exists( $post_title, $post_content, $post_date ) ) { 360 printf( __( 'Post <strong>%s</strong> already exists.' ), stripslashes( $post_title ) ); 361 } else { 362 printf( __( 'Importing post <strong>%s</strong>...' ), stripslashes( $post_title ) ); 363 $postdata = compact( 'post_author', 'post_date', 'post_content', 'post_title', 'post_status', 'post_password', 'tags_input', 'comment_status' ); 364 $post_id = wp_insert_post( $postdata ); 365 if ( is_wp_error( $post_id ) ) 366 return $post_id; 367 if ( !$post_id ) { 368 _e( "Couldn't get post ID" ); 369 echo '</li>'; 370 break; 371 } 372 $postdata['post_ID'] = $post_id; 373 $postdata['lj_itemid'] = $post['itemid']; 374 $this->log( $postdata, 'ljimport-post-' . $post_id . '.txt' ); 375 376 // Handle all the metadata for this post 377 $this->insert_postmeta( $post_id, $post ); 378 } 379 echo '</li>'; 380 } 381 382 // Convert lj-user tags to links to that user 383 function translate_lj_user( $str ) { 384 return preg_replace( '|<lj\s+user\s*=\s*["\']([\w-]+)["\']>|', '<a href="http://$1.livejournal.com/" class="lj-user">$1</a>', $str ); 385 } 386 387 function insert_postmeta( $post_id, $post ) { 388 // Need the original LJ id for comments 389 add_post_meta( $post_id, 'lj_itemid', $post['itemid'] ); 390 391 // And save the permalink on LJ in case we want to link back or something 392 add_post_meta( $post_id, 'lj_permalink', $post['url'] ); 393 394 // Supports the following "props" from LJ, saved as lj_<prop_name> in wp_postmeta 395 // Adult Content - adult_content 396 // Location - current_coords + current_location 397 // Mood - current_mood (translated from current_moodid) 398 // Music - current_music 399 // Userpic - picture_keyword 400 foreach ( array( 'adult_content', 'current_coords', 'current_location', 'current_moodid', 'current_music', 'picture_keyword' ) as $prop ) { 401 if ( !empty( $post['props'][$prop] ) ) { 402 if ( 'current_moodid' == $prop ) { 403 $prop = 'current_mood'; 404 $val = $this->moods[ $post['props']['current_moodid'] ]; 405 } else { 406 $val = $post['props'][$prop]; 407 } 408 add_post_meta( $post_id, 'lj_' . $prop, $val ); 409 } 410 } 411 } 412 413 // Loops through and gets comment meta and content from LJ in batches 414 // Writes raw XML files to disk for later processing 415 function download_comments() { 416 // Get a session via XMLRPC 417 $cookie = $this->lj_ixr( 'sessiongenerate', array( 'ver' => 1, 'expiration' => 'short' ) ); 418 419 // Comment Meta 420 421 // Load previous state (if any) 422 $this->usermap = (array) get_option( 'ljapi_usermap' ); 423 $maxid = (int) get_option( 'ljapi_maxid' ) || 1; 424 $highest_id = (int) get_option( 'ljapi_highest_id' ); 425 426 // Snoopy is required to handle the cookie 427 $this->snoop = new Snoopy(); 428 $this->snoop->cookies = $cookie; 429 430 // We need to loop over the metadata request until we have it all 431 while ( $maxid > $highest_id ) { 432 // Now get the meta listing 433 if ( !$this->snoop->fetch( $this->comments_url . '?get=comment_meta&startid=' . ( $highest_id + 1 ) ) ) 434 return new WP_Error( 'Snoopy', __( 'Failed to retrieve comment meta information from LiveJournal. Please try again soon.' ) ); 435 436 // Snoopy doesn't provide an accessor for results... 437 $results = $this->snoop->results; 438 439 // Get the maxid so we know if we have them all yet 440 preg_match( '|<maxid>(\d+)</maxid>|', $results, $matches ); 441 $maxid = !empty( $matches[1] ) ? $matches[1] : $maxid; 442 443 // Parse comments and get highest id available 444 preg_match_all( '|<comment id=\'(\d+)\'|is', $results, $matches ); 445 foreach ( $matches[1] as $id ) { 446 if ( $id > $highest_id ) 447 $highest_id = $id; 448 } 449 450 // Parse out the list of user mappings, and add it to the known list 451 preg_match_all( '|<usermap id=\'(\d+)\' user=\'([^\']+)\' />|', $results, $matches ); 452 foreach ( $matches[1] as $count => $userid ) 453 $this->usermap[$userid] = $matches[2][$count]; // need this in memory for translating ids => names 454 455 update_option( 'ljapi_usermap', $this->usermap ); 456 update_option( 'ljapi_maxid', $maxid ); 457 update_option( 'ljapi_highest_id', $highest_id ); 458 } 459 // endwhile - should have seen all comment meta at this point 460 461 462 // Download Comment XML 463 464 // Load previous state (if any) 465 $highest_id = (int) get_option( 'ljapi_highest_comment_id' ); 466 $comment_xml_files = get_option( 'ljapi_comment_xml_files' ); 467 if ( !is_array( $comment_xml_files ) ) { 468 update_option( 'ljapi_comment_xml_files', array() ); 469 $comment_xml_files = array(); 470 } 471 472 echo '<ol>'; 473 474 // And now request the actual comments, and keep going until we have them all 475 while ( $maxid > $highest_id ) { 476 // Get a batch of comments, using the highest_id we've already got as a starting point 477 if ( !$this->snoop->fetch( $this->comments_url . '?get=comment_body&startid=' . ( $highest_id + 1 ) ) ) 478 return new WP_Error( 'Snoopy', __( 'Failed to retrieve comment bodies from LiveJournal. Please try again soon.' ) ); 479 480 // Get the highest post ID in this batch (required for loop control) 481 $results = $this->snoop->results; 482 preg_match_all( '|<comment id=\'(\d+)\'|i', $results, $comments ); 483 for ( $r = 0; $r < count( $comments[1] ); $r++ ) { 484 if ( $comments[1][$r] > $highest_id ) 485 $highest_id = $comments[1][$r]; 486 } 487 488 // $this->snoop-results is where the actual response is stored 489 $this->log( $this->snoop->results, 'ljimport-comment-bodies-' . $highest_id . '.txt' ); 490 491 // Store in uploads dir. Can't use *.xml because it's not allowed 492 $results = wp_upload_bits( 'raw-comments-' . $highest_id . '.txt', null, $results ); 493 if ( !empty( $results['error'] ) ) 494 return new WP_Error( 'xml', $results['error'] ); 495 $comment_xml_files[] = $results['file']; 496 497 echo '<li>' . sprintf( __( 'Downloaded <strong>%s</strong>' ), basename( $results['file'] ) ) . '</li>'; 498 ob_flush(); flush(); 499 500 $comment_xml_files = array_unique( $comment_xml_files ); 501 update_option( 'ljapi_comment_xml_files', $comment_xml_files ); 502 update_option( 'ljapi_comment_xml_files_count', count( $comment_xml_files ) ); 503 } 504 // endwhile - all comments downloaded and ready for bulk processing 505 506 echo '</ol>'; 507 508 return true; 509 } 510 511 function parse_comment_xml( $xml_file ) { 512 if ( !is_file( $xml_file ) || !is_readable( $xml_file ) ) 513 return new WP_Error( 'file', sprintf( __( 'Could not access comment XML file: %s'), $filename ) ); 514 515 // Get content from file 516 $xml = @file_get_contents( $xml_file ); 517 518 $cache_files = get_option( 'ljapi_comment_cache_files' ); 519 if ( !is_array( $cache_files ) ) 520 $cache_files = array(); 521 522 // Parse XML into comments 523 preg_match_all( '|<comment id.*</comment>|iUs', $xml, $matches ); 524 unset( $xml ); 525 for ( $c = 0; $c < count( $matches[0] ); $c++ ) { 526 $comment = $matches[0][$c]; 527 528 // Filter out any captured, deleted comments (nothing useful to import) 529 $comment = preg_replace( '|<comment id=\'\d+\' jitemid=\'\d+\' posterid=\'\d+\' state=\'D\'[^/]*/>|is', '', $comment ); 530 531 // Parse this comment into an array 532 $comment = $this->parse_comment( $comment ); 533 if ( empty( $comment['comment_post_ID'] ) ) 534 continue; 535 536 // Add this comment to the appropriate cache file 537 $filename = $this->full_path( 'ljimport-comments-' . $comment['comment_post_ID'] . '.php' ); 538 if ( $this->write_file( '<?php $comments[] = ' . var_export( $comment, true ) . '; ?>' . "\n", 539 $filename, 540 $comment['comment_post_ID'], 541 'a' ) ) 542 { 543 // Keep track of files used 544 $cache_files[] = $filename; 545 } 546 } 547 548 // Update list of files in the DB 549 sort( $cache_files ); 550 $cache_files = array_unique( $cache_files ); 551 update_option( 'ljapi_comment_cache_files', $cache_files ); 552 update_option( 'ljapi_comment_cache_files_count', count( $cache_files ) ); 553 $this->close_file_pointers(); 554 555 // Don't need this XML file anymore 556 unlink( $xml_file ); 557 558 return true; 559 } 560 561 function parse_comment( $comment ) { 562 global $wpdb; 563 564 // Get the top-level attributes 565 preg_match( '|<comment([^>]+)>|i', $comment, $attribs ); 566 preg_match( '| id=\'(\d+)\'|i', $attribs[1], $matches ); 567 $lj_comment_ID = $matches[1]; 568 preg_match( '| jitemid=\'(\d+)\'|i', $attribs[1], $matches ); 569 $lj_comment_post_ID = $matches[1]; 570 preg_match( '| posterid=\'(\d+)\'|i', $attribs[1], $matches ); 571 $comment_author_ID = $matches[1]; 572 preg_match( '| parentid=\'(\d+)\'|i', $attribs[1], $matches ); 573 $lj_comment_parent = $matches[1]; 574 preg_match( '| state=\'([SDFA])\'|i', $attribs[1], $matches ); 575 $lj_comment_state = !empty( $matches[1] ) ? $matches[1] : 'A'; 576 577 // Clean up "subject" - this will become the first line of the comment in WP 578 preg_match( '|<subject>(.*)</subject>|is', $comment, $matches ); 579 $comment_subject = $wpdb->escape( trim( $matches[1] ) ); 580 if ( 'Re:' == $comment_subject ) 581 $comment_subject = ''; 582 583 // Get the body and HTMLize it 584 preg_match( '|<body>(.*)</body>|is', $comment, $matches ); 585 $comment_content = !empty( $comment_subject ) ? $comment_subject . "\n\n" . $matches[1] : $matches[1]; 586 $comment_content = $this->unhtmlentities( $comment_content ); 587 $comment_content = wpautop( $comment_content ); 588 $comment_content = str_replace( '<br>', '<br />', $comment_content ); 589 $comment_content = str_replace( '<hr>', '<hr />', $comment_content ); 590 $comment_content = preg_replace_callback( '|<(/?[A-Z]+)|', create_function( '$match', 'return "<" . strtolower( $match[1] );' ), $comment_content ); 591 $comment_content = $wpdb->escape( trim( $comment_content ) ); 592 593 // Get and convert the date 594 preg_match( '|<date>(.*)</date>|i', $comment, $matches ); 595 $comment_date = trim( str_replace( array( 'T', 'Z' ), ' ', $matches[1] ) ); 596 597 // Grab IP if available 598 preg_match( '|<property name=\'poster_ip\'>(.*)</property>|i', $comment, $matches ); 599 $comment_author_IP = $matches[1]; 600 601 // Try to get something useful for the comment author, especially if it was "my" comment 602 $author = ( substr( $this->usermap[$comment_author_ID], 0, 4 ) == 'ext_' || empty( $comment_author_ID ) ) ? __( 'Anonymous' ) : $this->usermap[$comment_author_ID]; 603 if ( get_option( 'ljapi_username' ) == $author ) { 604 $user = wp_get_current_user(); 605 $user_id = $user->ID; 606 $author = $user->display_name; 607 $url = trailingslashit( get_option( 'home' ) ); 608 } else { 609 $user_id = 0; 610 $url = ( __( 'Anonymous' ) == $author ) ? '' : 'http://' . $author . '.livejournal.com/'; 611 } 612 613 // Send back the array of details 614 return array( 'lj_comment_ID' => $lj_comment_ID, 615 'lj_comment_post_ID' => $lj_comment_post_ID, 616 'lj_comment_parent' => ( !empty( $lj_comment_parent ) ? $lj_comment_parent : 0 ), 617 'lj_comment_state' => $lj_comment_state, 618 'comment_post_ID' => $this->get_wp_post_ID( $lj_comment_post_ID ), 619 'comment_author' => $author, 620 'comment_author_url' => $url, 621 'comment_content' => $comment_content, 622 'comment_date' => $comment_date, 623 'comment_author_IP' => ( !empty( $comment_author_IP ) ? $comment_author_IP : '' ), 624 'comment_approved' => ( in_array( $lj_comment_state, array( 'A', 'F' ) ) ? 1 : 0 ), 625 'comment_agent' => 'WP LJ Importer', 626 'user_id' => $user_id 627 ); 628 } 629 630 631 // Gets the post_ID that a LJ post has been saved as within WP 632 function get_wp_post_ID( $post ) { 633 global $wpdb; 634 if ( empty( $this->postmap[$post] ) ) 635 $this->postmap[$post] = $wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = 'lj_itemid' AND meta_value = %d", $post ) ); 636 return $this->postmap[$post]; 637 } 638 639 // Re-build the threading within a single cache file 640 function thread_comments( $filename ) { 641 if ( !is_file( $filename ) || !is_readable( $filename ) ) 642 return new WP_Error( 'File', __( sprintf( 'Cannot access file %s', $filename ) ) ); 643 644 $comments = array(); 645 @include( $filename ); 646 $this->comments = $comments; 647 unset( $comments ); 648 if ( !is_array( $this->comments ) ) 649 $this->comments = array(); 650 651 $count = count( $this->comments ); 652 for ( $c = 0; $c < $count; $c++ ) { 653 // Skip anything that's not "top-level" for now 654 if ( 0 != $this->comments[$c]['lj_comment_parent'] ) 655 continue; 656 $this->comments[$c]['children'] = $this->get_child_comments( $this->comments[$c]['lj_comment_ID'] ); 657 } 658 659 // Remove anything that's not supposed to be at top level 660 $top_comments = array(); 661 for ( $c = 0; $c < $count; $c++ ) { 662 if ( 0 == $this->comments[$c]['lj_comment_parent'] ) { 663 $top_comments[] = $this->comments[$c]; 664 } 665 } 666 667 // Write back to file 668 @unlink( $filename ); 669 $this->write_file( '<?php $comments = ' . var_export( $top_comments, true ) . '; ?>', $filename, $count, 'w' ); 670 unset( $top_comments ); 671 $this->close_file_pointers(); 672 673 // Reference this file as being threaded 674 $files = get_option( 'ljapi_comment_threaded_files' ); 675 $files[] = $filename; 676 array_unique( $files ); 677 update_option( 'ljapi_comment_threaded_files', $files ); 678 update_option( 'ljapi_comment_threaded_files_count', count( $files ) ); 679 680 return true; 681 } 682 683 function get_child_comments( $id ) { 684 $children = array(); 685 $count = count( $this->comments ); 686 for ( $c = 0; $c < $count; $c++ ) { 687 // This comment is a child of the $id 688 if ( $id == $this->comments[$c]['lj_comment_parent'] ) { 689 $this->comments[$c]['children'] = $this->get_child_comments( $this->comments[$c]['lj_comment_ID'] ); 690 $children[] = $this->comments[$c]; 691 } 692 } 693 return $children; 694 } 695 696 // Inserts the contents of each cache file (should be threaded already) 697 function insert_comments( $filename ) { 698 echo '<ol>'; 699 700 if ( !is_file( $filename ) || !is_readable( $filename ) ) 701 return new WP_Error( 'File', __( sprintf( 'Cannot access file %s', $filename ) ) ); 702 703 $comments = array(); 704 @include( $filename ); 705 $this->comments = $comments; 706 unset( $comments ); 707 if ( !is_array( $this->comments ) ) 708 $this->comments = array(); 709 710 $count = count( $this->comments ); 711 for ( $c = 0; $c < $count; $c++ ) { 712 $comment =& $this->comments[$c]; 82 713 echo '<li>'; 83 if ($post_id = post_exists($post_title, $post_content, $post_date)) { 84 printf(__('Post <em>%s</em> already exists.'), stripslashes($post_title)); 85 } else { 86 printf(__('Importing post <em>%s</em>...'), stripslashes($post_title)); 87 $postdata = compact('post_author', 'post_date', 'post_content', 'post_title', 'post_status'); 88 $post_id = wp_insert_post($postdata); 89 if ( is_wp_error( $post_id ) ) 90 return $post_id; 91 if (!$post_id) { 92 _e("Couldn't get post ID"); 93 echo '</li>'; 94 break; 95 } 96 } 97 98 preg_match_all('|<comment>(.*?)</comment>|is', $post, $comments); 99 $comments = $comments[1]; 100 101 if ( $comments ) { 102 $comment_post_ID = (int) $post_id; 103 $num_comments = 0; 104 foreach ($comments as $comment) { 105 preg_match('|<event>(.*?)</event>|is', $comment, $comment_content); 106 $comment_content = str_replace(array ('<![CDATA[', ']]>'), '', trim($comment_content[1])); 107 $comment_content = $this->unhtmlentities($comment_content); 108 109 // Clean up content 110 $comment_content = preg_replace_callback('|<(/?[A-Z]+)|', create_function('$match', 'return "<" . strtolower($match[1]);'), $comment_content); 111 $comment_content = str_replace('<br>', '<br />', $comment_content); 112 $comment_content = str_replace('<hr>', '<hr />', $comment_content); 113 $comment_content = $wpdb->escape($comment_content); 114 115 preg_match('|<eventtime>(.*?)</eventtime>|is', $comment, $comment_date); 116 $comment_date = trim($comment_date[1]); 117 $comment_date = date('Y-m-d H:i:s', strtotime($comment_date)); 118 119 preg_match('|<name>(.*?)</name>|is', $comment, $comment_author); 120 $comment_author = $wpdb->escape(trim($comment_author[1])); 121 122 preg_match('|<email>(.*?)</email>|is', $comment, $comment_author_email); 123 $comment_author_email = $wpdb->escape(trim($comment_author_email[1])); 124 125 $comment_approved = 1; 126 // Check if it's already there 127 if (!comment_exists($comment_author, $comment_date)) { 128 $commentdata = compact('comment_post_ID', 'comment_author', 'comment_author_email', 'comment_date', 'comment_content', 'comment_approved'); 129 $commentdata = wp_filter_comment($commentdata); 130 wp_insert_comment($commentdata); 131 $num_comments++; 132 } 133 } 134 } 135 if ( $num_comments ) { 136 echo ' '; 137 printf(__ngettext('(%s comment)', '(%s comments)', $num_comments), $num_comments); 138 } 714 printf( __( 'Imported comment from <strong>%s</strong> on %s' ), $comment['comment_author'], $comment['comment_date'] ); 715 716 $id = wp_insert_comment( $comment ); 717 $comment['comment_ID'] = $id; 718 if ( count( $comment['children'] ) ) { 719 _e( ' and replies:' ); 720 $this->insert_child_comments( $comment['children'], $id ); 721 } 722 139 723 echo '</li>'; 140 724 } 725 726 // Remove the file now that we're done with it 727 @unlink( $filename ); 728 141 729 echo '</ol>'; 142 } 143 144 function import() { 145 $file = wp_import_handle_upload(); 146 if ( isset($file['error']) ) { 147 echo $file['error']; 148 return; 149 } 150 151 $this->file = $file['file']; 152 $result = $this->import_posts(); 153 if ( is_wp_error( $result ) ) 154 return $result; 155 wp_import_cleanup($file['id']); 156 do_action('import_done', 'livejournal'); 157 158 echo '<h3>'; 159 printf(__('All done. <a href="%s">Have fun!</a>'), get_option('home')); 160 echo '</h3>'; 161 } 162 730 731 return true; 732 } 733 734 function insert_child_comments( &$comments, $parent ) { 735 echo '<ol>'; 736 $count = count( $comments ); 737 for ( $c = 0; $c < $count; $c++ ) { 738 $comment =& $comments[$c]; 739 $comment['comment_parent'] = $parent; 740 echo '<li>'; 741 printf( __( 'Imported reply from <strong>%s</strong> on %s' ), $comment['comment_author'], $comment['comment_date'] ); 742 743 $id = wp_insert_comment( $comment ); 744 $comment['comment_ID'] = $id; 745 if ( count( $comment['children'] ) ) { 746 _e( ' and replies:' ); 747 $this->insert_child_comments( $comment['children'], $id ); 748 } 749 750 echo '</li>'; 751 } 752 echo '</ol>'; 753 } 754 755 function lj_ixr() { 756 if ( $challenge = $this->ixr->query( 'LJ.XMLRPC.getchallenge' ) ) { 757 $challenge = $this->ixr->getResponse(); 758 } 759 if ( isset( $challenge['challenge'] ) ) { 760 $params = array( 'username' => $this->username, 761 'auth_method' => 'challenge', 762 'auth_challenge' => $challenge['challenge'], 763 'auth_response' => md5( $challenge['challenge'] . md5( $this->password ) ) ); 764 } else { 765 return new WP_Error( 'IXR', __( 'LiveJournal does not appear to be responding right now. Please try again later.' ) ); 766 } 767 768 $args = func_get_args(); 769 $method = array_shift( $args ); 770 if ( isset( $args[0] ) ) 771 $params = array_merge( $params, $args[0] ); 772 if ( $this->ixr->query( 'LJ.XMLRPC.' . $method, $params ) ) { 773 return $this->ixr->getResponse(); 774 } else { 775 $this->log( $this->ixr->message, 'ljimport-error-' . $method . '.txt' ); 776 return new WP_Error( 'IXR', __( 'XML-RPC Request Failed - ' ) . $this->ixr->getErrorCode() . ': ' . $this->ixr->getErrorMessage() ); 777 } 778 } 779 163 780 function dispatch() { 164 if ( empty ($_GET['step']))781 if ( empty( $_REQUEST['step'] ) ) 165 782 $step = 0; 166 783 else 167 $step = (int) $_ GET['step'];784 $step = (int) $_REQUEST['step']; 168 785 169 786 $this->header(); 170 171 switch ($step) { 787 788 switch ( $step ) { 789 case -1 : 790 $this->cleanup(); 791 // Intentional no break 172 792 case 0 : 173 793 $this->greet(); 174 794 break; 175 795 case 1 : 176 check_admin_referer('import-upload'); 177 $result = $this->import(); 796 case 2 : 797 $this->ixr = new IXR_Client( $this->ixr_url ); 798 // Intentional no break 799 case 3 : 800 case 4 : 801 case 5 : 802 check_admin_referer( 'lj-api-import' ); 803 $result = $this->{ 'step' . $step }(); 178 804 if ( is_wp_error( $result ) ) 179 805 echo $result->get_error_message(); … … 184 810 } 185 811 186 function LJ_Import() { 187 // Nothing. 812 // Check form inputs and start importing posts 813 function step1() { 814 // Get details from form or from DB 815 if ( !empty( $_POST['lj_username'] ) && !empty( $_POST['lj_password'] ) ) { 816 // Store details for later 817 $this->username = $_POST['lj_username']; 818 $this->password = $_POST['lj_password']; 819 update_option( 'ljapi_username', $this->username ); 820 update_option( 'ljapi_password', $this->password ); 821 } else { 822 $this->username = get_option( 'ljapi_username' ); 823 $this->password = get_option( 'ljapi_password' ); 824 } 825 826 // This is the password to set on protected posts 827 if ( !empty( $_POST['protected_password'] ) ) { 828 $this->protected_password = $_POST['protected_password']; 829 update_option( 'ljapi_protected_password', $this->protected_password ); 830 } else { 831 $this->protected_password = get_option( 'ljapi_protected_password' ); 832 } 833 834 // Login to confirm the details are correct 835 if ( empty( $this->username ) || empty( $this->password ) ) { 836 ?> 837 <p><?php _e( 'Please enter your LiveJournal username <em>and</em> password so we can download your posts and comments.' ) ?></p> 838 <p><a href="<?php echo $_SERVER['PHP_SELF'] . '?import=livejournal&step=-1&_wpnonce=' . wp_create_nonce( 'lj-api-import' ) . '&_wp_http_referer=' . attribute_escape( str_replace( '&step=1', '', $_SERVER['REQUEST_URI'] ) ) ?>"><?php _e( 'Start again' ) ?></a></p> 839 <?php 840 return; 841 } 842 $login = $this->lj_ixr( 'login' ); 843 if ( is_wp_error( $login ) ) { 844 if ( 100 == $this->ixr->getErrorCode() || 101 == $this->ixr->getErrorCode() ) { 845 ?> 846 <p><?php _e( 'Logging in to LiveJournal failed. Check your username and password and try again.' ) ?></p> 847 <p><a href="<?php echo $_SERVER['PHP_SELF'] . '?import=livejournal&step=-1&_wpnonce=' . wp_create_nonce( 'lj-api-import' ) . '&_wp_http_referer=' . attribute_escape( str_replace( '&step=1', '', $_SERVER['REQUEST_URI'] ) ) ?>"><?php _e( 'Start again' ) ?></a></p> 848 <?php 849 return; 850 } else { 851 return $login; 852 } 853 } 854 855 // Set up some options to avoid them autoloading (these ones get big) 856 add_option( 'ljapi_sync_item_times', '', '', 'no' ); 857 add_option( 'ljapi_usermap', '', '', 'no' ); 858 add_option( 'ljapi_comment_xml_files', '', '', 'no' ); 859 add_option( 'ljapi_comment_cache_files', '', '', 'no' ); 860 add_option( 'ljapi_comment_threaded_files', '', '', 'no' ); 861 862 echo '<h3>' . __( 'Importing Posts' ) . '</h3>'; 863 echo '<p>' . __( "We're downloading and importing all your LiveJournal posts..." ) . '</p>'; 864 ob_flush(); flush(); 865 866 // Now do the grunt work 867 set_time_limit( 0 ); 868 $result = $this->import_posts(); 869 if ( is_wp_error( $result ) ) { 870 if ( 406 == $this->ixr->getErrorCode() ) { 871 ?> 872 <p><strong><?php _e( 'Uh oh – LiveJournal has disconnected us because we made too many requests to their servers too quickly.' ) ?></strong></p> 873 <p><strong><?php _e( "We've saved where you were up to though, so if you come back to this importer in about 30 minutes, you should be able to continue from where you were." ) ?></strong></p> 874 <?php 875 return; 876 } else { 877 return $result; 878 } 879 } 880 881 echo '<p>' . __( "Your posts have all been imported, but wait - there's more! Now we need to process & import your comments." ) . '</p>'; 882 echo $this->next_step( 2, __( 'Download my comments »' ) ); 883 $this->auto_submit(); 884 } 885 886 // Download comments to local XML 887 function step2() { 888 set_time_limit( 0 ); 889 update_option( 'ljapi_step', 2 ); 890 $this->username = get_option( 'ljapi_username' ); 891 $this->password = get_option( 'ljapi_password' ); 892 893 echo '<h3>' . __( 'Downloading Comments' ) . '</h3>'; 894 echo '<p>' . __( 'Now we will download your comments so we can process and import them...' ) . '</p>'; 895 ob_flush(); flush(); 896 897 $result = $this->download_comments(); 898 if ( is_wp_error( $result ) ) 899 return $result; 900 901 echo '<p>' . __( 'Your comments have all been downloaded to this server now, so we can process them and get them ready for importing.' ) . '</p>'; 902 echo $this->next_step( 3, __( 'Process my comment files »' ) ); 903 $this->auto_submit(); 904 } 905 906 // Parse XML into comment cache files 907 function step3() { 908 909 set_time_limit( 0 ); 910 update_option( 'ljapi_step', 3 ); 911 912 $this->usermap = get_option( 'ljapi_usermap' ); 913 914 echo '<div id="ljapi-status">'; 915 echo '<h3>' . __( 'Parsing Comments' ) . '</h3>'; 916 echo '<p>' . __( 'Time to clean up your comments and get them into a format WordPress understands...' ) . '</p>'; 917 ob_flush(); flush(); 918 919 $files = get_option( 'ljapi_comment_xml_files' ); 920 if ( count( $files ) ) { 921 $file = array_pop( $files ); 922 923 $result = $this->parse_comment_xml( $file ); 924 if ( is_wp_error( $result ) ) 925 return $result; 926 927 update_option( 'ljapi_comment_xml_files', $files ); 928 } 929 930 if ( count( $files ) ) { 931 ?> 932 <form action="admin.php?import=livejournal" method="post" id="ljapi-auto-repost"> 933 <p><strong><?php printf( __( 'Processed comment file %d of %d' ), ( get_option( 'ljapi_comment_xml_files_count' ) - count( $files ) ), get_option( 'ljapi_comment_xml_files_count' ) ) ?></strong></p> 934 <?php wp_nonce_field( 'lj-api-import' ) ?> 935 <input type="hidden" name="step" id="step" value="3" /> 936 <p><input type="submit" class="button-primary" value="<?php echo attribute_escape( __( 'Process the next comment file »' ) ) ?>" /> <span id="auto-message"></span></p> 937 </form> 938 <?php $this->auto_ajax( 'ljapi-auto-repost', 'auto-message', 0 ); ?> 939 <?php 940 } else { 941 echo '<p>' . __( 'Yay, we finished processing all of your comment files! Now we need to re-build your conversation threads.' ) . '</p>'; 942 echo $this->next_step( 4, __( 'Thread my comments »' ) ); 943 $this->auto_submit(); 944 } 945 echo '</div>'; 946 } 947 948 // Thread comments within their cache files 949 function step4() { 950 set_time_limit( 0 ); 951 update_option( 'ljapi_step', 4 ); 952 953 echo '<div id="ljapi-status">'; 954 echo '<h3>' . __( 'Threading Comments' ) . '</h3>'; 955 echo '<p>' . __( 'Re-building your conversation threads ready for import...' ) . '</p>'; 956 ob_flush(); flush(); 957 958 $files = get_option( 'ljapi_comment_cache_files' ); 959 if ( count( $files ) ) { 960 $file = array_pop( $files ); 961 962 $result = $this->thread_comments( $file ); 963 if ( is_wp_error( $result ) ) 964 return $result; 965 966 update_option( 'ljapi_comment_cache_files', $files ); 967 } 968 969 if ( count( $files ) ) { 970 ?> 971 <form action="admin.php?import=livejournal" method="post" id="ljapi-auto-repost"> 972 <p><strong><?php printf( __( 'Threaded cache file %d of %d' ), ( get_option( 'ljapi_comment_cache_files_count' ) - count( $files ) ), get_option( 'ljapi_comment_cache_files_count' ) ) ?></strong></p> 973 <?php wp_nonce_field( 'lj-api-import' ) ?> 974 <input type="hidden" name="step" id="step" value="4" /> 975 <p><input type="submit" class="button-primary" value="<?php echo attribute_escape( __( 'Thread the next cache file »' ) ) ?>" /> <span id="auto-message"></span></p> 976 </form> 977 <?php $this->auto_ajax( 'ljapi-auto-repost', 'auto-message', 0 ); ?> 978 <?php 979 } else { 980 echo '<p>' . __( "Alrighty, your comments are all threaded. There's just one last step -- time to actually import them all now!" ) . '</p>'; 981 echo '<p>' . __( 'This last part in particular can take a really long time if you have a lot of comments. You might want to go and do something else while you wait.' ) . '</p>'; 982 echo $this->next_step( 5, __( 'Import my threaded comments into WordPress »' ) ); 983 $this->auto_submit(); 984 } 985 echo '</div>'; 986 } 987 988 // Import comments from cache files into WP 989 function step5() { 990 set_time_limit( 0 ); 991 update_option( 'ljapi_step', 5 ); 992 993 994 echo '<div id="ljapi-status">'; 995 echo '<h3>' . __( 'Importing Comments' ) . '</h3>'; 996 echo '<p>' . __( 'This is the big one -- we are now inserting your comment threads into WordPress...' ) . '</p>'; 997 998 $files = get_option( 'ljapi_comment_threaded_files' ); 999 echo '<p><strong>' . sprintf( __( 'Importing cache file %d of %d' ), ( get_option( 'ljapi_comment_threaded_files_count' ) - count( $files ) + 1 ), get_option( 'ljapi_comment_threaded_files_count' ) ) . '</strong></p>'; 1000 ob_flush(); flush(); 1001 1002 if ( count( $files ) ) { 1003 $file = array_pop( $files ); 1004 1005 $result = $this->insert_comments( $file ); 1006 if ( is_wp_error( $result ) ) 1007 return $result; 1008 1009 update_option( 'ljapi_comment_threaded_files', $files ); 1010 } 1011 1012 if ( count( $files ) ) { 1013 ?> 1014 <form action="admin.php?import=livejournal" method="post" id="ljapi-auto-repost"> 1015 <?php wp_nonce_field( 'lj-api-import' ) ?> 1016 <input type="hidden" name="step" id="step" value="5" /> 1017 <p><input type="submit" class="button-primary" value="<?php echo attribute_escape( __( 'Import the next cache file »' ) ) ?>" /> <span id="auto-message"></span></p> 1018 </form> 1019 <?php $this->auto_ajax( 'ljapi-auto-repost', 'auto-message', 0 ); ?> 1020 <?php 1021 } else { 1022 // Clean up database and we're out 1023 $this->cleanup(); 1024 do_action( 'import_done', 'livejournal' ); 1025 echo '<h3>'; 1026 printf( __( 'All done. <a href="%s">Have fun!</a>' ), get_option( 'home' ) ); 1027 echo '</h3>'; 1028 } 1029 echo '</div>'; 1030 } 1031 1032 // Returns the HTML for a link to the next page 1033 function next_step( $next_step, $label, $id = 'ljapi-next-form' ) { 1034 $str = '<form action="admin.php?import=livejournal" method="post" id="' . $id . '">'; 1035 $str .= wp_nonce_field( 'lj-api-import', '_wpnonce', true, false ); 1036 $str .= wp_referer_field( false ); 1037 $str .= '<input type="hidden" name="step" id="step" value="' . $next_step . '" />'; 1038 $str .= '<p><input type="submit" class="button-primary" value="' . attribute_escape( $label ) . '" /> <span id="auto-message"></span></p>'; 1039 $str .= '</form>'; 1040 1041 return $str; 1042 } 1043 1044 // Automatically submit the form with #id to continue the process 1045 // Hide any submit buttons to avoid people clicking them 1046 // Display a countdown in the element indicated by $msg for "Continuing in x" 1047 function auto_ajax( $id = 'ljapi-next-form', $msg = 'auto-message', $seconds = 5 ) { 1048 ?><script type="text/javascript"> 1049 next_counter = <?php echo $seconds ?>; 1050 jQuery(document).ready(function(){ 1051 ljapi_msg(); 1052 }); 1053 1054 function ljapi_msg() { 1055 str = '<?php _e( "Continuing in %d" ) ?>'; 1056 jQuery( '#<?php echo $msg ?>' ).text( str.replace( /%d/, next_counter ) ); 1057 if ( next_counter <= 0 ) { 1058 if ( jQuery( '#<?php echo $id ?>' ).length ) { 1059 jQuery( "#<?php echo $id ?> input[type='submit']" ).hide(); 1060 jQuery.ajaxSetup({'timeout':3600000}); 1061 str = '<?php _e( "Processing next file." ) ?> <img src="images/loading-publish.gif" alt="" id="processing" align="top" />'; 1062 jQuery( '#<?php echo $msg ?>' ).html( str ); 1063 jQuery('#ljapi-status').load(ajaxurl, {'action':'lj-importer', 1064 'step':jQuery('#step').val(), 1065 '_wpnonce':'<?php echo wp_create_nonce( 'lj-api-import' ) ?>', 1066 '_wp_http_referer':'<?php echo $_SERVER['REQUEST_URI'] ?>'}); 1067 return; 1068 } 1069 } 1070 next_counter = next_counter - 1; 1071 setTimeout('ljapi_msg()', 1000); 1072 } 1073 </script><?php 1074 } 1075 1076 // Automatically submit the specified form after $seconds 1077 // Include a friendly countdown in the element with id=$msg 1078 function auto_submit( $id = 'ljapi-next-form', $msg = 'auto-message', $seconds = 10 ) { 1079 ?><script type="text/javascript"> 1080 next_counter = <?php echo $seconds ?>; 1081 jQuery(document).ready(function(){ 1082 ljapi_msg(); 1083 }); 1084 1085 function ljapi_msg() { 1086 str = '<?php _e( "Continuing in %d" ) ?>'; 1087 jQuery( '#<?php echo $msg ?>' ).text( str.replace( /%d/, next_counter ) ); 1088 if ( next_counter <= 0 ) { 1089 if ( jQuery( '#<?php echo $id ?>' ).length ) { 1090 jQuery( "#<?php echo $id ?> input[type='submit']" ).hide(); 1091 str = '<?php _e( "Continuing" ) ?> <img src="images/loading-publish.gif" alt="" id="processing" align="top" />'; 1092 jQuery( '#<?php echo $msg ?>' ).html( str ); 1093 jQuery( '#<?php echo $id ?>' ).submit(); 1094 return; 1095 } 1096 } 1097 next_counter = next_counter - 1; 1098 setTimeout('ljapi_msg()', 1000); 1099 } 1100 </script><?php 1101 } 1102 1103 // Remove all options used during import process 1104 function cleanup() { 1105 delete_option( 'ljapi_username' ); 1106 delete_option( 'ljapi_password' ); 1107 delete_option( 'ljapi_protected_password' ); 1108 delete_option( 'ljapi_total' ); 1109 delete_option( 'ljapi_count' ); 1110 delete_option( 'ljapi_lastsync' ); 1111 delete_option( 'ljapi_last_sync_count' ); 1112 delete_option( 'ljapi_sync_item_times' ); 1113 delete_option( 'ljapi_lastsync_posts' ); 1114 delete_option( 'ljapi_imported_count' ); 1115 delete_option( 'ljapi_maxid' ); 1116 delete_option( 'ljapi_usermap' ); 1117 delete_option( 'ljapi_highest_id' ); 1118 delete_option( 'ljapi_highest_comment_id' ); 1119 delete_option( 'ljapi_comment_xml_files' ); 1120 delete_option( 'ljapi_comment_xml_files_count' ); 1121 delete_option( 'ljapi_comment_cache_files' ); 1122 delete_option( 'ljapi_comment_cache_files_count' ); 1123 delete_option( 'ljapi_comment_threaded_files' ); 1124 delete_option( 'ljapi_comment_threaded_files_count' ); 1125 delete_option( 'ljapi_step' ); 1126 } 1127 1128 // Dump a string to a log file (appends to existing file) 1129 function log( $string, $name ) { 1130 return; // remove this to enable "debugging" output to files in /wp-content/ljimport 1131 $path = wp_upload_dir(); 1132 $path = $path['path']; 1133 if ( get_option( 'uploads_use_yearmonth_folders' ) ) 1134 $path = substr( $path, 0, -8 ); 1135 1136 if ( !is_dir( $path . '/ljimport' ) ) 1137 mkdir( $path . '/ljimport' ); 1138 1139 $fh = @fopen( $path . '/ljimport/' . $name, 'a' ); 1140 if ( $fh ) { 1141 if ( is_array( $string ) || is_object( $string ) ) 1142 fwrite( $fh, var_export( $string, true ) . "\n\n" ); 1143 else 1144 fwrite( $fh, $string . "\n\n" ); 1145 fclose( $fh ); 1146 } 1147 } 1148 1149 function write_file( $data, $name, $id, $mode = 'a' ) { 1150 if ( empty( $this->pointers[$id] ) ) 1151 $this->pointers[$id] = @fopen( $name, $mode ); 1152 if ( $this->pointers[$id] ) 1153 return fwrite( $this->pointers[$id], $data ); 1154 return false; 1155 } 1156 1157 function full_path( $basename ) { 1158 $uploads = wp_upload_dir(); 1159 return $uploads['path'] . '/' . $basename; 1160 } 1161 1162 function close_file_pointers() { 1163 foreach ( $this->pointers as $p ) 1164 @fclose( $p ); 1165 } 1166 1167 function LJ_API_Import() { 1168 $this->__construct(); 1169 } 1170 1171 function __construct() { 1172 // Nothing 188 1173 } 189 1174 } 190 1175 191 $l ivejournal_import = new LJ_Import();192 193 register_importer( 'livejournal', __('LiveJournal'), __('Import posts from a LiveJournal XML export file.'), array ($livejournal_import, 'dispatch'));1176 $lj_api_import = new LJ_API_Import(); 1177 1178 register_importer( 'livejournal', __( 'LiveJournal' ), __( 'Import posts from LiveJournal using their API.' ), array( $lj_api_import, 'dispatch' ) ); 194 1179 ?>
Note: See TracChangeset
for help on using the changeset viewer.