+ // Technically the first half of step 1, this is separated to allow for AJAX
+ // calls. Sets up some variables and options and confirms authentication.
+ function setup() {
+ global $verified;
+ // Get details from form or from DB
+ if ( !empty( $_POST['lj_username'] ) && !empty( $_POST['lj_password'] ) ) {
+ // Store details for later
+ $this->username = $_POST['lj_username'];
+ $this->password = $_POST['lj_password'];
+ update_option( 'ljapi_username', $this->username );
+ update_option( 'ljapi_password', $this->password );
+ } else {
+ $this->username = get_option( 'ljapi_username' );
+ $this->password = get_option( 'ljapi_password' );
+ }
+
+ // This is the password to set on protected posts
+ if ( !empty( $_POST['protected_password'] ) ) {
+ $this->protected_password = $_POST['protected_password'];
+ update_option( 'ljapi_protected_password', $this->protected_password );
+ } else {
+ $this->protected_password = get_option( 'ljapi_protected_password' );
+ }
+
+ // Log in to confirm the details are correct
+ if ( empty( $this->username ) || empty( $this->password ) ) {
+ ?>
+ <p><?php _e( 'Please enter your LiveJournal username <em>and</em> password so we can download your posts and comments.' ) ?></p>
+ <p><a href="<?php echo esc_url($_SERVER['PHP_SELF'] . '?import=livejournal&step=-1&_wpnonce=' . wp_create_nonce( 'lj-api-import' ) . '&_wp_http_referer=' . esc_attr( str_replace( '&step=1', '', $_SERVER['REQUEST_URI'] ) ) ) ?>"><?php _e( 'Start again' ) ?></a></p>
+ <?php
+ return false;
+ }
+ $verified = $this->lj_ixr( 'login' );
+ if ( is_wp_error( $verified ) ) {
+ if ( 100 == $this->ixr->getErrorCode() || 101 == $this->ixr->getErrorCode() ) {
+ delete_option( 'ljapi_username' );
+ delete_option( 'ljapi_password' );
+ delete_option( 'ljapi_protected_password' );
+ ?>
+ <p><?php _e( 'Logging in to LiveJournal failed. Check your username and password and try again.' ) ?></p>
+ <p><a href="<?php echo esc_url($_SERVER['PHP_SELF'] . '?import=livejournal&step=-1&_wpnonce=' . wp_create_nonce( 'lj-api-import' ) . '&_wp_http_referer=' . esc_attr( str_replace( '&step=1', '', $_SERVER['REQUEST_URI'] ) ) ) ?>"><?php _e( 'Start again' ) ?></a></p>
+ <?php
+ return false;
+ } else {
+ return $verified;
+ }
+ } else {
+ update_option( 'ljapi_verified', 'yes' );
+ }
+
+ // Set up some options to avoid them autoloading (these ones get big)
+ add_option( 'ljapi_sync_item_times', '', '', 'no' );
+ add_option( 'ljapi_usermap', '', '', 'no' );
+ update_option( 'ljapi_comment_batch', 0 );
+
+ return true;
+ }
+
+ // Check form inputs and start importing posts
+ function step1() {
+ global $verified;
+ set_time_limit( 0 );
+ update_option( 'ljapi_step', 1 );
+ if ( !$this->ixr ) $this->ixr = new IXR_Client( $this->ixr_url, false, 80, 30 );
+ if ( empty( $_POST['login'] ) ) {
+ // We're looping -- load some details from DB
+ $this->username = get_option( 'ljapi_username' );
+ $this->password = get_option( 'ljapi_password' );
+ $this->protected_password = get_option( 'ljapi_protected_password' );
+ } else {
+ // First run (non-AJAX)
+ $setup = $this->setup();
+ if ( !$setup ) {
+ return false;
+ } else if ( is_wp_error( $setup ) ) {
+ $this->throw_error( $setup, 1 );
+ return false;
+ }
+ }
+
+ echo '<div id="ljapi-status">';
+ echo '<h3>' . __( 'Importing Posts' ) . '</h3>';
+ echo '<p>' . __( 'We’re downloading and importing your LiveJournal posts...' ) . '</p>';
+ if ( get_option( 'ljapi_post_batch' ) && count( get_option( 'ljapi_sync_item_times' ) ) ) {
+ $batch = count( get_option( 'ljapi_sync_item_times' ) );
+ $batch = $count > 300 ? ceil( $batch / 300 ) : 1;
+ echo '<p><strong>' . sprintf( __( 'Imported post batch %d of <strong>approximately</strong> %d' ), ( get_option( 'ljapi_post_batch' ) + 1 ), $batch ) . '</strong></p>';
+ }
+ ob_flush(); flush();
+
+ if ( !get_option( 'ljapi_lastsync' ) || '1900-01-01 00:00:00' == get_option( 'ljapi_lastsync' ) ) {
+ // We haven't downloaded meta yet, so do that first
+ $result = $this->download_post_meta();
+ if ( is_wp_error( $result ) ) {
+ $this->throw_error( $result, 1 );
+ return false;
+ }
+ }
+
+ // Download a batch of actual posts
+ $result = $this->download_post_bodies();
+ if ( is_wp_error( $result ) ) {
+ if ( 406 == $this->ixr->getErrorCode() ) {
+ ?>
+ <p><strong><?php _e( 'Uh oh – LiveJournal has disconnected us because we made too many requests to their servers too quickly.' ) ?></strong></p>
+ <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>
+ <?php
+ echo $this->next_step( 1, __( 'Try Again' ) );
+ return false;
+ } else {
+ $this->throw_error( $result, 1 );
+ return false;
+ }
+ }
+
+ if ( get_option( 'ljapi_last_sync_count' ) > 0 ) {
+ ?>
+ <form action="admin.php?import=livejournal" method="post" id="ljapi-auto-repost">
+ <?php wp_nonce_field( 'lj-api-import' ) ?>
+ <input type="hidden" name="step" id="step" value="1" />
+ <p><input type="submit" class="button-primary" value="<?php esc_attr_e( 'Import the next batch' ) ?>" /> <span id="auto-message"></span></p>
+ </form>
+ <?php $this->auto_ajax( 'ljapi-auto-repost', 'auto-message', 0 ); ?>
+ <?php
+ } else {
+ echo '<p>' . __( 'Your posts have all been imported, but wait – there’s more! Now we need to download & import your comments.' ) . '</p>';
+ echo $this->next_step( 2, __( 'Download my comments »' ) );
+ $this->auto_submit();
+ }
+ echo '</div>';
+ }
+
+ // Download comments to local XML
+ function step2() {
+ set_time_limit( 0 );
+ update_option( 'ljapi_step', 2 );
+ $this->username = get_option( 'ljapi_username' );
+ $this->password = get_option( 'ljapi_password' );
+ $this->ixr = new IXR_Client( $this->ixr_url, false, 80, 30 );
+
+ echo '<div id="ljapi-status">';
+ echo '<h3>' . __( 'Downloading Comments' ) . '</h3>';
+ echo '<p>' . __( 'Now we will download your comments so we can import them (this could take a <strong>long</strong> time if you have lots of comments)...' ) . '</p>';
+ ob_flush(); flush();
+
+ if ( !get_option( 'ljapi_usermap' ) ) {
+ // We haven't downloaded meta yet, so do that first
+ $result = $this->download_comment_meta();
+ if ( is_wp_error( $result ) ) {
+ $this->throw_error( $result, 2 );
+ return false;
+ }
+ }
+
+ // Download a batch of actual comments
+ $result = $this->download_comment_bodies();
+ if ( is_wp_error( $result ) ) {
+ $this->throw_error( $result, 2 );
+ return false;
+ }
+
+ $maxid = get_option( 'ljapi_maxid' ) ? (int) get_option( 'ljapi_maxid' ) : 1;
+ $highest_id = (int) get_option( 'ljapi_highest_comment_id' );
+ if ( $maxid > $highest_id ) {
+ $batch = $maxid > 5000 ? ceil( $maxid / 5000 ) : 1;
+ ?>
+ <form action="admin.php?import=livejournal" method="post" id="ljapi-auto-repost">
+ <p><strong><?php printf( __( 'Imported comment batch %d of <strong>approximately</strong> %d' ), get_option( 'ljapi_comment_batch' ), $batch ) ?></strong></p>
+ <?php wp_nonce_field( 'lj-api-import' ) ?>
+ <input type="hidden" name="step" id="step" value="2" />
+ <p><input type="submit" class="button-primary" value="<?php esc_attr_e( 'Import the next batch' ) ?>" /> <span id="auto-message"></span></p>
+ </form>
+ <?php $this->auto_ajax( 'ljapi-auto-repost', 'auto-message', 0 ); ?>
+ <?php
+ } else {
+ echo '<p>' . __( 'Your comments have all been imported now, but we still need to rebuild your conversation threads.' ) . '</p>';
+ echo $this->next_step( 3, __( 'Rebuild my comment threads »' ) );
+ $this->auto_submit();
+ }
+ echo '</div>';
+ }
+
+ // Re-thread comments already in the DB
+ function step3() {
+ global $wpdb;
+ set_time_limit( 0 );
+ update_option( 'ljapi_step', 3 );
+
+ echo '<div id="ljapi-status">';
+ echo '<h3>' . __( 'Threading Comments' ) . '</h3>';
+ echo '<p>' . __( 'We are now re-building the threading of your comments (this can also take a while if you have lots of comments)...' ) . '</p>';
+ ob_flush(); flush();
+
+ // Only bother adding indexes if they have over 5000 comments (arbitrary number)
+ $imported_comments = $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->comments} WHERE comment_type = 'livejournal'" );
+ $added_indices = false;
+ if ( 5000 < $imported_comments ) {
+ include_once(ABSPATH . 'wp-admin/includes/upgrade.php');
+ $added_indices = true;
+ add_clean_index( $wpdb->comments, 'comment_type' );
+ add_clean_index( $wpdb->comments, 'comment_karma' );
+ add_clean_index( $wpdb->comments, 'comment_agent' );
+ }
+
+ // Get LJ comments, which haven't been threaded yet, 5000 at a time and thread them
+ while ( $comments = $wpdb->get_results( "SELECT comment_ID, comment_agent FROM {$wpdb->comments} WHERE comment_type = 'livejournal' AND comment_agent != '0' LIMIT 5000", OBJECT ) ) {
+ foreach ( $comments as $comment ) {
+ $wpdb->update( $wpdb->comments,
+ array( 'comment_parent' => $this->get_wp_comment_ID( $comment->comment_agent ), 'comment_type' => 'livejournal-done' ),
+ array( 'comment_ID' => $comment->comment_ID ) );
+ }
+ wp_cache_flush();
+ $wpdb->flush();
+ }
+
+ // Revert the comments table back to normal and optimize it to reclaim space
+ if ( $added_indices ) {
+ drop_index( $wpdb->comments, 'comment_type' );
+ drop_index( $wpdb->comments, 'comment_karma' );
+ drop_index( $wpdb->comments, 'comment_agent' );
+ $wpdb->query( "OPTIMIZE TABLE {$wpdb->comments}" );
+ }
+
+ // Clean up database and we're out
+ $this->cleanup();
+ do_action( 'import_done', 'livejournal' );
+ if ( $imported_comments > 1 )
+ echo '<p>' . sprintf( __( "Successfully re-threaded %s comments." ), number_format( $imported_comments ) ) . '</p>';
+ echo '<h3>';
+ printf( __( 'All done. <a href="%s">Have fun!</a>' ), get_option( 'home' ) );
+ echo '</h3>';
+ echo '</div>';
+ }
+
+ // Output an error message with a button to try again.
+ function throw_error( $error, $step ) {
+ echo '<p><strong>' . $error->get_error_message() . '</strong></p>';
+ echo $this->next_step( $step, __( 'Try Again' ) );
+ }
+
+ // Returns the HTML for a link to the next page
+ function next_step( $next_step, $label, $id = 'ljapi-next-form' ) {
+ $str = '<form action="admin.php?import=livejournal" method="post" id="' . $id . '">';
+ $str .= wp_nonce_field( 'lj-api-import', '_wpnonce', true, false );
+ $str .= wp_referer_field( false );
+ $str .= '<input type="hidden" name="step" id="step" value="' . esc_attr($next_step) . '" />';
+ $str .= '<p><input type="submit" class="button-primary" value="' . esc_attr( $label ) . '" /> <span id="auto-message"></span></p>';
+ $str .= '</form>';
+
+ return $str;
+ }
+
+ // Automatically submit the specified form after $seconds
+ // Include a friendly countdown in the element with id=$msg
+ function auto_submit( $id = 'ljapi-next-form', $msg = 'auto-message', $seconds = 10 ) {
+ ?><script type="text/javascript">
+ next_counter = <?php echo $seconds ?>;
+ jQuery(document).ready(function(){
+ ljapi_msg();
+ });
+
+ function ljapi_msg() {
+ str = '<?php _e( "Continuing in %d" ) ?>';
+ jQuery( '#<?php echo $msg ?>' ).text( str.replace( /%d/, next_counter ) );
+ if ( next_counter <= 0 ) {
+ if ( jQuery( '#<?php echo $id ?>' ).length ) {
+ jQuery( "#<?php echo $id ?> input[type='submit']" ).hide();
+ str = '<?php _e( "Continuing" ) ?> <img src="images/wpspin_light.gif" alt="" id="processing" align="top" />';
+ jQuery( '#<?php echo $msg ?>' ).html( str );
+ jQuery( '#<?php echo $id ?>' ).submit();
+ return;
+ }
+ }
+ next_counter = next_counter - 1;
+ setTimeout('ljapi_msg()', 1000);
+ }
+ </script><?php
+ }
+
+ // Automatically submit the form with #id to continue the process
+ // Hide any submit buttons to avoid people clicking them
+ // Display a countdown in the element indicated by $msg for "Continuing in x"
+ function auto_ajax( $id = 'ljapi-next-form', $msg = 'auto-message', $seconds = 5 ) {
+ ?><script type="text/javascript">
+ next_counter = <?php echo $seconds ?>;
+ jQuery(document).ready(function(){
+ ljapi_msg();
+ });
+
+ function ljapi_msg() {
+ str = '<?php _e( "Continuing in %d" ) ?>';
+ jQuery( '#<?php echo $msg ?>' ).text( str.replace( /%d/, next_counter ) );
+ if ( next_counter <= 0 ) {
+ if ( jQuery( '#<?php echo $id ?>' ).length ) {
+ jQuery( "#<?php echo $id ?> input[type='submit']" ).hide();
+ jQuery.ajaxSetup({'timeout':3600000});
+ str = '<?php _e( "Processing next batch." ) ?> <img src="images/wpspin_light.gif" alt="" id="processing" align="top" />';
+ jQuery( '#<?php echo $msg ?>' ).html( str );
+ jQuery('#ljapi-status').load(ajaxurl, {'action':'lj-importer',
+ 'step':jQuery('#step').val(),
+ '_wpnonce':'<?php echo wp_create_nonce( 'lj-api-import' ) ?>',
+ '_wp_http_referer':'<?php echo $_SERVER['REQUEST_URI'] ?>'});
+ return;
+ }
+ }
+ next_counter = next_counter - 1;
+ setTimeout('ljapi_msg()', 1000);
+ }
+ </script><?php
+ }
+
+ // Remove all options used during import process and
+ // set wp_comments entries back to "normal" values
+ function cleanup() {
+ global $wpdb;
+
+ delete_option( 'ljapi_username' );
+ delete_option( 'ljapi_password' );
+ delete_option( 'ljapi_protected_password' );
+ delete_option( 'ljapi_verified' );
+ delete_option( 'ljapi_total' );
+ delete_option( 'ljapi_count' );
+ delete_option( 'ljapi_lastsync' );
+ delete_option( 'ljapi_last_sync_count' );
+ delete_option( 'ljapi_sync_item_times' );
+ delete_option( 'ljapi_lastsync_posts' );
+ delete_option( 'ljapi_post_batch' );
+ delete_option( 'ljapi_imported_count' );
+ delete_option( 'ljapi_maxid' );
+ delete_option( 'ljapi_usermap' );
+ delete_option( 'ljapi_highest_id' );
+ delete_option( 'ljapi_highest_comment_id' );
+ delete_option( 'ljapi_comment_batch' );
+ delete_option( 'ljapi_step' );
+
+ $wpdb->update( $wpdb->comments,
+ array( 'comment_karma' => 0, 'comment_agent' => 'WP LJ Importer', 'comment_type' => '' ),
+ array( 'comment_type' => 'livejournal-done' ) );
+ $wpdb->update( $wpdb->comments,
+ array( 'comment_karma' => 0, 'comment_agent' => 'WP LJ Importer', 'comment_type' => '' ),
+ array( 'comment_type' => 'livejournal' ) );
+ }
+
+ function LJ_API_Import() {
+ $this->__construct();
+ }
+
+ function __construct() {
+ // Nothing