WordPress.org

Make WordPress Core

Ticket #8999: lj-api-importer.diff

File lj-api-importer.diff, 50.3 KB (added by beaulebens, 5 years ago)

My bad - use this diff instead. Had a renaming issue from dev -> diff.

  • wp-admin/admin-ajax.php

     
    11281128        $x->send(); 
    11291129 
    11301130        break; 
     1131case '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; 
    11311144default : 
    11321145        do_action( 'wp_ajax_' . $_POST['action'] ); 
    11331146        die('0'); 
  • wp-admin/import/livejournal.php

     
    11<?php 
    22/** 
    3  * LiveJournal Importer 
     3 * LiveJournal API Importer 
    44 * 
    55 * @package WordPress 
    66 * @subpackage Importer 
    77 */ 
    88 
     9// XML-RPC library for communicating with LiveJournal API 
     10require_once( ABSPATH . WPINC . '/class-IXR.php' ); 
     11 
     12// Snoopy for getting comments (with cookies) 
     13require_once( ABSPATH . WPINC . '/class-snoopy.php' ); 
     14 
    915/** 
    10  * LiveJournal Importer class 
     16 * LiveJournal API Importer class 
    1117 * 
    12  * Imports your LiveJournal XML exported file into WordPress. 
     18 * Imports your LiveJournal contents into WordPress using the LJ API 
    1319 * 
    14  * @since unknown 
     20 * @since 2.7.1 
    1521 */ 
    16 class LJ_Import { 
     22class LJ_API_Import { 
    1723 
    18         var $file; 
     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' ); 
    19169 
    20170        function header() { 
    21171                echo '<div class="wrap">'; 
    22172                screen_icon(); 
    23                 echo '<h2>'.__('Import LiveJournal').'</h2>'; 
     173                echo '<h2>' . __( 'Import LiveJournal' ) . '</h2>'; 
    24174        } 
    25175 
    26176        function footer() { 
    27177                echo '</div>'; 
    28178        } 
    29179 
     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&amp;step=-1&amp;_wpnonce=' . wp_create_nonce( 'lj-api-import' ) . '&amp;_wp_http_referer=' . attribute_escape( $_SERVER['REQUEST_URI'] ) ?>"><?php _e( 'Cancel &amp; 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         
    30237        function unhtmlentities($string) { // From php.net for < 4.3 compat 
    31238                $trans_tbl = get_html_translation_table(HTML_ENTITIES); 
    32239                $trans_tbl = array_flip($trans_tbl); 
    33240                return strtr($string, $trans_tbl); 
    34241        } 
    35  
    36         function greet() { 
    37                 echo '<div class="narrow">'; 
    38                 echo '<p>'.__('Howdy! Upload your LiveJournal XML export file and we&#8217;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&amp;step=1"); 
    41                 echo '</div>'; 
    42         } 
    43  
     242         
    44243        function import_posts() { 
    45                 global $wpdb, $current_user; 
     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                        } 
    46270 
    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); 
     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                 
    55279                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); 
     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 ); 
    63307                        } 
     308                } while ( $num > 0 ); 
    64309 
    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); 
     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 
    68324 
    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); 
     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'; 
    72357 
    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  
    82                         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; 
     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]; 
    95407                                } 
     408                                add_post_meta( $post_id, 'lj_' . $prop, $val ); 
    96409                        } 
     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' ); 
    97425 
    98                         preg_match_all('|<comment>(.*?)</comment>|is', $post, $comments); 
    99                         $comments = $comments[1]; 
     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.' ) ); 
    100435 
    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); 
     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                        } 
    108449 
    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); 
     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 ); 
    114517 
    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)); 
     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>'; 
    118699 
    119                                         preg_match('|<name>(.*?)</name>|is', $comment, $comment_author); 
    120                                         $comment_author = $wpdb->escape(trim($comment_author[1])); 
     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]; 
     713                        echo '<li>'; 
     714                        printf( __( 'Imported comment from <strong>%s</strong> on %s' ), $comment['comment_author'], $comment['comment_date'] ); 
    121715 
    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                                 } 
     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 ); 
    134721                        } 
    135                         if ( $num_comments ) { 
    136                                 echo ' '; 
    137                                 printf(__ngettext('(%s comment)', '(%s comments)', $num_comments), $num_comments); 
    138                         } 
     722                         
    139723                        echo '</li>'; 
    140724                } 
     725                 
     726                // Remove the file now that we're done with it 
     727                @unlink( $filename ); 
     728 
    141729                echo '</ol>'; 
     730                 
     731                return true; 
    142732        } 
     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'] ); 
    143742 
    144         function import() { 
    145                 $file = wp_import_handle_upload(); 
    146                 if ( isset($file['error']) ) { 
    147                         echo $file['error']; 
    148                         return; 
     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>'; 
    149751                } 
    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>'; 
     752                echo '</ol>'; 
    161753        } 
    162  
     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         
    163780        function dispatch() { 
    164                 if (empty ($_GET['step'])) 
     781                if ( empty( $_REQUEST['step'] ) ) 
    165782                        $step = 0; 
    166783                else 
    167                         $step = (int) $_GET['step']; 
     784                        $step = (int) $_REQUEST['step']; 
    168785 
    169786                $this->header(); 
    170  
    171                 switch ($step) { 
     787                 
     788                switch ( $step ) { 
     789                        case -1 : 
     790                                $this->cleanup(); 
     791                                // Intentional no break 
    172792                        case 0 : 
    173793                                $this->greet(); 
    174794                                break; 
    175795                        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 }(); 
    178804                                if ( is_wp_error( $result ) ) 
    179805                                        echo $result->get_error_message(); 
    180806                                break; 
     
    183809                $this->footer(); 
    184810        } 
    185811 
    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&amp;step=-1&amp;_wpnonce=' . wp_create_nonce( 'lj-api-import' ) . '&amp;_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&amp;step=-1&amp;_wpnonce=' . wp_create_nonce( 'lj-api-import' ) . '&amp;_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 &ndash; 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 &amp; import your comments." ) . '</p>'; 
     882                echo $this->next_step( 2, __( 'Download my comments &raquo;' ) ); 
     883                $this->auto_submit(); 
    188884        } 
     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 &raquo;' ) ); 
     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 &raquo;' ) ) ?>" /> <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 &raquo;' ) ); 
     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 &raquo;' ) ) ?>" /> <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 &raquo;' ) ); 
     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 &raquo;' ) ) ?>" /> <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 
     1173        } 
    1891174} 
    1901175 
    191 $livejournal_import = new LJ_Import(); 
     1176$lj_api_import = new LJ_API_Import(); 
    1921177 
    193 register_importer('livejournal', __('LiveJournal'), __('Import posts from a LiveJournal XML export file.'), array ($livejournal_import, 'dispatch')); 
    194 ?> 
     1178register_importer( 'livejournal', __( 'LiveJournal' ), __( 'Import posts from LiveJournal using their API.' ), array( $lj_api_import, 'dispatch' ) ); 
     1179?> 
     1180 No newline at end of file