[44] | 1 | <?php
|
---|
| 2 |
|
---|
| 3 | /**
|
---|
| 4 | * LiveJournal API Importer
|
---|
| 5 | *
|
---|
| 6 | * @package WordPress
|
---|
| 7 | * @subpackage Importer
|
---|
| 8 | */
|
---|
| 9 |
|
---|
| 10 | // XML-RPC library for communicating with LiveJournal API
|
---|
| 11 | require_once( ABSPATH . WPINC . '/class-IXR.php' );
|
---|
| 12 |
|
---|
| 13 | /**
|
---|
| 14 | * LiveJournal API Importer class
|
---|
| 15 | *
|
---|
| 16 | * Imports your LiveJournal contents into WordPress using the LJ API
|
---|
| 17 | *
|
---|
| 18 | * @since 2.8
|
---|
| 19 | */
|
---|
| 20 | class LJ_API_Import {
|
---|
| 21 |
|
---|
| 22 | var $comments_url = 'http://www.livejournal.com/export_comments.bml';
|
---|
| 23 | var $ixr_url = 'http://www.livejournal.com/interface/xmlrpc';
|
---|
| 24 | var $ixr;
|
---|
| 25 | var $username;
|
---|
| 26 | var $password;
|
---|
| 27 | var $comment_meta;
|
---|
| 28 | var $comments;
|
---|
| 29 | var $usermap;
|
---|
| 30 | var $postmap;
|
---|
| 31 | var $commentmap;
|
---|
| 32 | var $pointers = array();
|
---|
| 33 |
|
---|
| 34 | // This list taken from LJ, they don't appear to have an API for it
|
---|
| 35 | var $moods = array( '1' => 'aggravated',
|
---|
| 36 | '10' => 'discontent',
|
---|
| 37 | '100' => 'rushed',
|
---|
| 38 | '101' => 'contemplative',
|
---|
| 39 | '102' => 'nerdy',
|
---|
| 40 | '103' => 'geeky',
|
---|
| 41 | '104' => 'cynical',
|
---|
| 42 | '105' => 'quixotic',
|
---|
| 43 | '106' => 'crazy',
|
---|
| 44 | '107' => 'creative',
|
---|
| 45 | '108' => 'artistic',
|
---|
| 46 | '109' => 'pleased',
|
---|
| 47 | '11' => 'energetic',
|
---|
| 48 | '110' => 'bitchy',
|
---|
| 49 | '111' => 'guilty',
|
---|
| 50 | '112' => 'irritated',
|
---|
| 51 | '113' => 'blank',
|
---|
| 52 | '114' => 'apathetic',
|
---|
| 53 | '115' => 'dorky',
|
---|
| 54 | '116' => 'impressed',
|
---|
| 55 | '117' => 'naughty',
|
---|
| 56 | '118' => 'predatory',
|
---|
| 57 | '119' => 'dirty',
|
---|
| 58 | '12' => 'enraged',
|
---|
| 59 | '120' => 'giddy',
|
---|
| 60 | '121' => 'surprised',
|
---|
| 61 | '122' => 'shocked',
|
---|
| 62 | '123' => 'rejected',
|
---|
| 63 | '124' => 'numb',
|
---|
| 64 | '125' => 'cheerful',
|
---|
| 65 | '126' => 'good',
|
---|
| 66 | '127' => 'distressed',
|
---|
| 67 | '128' => 'intimidated',
|
---|
| 68 | '129' => 'crushed',
|
---|
| 69 | '13' => 'enthralled',
|
---|
| 70 | '130' => 'devious',
|
---|
| 71 | '131' => 'thankful',
|
---|
| 72 | '132' => 'grateful',
|
---|
| 73 | '133' => 'jealous',
|
---|
| 74 | '134' => 'nervous',
|
---|
| 75 | '14' => 'exhausted',
|
---|
| 76 | '15' => 'happy',
|
---|
| 77 | '16' => 'high',
|
---|
| 78 | '17' => 'horny',
|
---|
| 79 | '18' => 'hungry',
|
---|
| 80 | '19' => 'infuriated',
|
---|
| 81 | '2' => 'angry',
|
---|
| 82 | '20' => 'irate',
|
---|
| 83 | '21' => 'jubilant',
|
---|
| 84 | '22' => 'lonely',
|
---|
| 85 | '23' => 'moody',
|
---|
| 86 | '24' => 'pissed off',
|
---|
| 87 | '25' => 'sad',
|
---|
| 88 | '26' => 'satisfied',
|
---|
| 89 | '27' => 'sore',
|
---|
| 90 | '28' => 'stressed',
|
---|
| 91 | '29' => 'thirsty',
|
---|
| 92 | '3' => 'annoyed',
|
---|
| 93 | '30' => 'thoughtful',
|
---|
| 94 | '31' => 'tired',
|
---|
| 95 | '32' => 'touched',
|
---|
| 96 | '33' => 'lazy',
|
---|
| 97 | '34' => 'drunk',
|
---|
| 98 | '35' => 'ditzy',
|
---|
| 99 | '36' => 'mischievous',
|
---|
| 100 | '37' => 'morose',
|
---|
| 101 | '38' => 'gloomy',
|
---|
| 102 | '39' => 'melancholy',
|
---|
| 103 | '4' => 'anxious',
|
---|
| 104 | '40' => 'drained',
|
---|
| 105 | '41' => 'excited',
|
---|
| 106 | '42' => 'relieved',
|
---|
| 107 | '43' => 'hopeful',
|
---|
| 108 | '44' => 'amused',
|
---|
| 109 | '45' => 'determined',
|
---|
| 110 | '46' => 'scared',
|
---|
| 111 | '47' => 'frustrated',
|
---|
| 112 | '48' => 'indescribable',
|
---|
| 113 | '49' => 'sleepy',
|
---|
| 114 | '5' => 'bored',
|
---|
| 115 | '51' => 'groggy',
|
---|
| 116 | '52' => 'hyper',
|
---|
| 117 | '53' => 'relaxed',
|
---|
| 118 | '54' => 'restless',
|
---|
| 119 | '55' => 'disappointed',
|
---|
| 120 | '56' => 'curious',
|
---|
| 121 | '57' => 'mellow',
|
---|
| 122 | '58' => 'peaceful',
|
---|
| 123 | '59' => 'bouncy',
|
---|
| 124 | '6' => 'confused',
|
---|
| 125 | '60' => 'nostalgic',
|
---|
| 126 | '61' => 'okay',
|
---|
| 127 | '62' => 'rejuvenated',
|
---|
| 128 | '63' => 'complacent',
|
---|
| 129 | '64' => 'content',
|
---|
| 130 | '65' => 'indifferent',
|
---|
| 131 | '66' => 'silly',
|
---|
| 132 | '67' => 'flirty',
|
---|
| 133 | '68' => 'calm',
|
---|
| 134 | '69' => 'refreshed',
|
---|
| 135 | '7' => 'crappy',
|
---|
| 136 | '70' => 'optimistic',
|
---|
| 137 | '71' => 'pessimistic',
|
---|
| 138 | '72' => 'giggly',
|
---|
| 139 | '73' => 'pensive',
|
---|
| 140 | '74' => 'uncomfortable',
|
---|
| 141 | '75' => 'lethargic',
|
---|
| 142 | '76' => 'listless',
|
---|
| 143 | '77' => 'recumbent',
|
---|
| 144 | '78' => 'exanimate',
|
---|
| 145 | '79' => 'embarrassed',
|
---|
| 146 | '8' => 'cranky',
|
---|
| 147 | '80' => 'envious',
|
---|
| 148 | '81' => 'sympathetic',
|
---|
| 149 | '82' => 'sick',
|
---|
| 150 | '83' => 'hot',
|
---|
| 151 | '84' => 'cold',
|
---|
| 152 | '85' => 'worried',
|
---|
| 153 | '86' => 'loved',
|
---|
| 154 | '87' => 'awake',
|
---|
| 155 | '88' => 'working',
|
---|
| 156 | '89' => 'productive',
|
---|
| 157 | '9' => 'depressed',
|
---|
| 158 | '90' => 'accomplished',
|
---|
| 159 | '91' => 'busy',
|
---|
| 160 | '92' => 'blah',
|
---|
| 161 | '93' => 'full',
|
---|
| 162 | '95' => 'grumpy',
|
---|
| 163 | '96' => 'weird',
|
---|
| 164 | '97' => 'nauseated',
|
---|
| 165 | '98' => 'ecstatic',
|
---|
| 166 | '99' => 'chipper' );
|
---|
| 167 |
|
---|
| 168 | function header() {
|
---|
| 169 | echo '<div class="wrap">';
|
---|
| 170 | screen_icon();
|
---|
| 171 | echo '<h2>' . __( 'Import LiveJournal' ) . '</h2>';
|
---|
| 172 | }
|
---|
| 173 |
|
---|
| 174 | function footer() {
|
---|
| 175 | echo '</div>';
|
---|
| 176 | }
|
---|
| 177 |
|
---|
| 178 | function greet() {
|
---|
| 179 | ?>
|
---|
| 180 | <div class="narrow">
|
---|
| 181 | <form action="admin.php?import=livejournal" method="post">
|
---|
| 182 | <?php wp_nonce_field( 'lj-api-import' ) ?>
|
---|
| 183 | <?php if ( get_option( 'ljapi_username' ) && get_option( 'ljapi_password' ) ) : ?>
|
---|
| 184 | <input type="hidden" name="step" value="<?php echo esc_attr( get_option( 'ljapi_step' ) ) ?>" />
|
---|
| 185 | <p><?php _e( 'It looks like you attempted to import your LiveJournal posts previously and got interrupted.' ) ?></p>
|
---|
| 186 | <p class="submit">
|
---|
| 187 | <input type="submit" class="button-primary" value="<?php esc_attr_e( 'Continue previous import' ) ?>" />
|
---|
| 188 | </p>
|
---|
| 189 | <p class="submitbox"><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( $_SERVER['REQUEST_URI'] )) ?>" class="deletion submitdelete"><?php _e( 'Cancel & start a new import' ) ?></a></p>
|
---|
| 190 | <p>
|
---|
| 191 | <?php else : ?>
|
---|
| 192 | <input type="hidden" name="step" value="1" />
|
---|
| 193 | <input type="hidden" name="login" value="true" />
|
---|
| 194 | <p><?php _e( 'Howdy! This importer allows you to connect directly to LiveJournal and download all your entries and comments' ) ?></p>
|
---|
| 195 | <p><?php _e( 'Enter your LiveJournal username and password below so we can connect to your account:' ) ?></p>
|
---|
| 196 |
|
---|
| 197 | <table class="form-table">
|
---|
| 198 |
|
---|
| 199 | <tr>
|
---|
| 200 | <th scope="row"><label for="lj_username"><?php _e( 'LiveJournal Username' ) ?></label></th>
|
---|
| 201 | <td><input type="text" name="lj_username" id="lj_username" class="regular-text" /></td>
|
---|
| 202 | </tr>
|
---|
| 203 |
|
---|
| 204 | <tr>
|
---|
| 205 | <th scope="row"><label for="lj_password"><?php _e( 'LiveJournal Password' ) ?></label></th>
|
---|
| 206 | <td><input type="password" name="lj_password" id="lj_password" class="regular-text" /></td>
|
---|
| 207 | </tr>
|
---|
| 208 |
|
---|
| 209 | </table>
|
---|
| 210 |
|
---|
| 211 | <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>
|
---|
| 212 | <p><?php _e( 'If you don’t enter a password, ALL ENTRIES from your LiveJournal will be imported as public posts in WordPress.' ) ?></p>
|
---|
| 213 | <p><?php _e( 'Enter the password you would like to use for all protected entries here:' ) ?></p>
|
---|
| 214 | <table class="form-table">
|
---|
| 215 |
|
---|
| 216 | <tr>
|
---|
| 217 | <th scope="row"><label for="protected_password"><?php _e( 'Protected Post Password' ) ?></label></th>
|
---|
| 218 | <td><input type="text" name="protected_password" id="protected_password" class="regular-text" /></td>
|
---|
| 219 | </tr>
|
---|
| 220 |
|
---|
| 221 | </table>
|
---|
| 222 |
|
---|
| 223 | <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>
|
---|
| 224 |
|
---|
| 225 | <p class="submit">
|
---|
| 226 | <input type="submit" class="button-primary" value="<?php esc_attr_e( 'Connect to LiveJournal and Import' ) ?>" />
|
---|
| 227 | </p>
|
---|
| 228 |
|
---|
| 229 | <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>
|
---|
| 230 |
|
---|
| 231 | <noscript>
|
---|
| 232 | <p><?php _e( '<strong>NOTE:</strong> You appear to have JavaScript disabled, so you will need to manually click through each step of this importer. If you enable JavaScript, it will step through automatically.' ) ?></p>
|
---|
| 233 | </noscript>
|
---|
| 234 | <?php endif; ?>
|
---|
| 235 | </form>
|
---|
| 236 | </div>
|
---|
| 237 | <?php
|
---|
| 238 | }
|
---|
| 239 |
|
---|
| 240 | function download_post_meta() {
|
---|
| 241 | $total = (int) get_option( 'ljapi_total' );
|
---|
| 242 | $count = (int) get_option( 'ljapi_count' );
|
---|
| 243 | $lastsync = get_option( 'ljapi_lastsync' );
|
---|
| 244 | if ( !$lastsync ) {
|
---|
| 245 | update_option( 'ljapi_lastsync', '1900-01-01 00:00:00' );
|
---|
| 246 | }
|
---|
| 247 | $sync_item_times = get_option( 'ljapi_sync_item_times' );
|
---|
| 248 | if ( !is_array( $sync_item_times ) )
|
---|
| 249 | $sync_item_times = array();
|
---|
| 250 |
|
---|
| 251 | do {
|
---|
| 252 | $lastsync = date( 'Y-m-d H:i:s', strtotime( get_option( 'ljapi_lastsync' ) ) );
|
---|
| 253 | $synclist = $this->lj_ixr( 'syncitems', array( 'ver' => 1, 'lastsync' => $lastsync ) );
|
---|
| 254 | if ( is_wp_error( $synclist ) )
|
---|
| 255 | return $synclist;
|
---|
| 256 |
|
---|
| 257 | // Keep track of if we've downloaded everything
|
---|
| 258 | $total = $synclist['total'];
|
---|
| 259 | $count = $synclist['count'];
|
---|
| 260 |
|
---|
| 261 | foreach ( $synclist['syncitems'] as $event ) {
|
---|
| 262 | if ( substr( $event['item'], 0, 2 ) == 'L-' ) {
|
---|
| 263 | $sync_item_times[ str_replace( 'L-', '', $event['item'] ) ] = $event['time'];
|
---|
| 264 | if ( $event['time'] > $lastsync ) {
|
---|
| 265 | $lastsync = $event['time'];
|
---|
| 266 | update_option( 'ljapi_lastsync', $lastsync );
|
---|
| 267 | }
|
---|
| 268 | }
|
---|
| 269 | }
|
---|
| 270 | } while ( $total > $count );
|
---|
| 271 | // endwhile - all post meta is cached locally
|
---|
| 272 | unset( $synclist );
|
---|
| 273 | update_option( 'ljapi_sync_item_times', $sync_item_times );
|
---|
| 274 | update_option( 'ljapi_total', $total );
|
---|
| 275 | update_option( 'ljapi_count', $count );
|
---|
| 276 |
|
---|
| 277 | echo '<p>' . __( 'Post metadata has been downloaded, proceeding with posts...' ) . '</p>';
|
---|
| 278 | }
|
---|
| 279 |
|
---|
| 280 | function download_post_bodies() {
|
---|
| 281 | $imported_count = (int) get_option( 'ljapi_imported_count' );
|
---|
| 282 | $sync_item_times = get_option( 'ljapi_sync_item_times' );
|
---|
| 283 | $lastsync = get_option( 'ljapi_lastsync_posts' );
|
---|
| 284 | if ( !$lastsync )
|
---|
| 285 | update_option( 'ljapi_lastsync_posts', date( 'Y-m-d H:i:s', 0 ) );
|
---|
| 286 |
|
---|
| 287 | $count = 0;
|
---|
| 288 | echo '<ol>';
|
---|
| 289 | do {
|
---|
| 290 | $lastsync = date( 'Y-m-d H:i:s', strtotime( get_option( 'ljapi_lastsync_posts' ) ) );
|
---|
| 291 |
|
---|
| 292 | // Get the batch of items that match up with the syncitems list
|
---|
| 293 | $itemlist = $this->lj_ixr( 'getevents', array( 'ver' => 1,
|
---|
| 294 | 'selecttype' => 'syncitems',
|
---|
| 295 | 'lineendings' => 'pc',
|
---|
| 296 | 'lastsync' => $lastsync ) );
|
---|
| 297 | if ( is_wp_error( $itemlist ) )
|
---|
| 298 | return $itemlist;
|
---|
| 299 |
|
---|
| 300 | if ( $num = count( $itemlist['events'] ) ) {
|
---|
| 301 | for ( $e = 0; $e < count( $itemlist['events'] ); $e++ ) {
|
---|
| 302 | $event = $itemlist['events'][$e];
|
---|
| 303 | $imported_count++;
|
---|
| 304 | $inserted = $this->import_post( $event );
|
---|
| 305 | if ( is_wp_error( $inserted ) )
|
---|
| 306 | return $inserted;
|
---|
| 307 | if ( $sync_item_times[ $event['itemid'] ] > $lastsync )
|
---|
| 308 | $lastsync = $sync_item_times[ $event['itemid'] ];
|
---|
| 309 | wp_cache_flush();
|
---|
| 310 | }
|
---|
| 311 | update_option( 'ljapi_lastsync_posts', $lastsync );
|
---|
| 312 | update_option( 'ljapi_imported_count', $imported_count );
|
---|
| 313 | update_option( 'ljapi_last_sync_count', $num );
|
---|
| 314 | }
|
---|
| 315 | $count++;
|
---|
| 316 | } while ( $num > 0 && $count < 3 ); // Doing up to 3 requests at a time to avoid memory problems
|
---|
| 317 |
|
---|
| 318 | // Used so that step1 knows when to stop posting back on itself
|
---|
| 319 | update_option( 'ljapi_last_sync_count', $num );
|
---|
| 320 |
|
---|
| 321 | // Counter just used to show progress to user
|
---|
| 322 | update_option( 'ljapi_post_batch', ( (int) get_option( 'ljapi_post_batch' ) + 1 ) );
|
---|
| 323 |
|
---|
| 324 | echo '</ol>';
|
---|
| 325 | }
|
---|
| 326 |
|
---|
| 327 | function import_post( $post ) {
|
---|
| 328 | global $wpdb;
|
---|
| 329 |
|
---|
| 330 | // Make sure we haven't already imported this one
|
---|
| 331 | if ( $this->get_wp_post_ID( $post['itemid'] ) )
|
---|
| 332 | return;
|
---|
| 333 |
|
---|
| 334 | $user = wp_get_current_user();
|
---|
| 335 | $post_author = $user->ID;
|
---|
| 336 | $post['security'] = !empty( $post['security'] ) ? $post['security'] : '';
|
---|
| 337 | $post_status = ( 'private' == trim( $post['security'] ) ) ? 'private' : 'publish'; // Only me
|
---|
| 338 | $post_password = ( 'usemask' == trim( $post['security'] ) ) ? $this->protected_password : ''; // "Friends" via password
|
---|
| 339 |
|
---|
| 340 | // For some reason, LJ sometimes sends a date as "2004-04-1408:38:00" (no space btwn date/time)
|
---|
| 341 | $post_date = $post['eventtime'];
|
---|
| 342 | if ( 18 == strlen( $post_date ) )
|
---|
| 343 | $post_date = substr( $post_date, 0, 10 ) . ' ' . substr( $post_date, 10 );
|
---|
| 344 |
|
---|
| 345 | // Cleaning up and linking the title
|
---|
| 346 | $post_title = isset( $post['subject'] ) ? trim( $post['subject'] ) : '';
|
---|
| 347 | $post_title = $this->translate_lj_user( $post_title ); // Translate it, but then we'll strip the link
|
---|
| 348 | $post_title = strip_tags( $post_title ); // Can't have tags in the title in WP
|
---|
| 349 | $post_title = $wpdb->escape( $post_title );
|
---|
| 350 |
|
---|
| 351 | // Clean up content
|
---|
| 352 | $post_content = $post['event'];
|
---|
| 353 | $post_content = preg_replace_callback( '|<(/?[A-Z]+)|', create_function( '$match', 'return "<" . strtolower( $match[1] );' ), $post_content );
|
---|
| 354 | // XHTMLize some tags
|
---|
| 355 | $post_content = str_replace( '<br>', '<br />', $post_content );
|
---|
| 356 | $post_content = str_replace( '<hr>', '<hr />', $post_content );
|
---|
| 357 | // lj-cut ==> <!--more-->
|
---|
| 358 | $post_content = preg_replace( '|<lj-cut text="([^"]*)">|is', '<!--more $1-->', $post_content );
|
---|
| 359 | $post_content = str_replace( array( '<lj-cut>', '</lj-cut>' ), array( '<!--more-->', '' ), $post_content );
|
---|
| 360 | $first = strpos( $post_content, '<!--more' );
|
---|
| 361 | $post_content = substr( $post_content, 0, $first + 1 ) . preg_replace( '|<!--more(.*)?-->|sUi', '', substr( $post_content, $first + 1 ) );
|
---|
| 362 | // lj-user ==> a href
|
---|
| 363 | $post_content = $this->translate_lj_user( $post_content );
|
---|
| 364 | //$post_content = force_balance_tags( $post_content );
|
---|
| 365 | $post_content = $wpdb->escape( $post_content );
|
---|
| 366 |
|
---|
| 367 | // Handle any tags associated with the post
|
---|
| 368 | $tags_input = !empty( $post['props']['taglist'] ) ? $post['props']['taglist'] : '';
|
---|
| 369 |
|
---|
| 370 | // Check if comments are closed on this post
|
---|
| 371 | $comment_status = !empty( $post['props']['opt_nocomments'] ) ? 'closed' : 'open';
|
---|
| 372 |
|
---|
| 373 | echo '<li>';
|
---|
| 374 | if ( $post_id = post_exists( $post_title, $post_content, $post_date ) ) {
|
---|
| 375 | printf( __( 'Post <strong>%s</strong> already exists.' ), stripslashes( $post_title ) );
|
---|
| 376 | } else {
|
---|
| 377 | printf( __( 'Imported post <strong>%s</strong>...' ), stripslashes( $post_title ) );
|
---|
| 378 | $postdata = compact( 'post_author', 'post_date', 'post_content', 'post_title', 'post_status', 'post_password', 'tags_input', 'comment_status' );
|
---|
| 379 | $post_id = wp_insert_post( $postdata, true );
|
---|
| 380 | if ( is_wp_error( $post_id ) ) {
|
---|
| 381 | if ( 'empty_content' == $post_id->get_error_code() )
|
---|
| 382 | return; // Silent skip on "empty" posts
|
---|
| 383 | return $post_id;
|
---|
| 384 | }
|
---|
| 385 | if ( !$post_id ) {
|
---|
| 386 | _e( 'Couldn’t get post ID (creating post failed!)' );
|
---|
| 387 | echo '</li>';
|
---|
| 388 | return new WP_Error( 'insert_post_failed', __( 'Failed to create post.' ) );
|
---|
| 389 | }
|
---|
| 390 |
|
---|
| 391 | // Handle all the metadata for this post
|
---|
| 392 | $this->insert_postmeta( $post_id, $post );
|
---|
| 393 | }
|
---|
| 394 | echo '</li>';
|
---|
| 395 | }
|
---|
| 396 |
|
---|
| 397 | // Convert lj-user tags to links to that user
|
---|
| 398 | function translate_lj_user( $str ) {
|
---|
| 399 | return preg_replace( '|<lj\s+user\s*=\s*["\']([\w-]+)["\']>|', '<a href="http://$1.livejournal.com/" class="lj-user">$1</a>', $str );
|
---|
| 400 | }
|
---|
| 401 |
|
---|
| 402 | function insert_postmeta( $post_id, $post ) {
|
---|
| 403 | // Need the original LJ id for comments
|
---|
| 404 | add_post_meta( $post_id, 'lj_itemid', $post['itemid'] );
|
---|
| 405 |
|
---|
| 406 | // And save the permalink on LJ in case we want to link back or something
|
---|
| 407 | add_post_meta( $post_id, 'lj_permalink', $post['url'] );
|
---|
| 408 |
|
---|
| 409 | // Supports the following "props" from LJ, saved as lj_<prop_name> in wp_postmeta
|
---|
| 410 | // Adult Content - adult_content
|
---|
| 411 | // Location - current_coords + current_location
|
---|
| 412 | // Mood - current_mood (translated from current_moodid)
|
---|
| 413 | // Music - current_music
|
---|
| 414 | // Userpic - picture_keyword
|
---|
| 415 | foreach ( array( 'adult_content', 'current_coords', 'current_location', 'current_moodid', 'current_music', 'picture_keyword' ) as $prop ) {
|
---|
| 416 | if ( !empty( $post['props'][$prop] ) ) {
|
---|
| 417 | if ( 'current_moodid' == $prop ) {
|
---|
| 418 | $prop = 'current_mood';
|
---|
| 419 | $val = $this->moods[ $post['props']['current_moodid'] ];
|
---|
| 420 | } else {
|
---|
| 421 | $val = $post['props'][$prop];
|
---|
| 422 | }
|
---|
| 423 | add_post_meta( $post_id, 'lj_' . $prop, $val );
|
---|
| 424 | }
|
---|
| 425 | }
|
---|
| 426 | }
|
---|
| 427 |
|
---|
| 428 | // Set up a session (authenticate) with LJ
|
---|
| 429 | function get_session() {
|
---|
| 430 | // Get a session via XMLRPC
|
---|
| 431 | $cookie = $this->lj_ixr( 'sessiongenerate', array( 'ver' => 1, 'expiration' => 'short' ) );
|
---|
| 432 | if ( is_wp_error( $cookie ) )
|
---|
| 433 | return new WP_Error( 'cookie', __( 'Could not get a cookie from LiveJournal. Please try again soon.' ) );
|
---|
| 434 | return new WP_Http_Cookie( array( 'name' => 'ljsession', 'value' => $cookie['ljsession'] ) );
|
---|
| 435 | }
|
---|
| 436 |
|
---|
| 437 | // Loops through and gets comment meta from LJ in batches
|
---|
| 438 | function download_comment_meta() {
|
---|
| 439 | $cookie = $this->get_session();
|
---|
| 440 | if ( is_wp_error( $cookie ) )
|
---|
| 441 | return $cookie;
|
---|
| 442 |
|
---|
| 443 | // Load previous state (if any)
|
---|
| 444 | $this->usermap = (array) get_option( 'ljapi_usermap' );
|
---|
| 445 | $maxid = get_option( 'ljapi_maxid' ) ? get_option( 'ljapi_maxid' ) : 1;
|
---|
| 446 | $highest_id = get_option( 'ljapi_highest_id' ) ? get_option( 'ljapi_highest_id' ) : 0;
|
---|
| 447 |
|
---|
| 448 | // We need to loop over the metadata request until we have it all
|
---|
| 449 | while ( $maxid > $highest_id ) {
|
---|
| 450 | // Now get the meta listing
|
---|
| 451 | $results = wp_remote_get( $this->comments_url . '?get=comment_meta&startid=' . ( $highest_id + 1 ),
|
---|
| 452 | array( 'cookies' => array( $cookie ), 'timeout' => 20 ) );
|
---|
| 453 | if ( is_wp_error( $results ) )
|
---|
| 454 | return new WP_Error( 'comment_meta', __( 'Failed to retrieve comment meta information from LiveJournal. Please try again soon.' ) );
|
---|
| 455 |
|
---|
| 456 | $results = wp_remote_retrieve_body( $results );
|
---|
| 457 |
|
---|
| 458 | // Get the maxid so we know if we have them all yet
|
---|
| 459 | preg_match( '|<maxid>(\d+)</maxid>|', $results, $matches );
|
---|
| 460 | if ( 0 == $matches[1] ) {
|
---|
| 461 | // No comment meta = no comments for this journal
|
---|
| 462 | echo '<p>' . __( 'You have no comments to import!' ) . '</p>';
|
---|
| 463 | update_option( 'ljapi_highest_id', 1 );
|
---|
| 464 | update_option( 'ljapi_highest_comment_id', 1 );
|
---|
| 465 | return false; // Bail out of comment importing entirely
|
---|
| 466 | }
|
---|
| 467 | $maxid = !empty( $matches[1] ) ? $matches[1] : $maxid;
|
---|
| 468 |
|
---|
| 469 | // Parse comments and get highest id available
|
---|
| 470 | preg_match_all( '|<comment id=\'(\d+)\'|is', $results, $matches );
|
---|
| 471 | foreach ( $matches[1] as $id ) {
|
---|
| 472 | if ( $id > $highest_id )
|
---|
| 473 | $highest_id = $id;
|
---|
| 474 | }
|
---|
| 475 |
|
---|
| 476 | // Parse out the list of user mappings, and add it to the known list
|
---|
| 477 | preg_match_all( '|<usermap id=\'(\d+)\' user=\'([^\']+)\' />|', $results, $matches );
|
---|
| 478 | foreach ( $matches[1] as $count => $userid )
|
---|
| 479 | $this->usermap[$userid] = $matches[2][$count]; // need this in memory for translating ids => names
|
---|
| 480 |
|
---|
| 481 | wp_cache_flush();
|
---|
| 482 | }
|
---|
| 483 | // endwhile - should have seen all comment meta at this point
|
---|
| 484 |
|
---|
| 485 | update_option( 'ljapi_usermap', $this->usermap );
|
---|
| 486 | update_option( 'ljapi_maxid', $maxid );
|
---|
| 487 | update_option( 'ljapi_highest_id', $highest_id );
|
---|
| 488 |
|
---|
| 489 | echo '<p>' . __( ' Comment metadata downloaded successfully, proceeding with comment bodies...' ) . '</p>';
|
---|
| 490 |
|
---|
| 491 | return true;
|
---|
| 492 | }
|
---|
| 493 |
|
---|
| 494 | // Downloads actual comment bodies from LJ
|
---|
| 495 | // Inserts them all directly to the DB, with additional info stored in "spare" fields
|
---|
| 496 | function download_comment_bodies() {
|
---|
| 497 | global $wpdb;
|
---|
| 498 | $cookie = $this->get_session();
|
---|
| 499 | if ( is_wp_error( $cookie ) )
|
---|
| 500 | return $cookie;
|
---|
| 501 |
|
---|
| 502 | // Load previous state (if any)
|
---|
| 503 | $this->usermap = (array) get_option( 'ljapi_usermap' );
|
---|
| 504 | $maxid = get_option( 'ljapi_maxid' ) ? (int) get_option( 'ljapi_maxid' ) : 1;
|
---|
| 505 | $highest_id = (int) get_option( 'ljapi_highest_comment_id' );
|
---|
| 506 | $loop = 0;
|
---|
| 507 | while ( $maxid > $highest_id && $loop < 5 ) { // We do 5 loops per call to avoid memory limits
|
---|
| 508 | $loop++;
|
---|
| 509 |
|
---|
| 510 | // Get a batch of comments, using the highest_id we've already got as a starting point
|
---|
| 511 | $results = wp_remote_get( $this->comments_url . '?get=comment_body&startid=' . ( $highest_id + 1 ),
|
---|
| 512 | array( 'cookies' => array( $cookie ), 'timeout' => 20 ) );
|
---|
| 513 | if ( is_wp_error( $results ) )
|
---|
| 514 | return new WP_Error( 'comment_bodies', __( 'Failed to retrieve comment bodies from LiveJournal. Please try again soon.' ) );
|
---|
| 515 |
|
---|
| 516 | $results = wp_remote_retrieve_body( $results );
|
---|
| 517 |
|
---|
| 518 | // Parse out each comment and insert directly
|
---|
| 519 | preg_match_all( '|<comment id=\'(\d+)\'.*</comment>|iUs', $results, $matches );
|
---|
| 520 | for ( $c = 0; $c < count( $matches[0] ); $c++ ) {
|
---|
| 521 | // Keep track of highest id seen
|
---|
| 522 | if ( $matches[1][$c] > $highest_id ) {
|
---|
| 523 | $highest_id = $matches[1][$c];
|
---|
| 524 | update_option( 'ljapi_highest_comment_id', $highest_id );
|
---|
| 525 | }
|
---|
| 526 |
|
---|
| 527 | $comment = $matches[0][$c];
|
---|
| 528 |
|
---|
| 529 | // Filter out any captured, deleted comments (nothing useful to import)
|
---|
| 530 | $comment = preg_replace( '|<comment id=\'\d+\' jitemid=\'\d+\' posterid=\'\d+\' state=\'D\'[^/]*/>|is', '', $comment );
|
---|
| 531 |
|
---|
| 532 | // Parse this comment into an array and insert
|
---|
| 533 | $comment = $this->parse_comment( $comment );
|
---|
| 534 | $id = wp_insert_comment( $comment );
|
---|
| 535 |
|
---|
| 536 | // Clear cache
|
---|
| 537 | clean_comment_cache( $id );
|
---|
| 538 | }
|
---|
| 539 |
|
---|
| 540 | // Clear cache to preseve memory
|
---|
| 541 | wp_cache_flush();
|
---|
| 542 | }
|
---|
| 543 | // endwhile - all comments downloaded and ready for bulk processing
|
---|
| 544 |
|
---|
| 545 | // Counter just used to show progress to user
|
---|
| 546 | update_option( 'ljapi_comment_batch', ( (int) get_option( 'ljapi_comment_batch' ) + 1 ) );
|
---|
| 547 |
|
---|
| 548 | return true;
|
---|
| 549 | }
|
---|
| 550 |
|
---|
| 551 | // Takes a block of XML and parses out all the elements of the comment
|
---|
| 552 | function parse_comment( $comment ) {
|
---|
| 553 | global $wpdb;
|
---|
| 554 |
|
---|
| 555 | // Get the top-level attributes
|
---|
| 556 | preg_match( '|<comment([^>]+)>|i', $comment, $attribs );
|
---|
| 557 | preg_match( '| id=\'(\d+)\'|i', $attribs[1], $matches );
|
---|
| 558 | $lj_comment_ID = $matches[1];
|
---|
| 559 | preg_match( '| jitemid=\'(\d+)\'|i', $attribs[1], $matches );
|
---|
| 560 | $lj_comment_post_ID = $matches[1];
|
---|
| 561 | preg_match( '| posterid=\'(\d+)\'|i', $attribs[1], $matches );
|
---|
| 562 | $comment_author_ID = isset( $matches[1] ) ? $matches[1] : 0;
|
---|
| 563 | preg_match( '| parentid=\'(\d+)\'|i', $attribs[1], $matches ); // optional
|
---|
| 564 | $lj_comment_parent = isset( $matches[1] ) ? $matches[1] : 0;
|
---|
| 565 | preg_match( '| state=\'([SDFA])\'|i', $attribs[1], $matches ); // optional
|
---|
| 566 | $lj_comment_state = isset( $matches[1] ) ? $matches[1] : 'A';
|
---|
| 567 |
|
---|
| 568 | // Clean up "subject" - this will become the first line of the comment in WP
|
---|
| 569 | preg_match( '|<subject>(.*)</subject>|is', $comment, $matches );
|
---|
| 570 | if ( isset( $matches[1] ) ) {
|
---|
| 571 | $comment_subject = $wpdb->escape( trim( $matches[1] ) );
|
---|
| 572 | if ( 'Re:' == $comment_subject )
|
---|
| 573 | $comment_subject = '';
|
---|
| 574 | }
|
---|
| 575 |
|
---|
| 576 | // Get the body and HTMLize it
|
---|
| 577 | preg_match( '|<body>(.*)</body>|is', $comment, $matches );
|
---|
| 578 | $comment_content = !empty( $comment_subject ) ? $comment_subject . "\n\n" . $matches[1] : $matches[1];
|
---|
| 579 | $comment_content = @html_entity_decode( $comment_content, ENT_COMPAT, get_option('blog_charset') );
|
---|
| 580 | $comment_content = str_replace( ''', "'", $comment_content );
|
---|
| 581 | $comment_content = wpautop( $comment_content );
|
---|
| 582 | $comment_content = str_replace( '<br>', '<br />', $comment_content );
|
---|
| 583 | $comment_content = str_replace( '<hr>', '<hr />', $comment_content );
|
---|
| 584 | $comment_content = preg_replace_callback( '|<(/?[A-Z]+)|', create_function( '$match', 'return "<" . strtolower( $match[1] );' ), $comment_content );
|
---|
| 585 | $comment_content = $wpdb->escape( trim( $comment_content ) );
|
---|
| 586 |
|
---|
| 587 | // Get and convert the date
|
---|
| 588 | preg_match( '|<date>(.*)</date>|i', $comment, $matches );
|
---|
| 589 | $comment_date = trim( str_replace( array( 'T', 'Z' ), ' ', $matches[1] ) );
|
---|
| 590 |
|
---|
| 591 | // Grab IP if available
|
---|
| 592 | preg_match( '|<property name=\'poster_ip\'>(.*)</property>|i', $comment, $matches ); // optional
|
---|
| 593 | $comment_author_IP = isset( $matches[1] ) ? $matches[1] : '';
|
---|
| 594 |
|
---|
| 595 | // Try to get something useful for the comment author, especially if it was "my" comment
|
---|
| 596 | $author = ( empty( $comment_author_ID ) || empty( $this->usermap[$comment_author_ID] ) || substr( $this->usermap[$comment_author_ID], 0, 4 ) == 'ext_' ) ? __( 'Anonymous' ) : $this->usermap[$comment_author_ID];
|
---|
| 597 | if ( get_option( 'ljapi_username' ) == $author ) {
|
---|
| 598 | $user = wp_get_current_user();
|
---|
| 599 | $user_id = $user->ID;
|
---|
| 600 | $author = $user->display_name;
|
---|
| 601 | $url = trailingslashit( get_option( 'home' ) );
|
---|
| 602 | } else {
|
---|
| 603 | $user_id = 0;
|
---|
| 604 | $url = ( __( 'Anonymous' ) == $author ) ? '' : 'http://' . $author . '.livejournal.com/';
|
---|
| 605 | }
|
---|
| 606 |
|
---|
| 607 | // Send back the array of details
|
---|
| 608 | return array( 'lj_comment_ID' => $lj_comment_ID,
|
---|
| 609 | 'lj_comment_post_ID' => $lj_comment_post_ID,
|
---|
| 610 | 'lj_comment_parent' => ( !empty( $lj_comment_parent ) ? $lj_comment_parent : 0 ),
|
---|
| 611 | 'lj_comment_state' => $lj_comment_state,
|
---|
| 612 | 'comment_post_ID' => $this->get_wp_post_ID( $lj_comment_post_ID ),
|
---|
| 613 | 'comment_author' => $author,
|
---|
| 614 | 'comment_author_url' => $url,
|
---|
| 615 | 'comment_author_email' => '',
|
---|
| 616 | 'comment_content' => $comment_content,
|
---|
| 617 | 'comment_date' => $comment_date,
|
---|
| 618 | 'comment_author_IP' => ( !empty( $comment_author_IP ) ? $comment_author_IP : '' ),
|
---|
| 619 | 'comment_approved' => ( in_array( $lj_comment_state, array( 'A', 'F' ) ) ? 1 : 0 ),
|
---|
| 620 | 'comment_karma' => $lj_comment_ID, // Need this and next value until rethreading is done
|
---|
| 621 | 'comment_agent' => $lj_comment_parent,
|
---|
| 622 | 'comment_type' => 'livejournal', // Custom type, so we can find it later for processing
|
---|
| 623 | 'user_ID' => $user_id
|
---|
| 624 | );
|
---|
| 625 | }
|
---|
| 626 |
|
---|
| 627 |
|
---|
| 628 | // Gets the post_ID that a LJ post has been saved as within WP
|
---|
| 629 | function get_wp_post_ID( $post ) {
|
---|
| 630 | global $wpdb;
|
---|
| 631 |
|
---|
| 632 | if ( empty( $this->postmap[$post] ) )
|
---|
| 633 | $this->postmap[$post] = (int) $wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = 'lj_itemid' AND meta_value = %d", $post ) );
|
---|
| 634 |
|
---|
| 635 | return $this->postmap[$post];
|
---|
| 636 | }
|
---|
| 637 |
|
---|
| 638 | // Gets the comment_ID that a LJ comment has been saved as within WP
|
---|
| 639 | function get_wp_comment_ID( $comment ) {
|
---|
| 640 | global $wpdb;
|
---|
| 641 | if ( empty( $this->commentmap[$comment] ) )
|
---|
| 642 | $this->commentmap[$comment] = $wpdb->get_var( $wpdb->prepare( "SELECT comment_ID FROM $wpdb->comments WHERE comment_karma = %d", $comment ) );
|
---|
| 643 | return $this->commentmap[$comment];
|
---|
| 644 | }
|
---|
| 645 |
|
---|
| 646 | function lj_ixr() {
|
---|
| 647 | if ( $challenge = $this->ixr->query( 'LJ.XMLRPC.getchallenge' ) ) {
|
---|
| 648 | $challenge = $this->ixr->getResponse();
|
---|
| 649 | }
|
---|
| 650 | if ( isset( $challenge['challenge'] ) ) {
|
---|
| 651 | $params = array( 'username' => $this->username,
|
---|
| 652 | 'auth_method' => 'challenge',
|
---|
| 653 | 'auth_challenge' => $challenge['challenge'],
|
---|
| 654 | 'auth_response' => md5( $challenge['challenge'] . md5( $this->password ) ) );
|
---|
| 655 | } else {
|
---|
| 656 | return new WP_Error( 'IXR', __( 'LiveJournal is not responding to authentication requests. Please wait a while and then try again.' ) );
|
---|
| 657 | }
|
---|
| 658 |
|
---|
| 659 | $args = func_get_args();
|
---|
| 660 | $method = array_shift( $args );
|
---|
| 661 | if ( isset( $args[0] ) )
|
---|
| 662 | $params = array_merge( $params, $args[0] );
|
---|
| 663 | if ( $this->ixr->query( 'LJ.XMLRPC.' . $method, $params ) ) {
|
---|
| 664 | return $this->ixr->getResponse();
|
---|
| 665 | } else {
|
---|
| 666 | return new WP_Error( 'IXR', __( 'XML-RPC Request Failed -- ' ) . $this->ixr->getErrorCode() . ': ' . $this->ixr->getErrorMessage() );
|
---|
| 667 | }
|
---|
| 668 | }
|
---|
| 669 |
|
---|
| 670 | function dispatch() {
|
---|
| 671 | if ( empty( $_REQUEST['step'] ) )
|
---|
| 672 | $step = 0;
|
---|
| 673 | else
|
---|
| 674 | $step = (int) $_REQUEST['step'];
|
---|
| 675 |
|
---|
| 676 | $this->header();
|
---|
| 677 |
|
---|
| 678 | switch ( $step ) {
|
---|
| 679 | case -1 :
|
---|
| 680 | $this->cleanup();
|
---|
| 681 | // Intentional no break
|
---|
| 682 | case 0 :
|
---|
| 683 | $this->greet();
|
---|
| 684 | break;
|
---|
| 685 | case 1 :
|
---|
| 686 | case 2 :
|
---|
| 687 | case 3 :
|
---|
| 688 | check_admin_referer( 'lj-api-import' );
|
---|
| 689 | $result = $this->{ 'step' . $step }();
|
---|
| 690 | if ( is_wp_error( $result ) ) {
|
---|
| 691 | $this->throw_error( $result, $step );
|
---|
| 692 | }
|
---|
| 693 | break;
|
---|
| 694 | }
|
---|
| 695 |
|
---|
| 696 | $this->footer();
|
---|
| 697 | }
|
---|
| 698 |
|
---|
| 699 | // Technically the first half of step 1, this is separated to allow for AJAX
|
---|
| 700 | // calls. Sets up some variables and options and confirms authentication.
|
---|
| 701 | function setup() {
|
---|
| 702 | global $verified;
|
---|
| 703 | // Get details from form or from DB
|
---|
| 704 | if ( !empty( $_POST['lj_username'] ) && !empty( $_POST['lj_password'] ) ) {
|
---|
| 705 | // Store details for later
|
---|
| 706 | $this->username = $_POST['lj_username'];
|
---|
| 707 | $this->password = $_POST['lj_password'];
|
---|
| 708 | update_option( 'ljapi_username', $this->username );
|
---|
| 709 | update_option( 'ljapi_password', $this->password );
|
---|
| 710 | } else {
|
---|
| 711 | $this->username = get_option( 'ljapi_username' );
|
---|
| 712 | $this->password = get_option( 'ljapi_password' );
|
---|
| 713 | }
|
---|
| 714 |
|
---|
| 715 | // This is the password to set on protected posts
|
---|
| 716 | if ( !empty( $_POST['protected_password'] ) ) {
|
---|
| 717 | $this->protected_password = $_POST['protected_password'];
|
---|
| 718 | update_option( 'ljapi_protected_password', $this->protected_password );
|
---|
| 719 | } else {
|
---|
| 720 | $this->protected_password = get_option( 'ljapi_protected_password' );
|
---|
| 721 | }
|
---|
| 722 |
|
---|
| 723 | // Login to confirm the details are correct
|
---|
| 724 | if ( empty( $this->username ) || empty( $this->password ) ) {
|
---|
| 725 | ?>
|
---|
| 726 | <p><?php _e( 'Please enter your LiveJournal username <em>and</em> password so we can download your posts and comments.' ) ?></p>
|
---|
| 727 | <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>
|
---|
| 728 | <?php
|
---|
| 729 | return false;
|
---|
| 730 | }
|
---|
| 731 | $verified = $this->lj_ixr( 'login' );
|
---|
| 732 | if ( is_wp_error( $verified ) ) {
|
---|
| 733 | if ( 100 == $this->ixr->getErrorCode() || 101 == $this->ixr->getErrorCode() ) {
|
---|
| 734 | delete_option( 'ljapi_username' );
|
---|
| 735 | delete_option( 'ljapi_password' );
|
---|
| 736 | delete_option( 'ljapi_protected_password' );
|
---|
| 737 | ?>
|
---|
| 738 | <p><?php _e( 'Logging in to LiveJournal failed. Check your username and password and try again.' ) ?></p>
|
---|
| 739 | <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>
|
---|
| 740 | <?php
|
---|
| 741 | return false;
|
---|
| 742 | } else {
|
---|
| 743 | return $verified;
|
---|
| 744 | }
|
---|
| 745 | } else {
|
---|
| 746 | update_option( 'ljapi_verified', 'yes' );
|
---|
| 747 | }
|
---|
| 748 |
|
---|
| 749 | // Set up some options to avoid them autoloading (these ones get big)
|
---|
| 750 | add_option( 'ljapi_sync_item_times', '', '', 'no' );
|
---|
| 751 | add_option( 'ljapi_usermap', '', '', 'no' );
|
---|
| 752 | update_option( 'ljapi_comment_batch', 0 );
|
---|
| 753 |
|
---|
| 754 | return true;
|
---|
| 755 | }
|
---|
| 756 |
|
---|
| 757 | // Check form inputs and start importing posts
|
---|
| 758 | function step1() {
|
---|
| 759 | global $verified;
|
---|
| 760 | set_time_limit( 0 );
|
---|
| 761 | update_option( 'ljapi_step', 1 );
|
---|
| 762 | if ( !$this->ixr ) $this->ixr = new IXR_Client( $this->ixr_url, false, 80, 30 );
|
---|
| 763 | if ( empty( $_POST['login'] ) ) {
|
---|
| 764 | // We're looping -- load some details from DB
|
---|
| 765 | $this->username = get_option( 'ljapi_username' );
|
---|
| 766 | $this->password = get_option( 'ljapi_password' );
|
---|
| 767 | $this->protected_password = get_option( 'ljapi_protected_password' );
|
---|
| 768 | } else {
|
---|
| 769 | // First run (non-AJAX)
|
---|
| 770 | $setup = $this->setup();
|
---|
| 771 | if ( !$setup ) {
|
---|
| 772 | return false;
|
---|
| 773 | } else if ( is_wp_error( $setup ) ) {
|
---|
| 774 | $this->throw_error( $setup, 1 );
|
---|
| 775 | return false;
|
---|
| 776 | }
|
---|
| 777 | }
|
---|
| 778 |
|
---|
| 779 | echo '<div id="ljapi-status">';
|
---|
| 780 | echo '<h3>' . __( 'Importing Posts' ) . '</h3>';
|
---|
| 781 | echo '<p>' . __( 'We’re downloading and importing your LiveJournal posts...' ) . '</p>';
|
---|
| 782 | if ( get_option( 'ljapi_post_batch' ) && count( get_option( 'ljapi_sync_item_times' ) ) ) {
|
---|
| 783 | $batch = count( get_option( 'ljapi_sync_item_times' ) );
|
---|
| 784 | $batch = $count > 300 ? ceil( $batch / 300 ) : 1;
|
---|
| 785 | echo '<p><strong>' . sprintf( __( 'Imported post batch %d of <strong>approximately</strong> %d' ), ( get_option( 'ljapi_post_batch' ) + 1 ), $batch ) . '</strong></p>';
|
---|
| 786 | }
|
---|
| 787 | ob_flush(); flush();
|
---|
| 788 |
|
---|
| 789 | if ( !get_option( 'ljapi_lastsync' ) || '1900-01-01 00:00:00' == get_option( 'ljapi_lastsync' ) ) {
|
---|
| 790 | // We haven't downloaded meta yet, so do that first
|
---|
| 791 | $result = $this->download_post_meta();
|
---|
| 792 | if ( is_wp_error( $result ) ) {
|
---|
| 793 | $this->throw_error( $result, 1 );
|
---|
| 794 | return false;
|
---|
| 795 | }
|
---|
| 796 | }
|
---|
| 797 |
|
---|
| 798 | // Download a batch of actual posts
|
---|
| 799 | $result = $this->download_post_bodies();
|
---|
| 800 | if ( is_wp_error( $result ) ) {
|
---|
| 801 | if ( 406 == $this->ixr->getErrorCode() ) {
|
---|
| 802 | ?>
|
---|
| 803 | <p><strong><?php _e( 'Uh oh – LiveJournal has disconnected us because we made too many requests to their servers too quickly.' ) ?></strong></p>
|
---|
| 804 | <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>
|
---|
| 805 | <?php
|
---|
| 806 | echo $this->next_step( 1, __( 'Try Again' ) );
|
---|
| 807 | return false;
|
---|
| 808 | } else {
|
---|
| 809 | $this->throw_error( $result, 1 );
|
---|
| 810 | return false;
|
---|
| 811 | }
|
---|
| 812 | }
|
---|
| 813 |
|
---|
| 814 | if ( get_option( 'ljapi_last_sync_count' ) > 0 ) {
|
---|
| 815 | ?>
|
---|
| 816 | <form action="admin.php?import=livejournal" method="post" id="ljapi-auto-repost">
|
---|
| 817 | <?php wp_nonce_field( 'lj-api-import' ) ?>
|
---|
| 818 | <input type="hidden" name="step" id="step" value="1" />
|
---|
| 819 | <p><input type="submit" class="button-primary" value="<?php esc_attr_e( 'Import the next batch' ) ?>" /> <span id="auto-message"></span></p>
|
---|
| 820 | </form>
|
---|
| 821 | <?php $this->auto_ajax( 'ljapi-auto-repost', 'auto-message', 0 ); ?>
|
---|
| 822 | <?php
|
---|
| 823 | } else {
|
---|
| 824 | echo '<p>' . __( 'Your posts have all been imported, but wait – there’s more! Now we need to download & import your comments.' ) . '</p>';
|
---|
| 825 | echo $this->next_step( 2, __( 'Download my comments »' ) );
|
---|
| 826 | $this->auto_submit();
|
---|
| 827 | }
|
---|
| 828 | echo '</div>';
|
---|
| 829 | }
|
---|
| 830 |
|
---|
| 831 | // Download comments to local XML
|
---|
| 832 | function step2() {
|
---|
| 833 | set_time_limit( 0 );
|
---|
| 834 | update_option( 'ljapi_step', 2 );
|
---|
| 835 | $this->username = get_option( 'ljapi_username' );
|
---|
| 836 | $this->password = get_option( 'ljapi_password' );
|
---|
| 837 | $this->ixr = new IXR_Client( $this->ixr_url, false, 80, 30 );
|
---|
| 838 |
|
---|
| 839 | echo '<div id="ljapi-status">';
|
---|
| 840 | echo '<h3>' . __( 'Downloading Comments' ) . '</h3>';
|
---|
| 841 | 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>';
|
---|
| 842 | ob_flush(); flush();
|
---|
| 843 |
|
---|
| 844 | if ( !get_option( 'ljapi_usermap' ) ) {
|
---|
| 845 | // We haven't downloaded meta yet, so do that first
|
---|
| 846 | $result = $this->download_comment_meta();
|
---|
| 847 | if ( is_wp_error( $result ) ) {
|
---|
| 848 | $this->throw_error( $result, 2 );
|
---|
| 849 | return false;
|
---|
| 850 | }
|
---|
| 851 | }
|
---|
| 852 |
|
---|
| 853 | // Download a batch of actual comments
|
---|
| 854 | $result = $this->download_comment_bodies();
|
---|
| 855 | if ( is_wp_error( $result ) ) {
|
---|
| 856 | $this->throw_error( $result, 2 );
|
---|
| 857 | return false;
|
---|
| 858 | }
|
---|
| 859 |
|
---|
| 860 | $maxid = get_option( 'ljapi_maxid' ) ? (int) get_option( 'ljapi_maxid' ) : 1;
|
---|
| 861 | $highest_id = (int) get_option( 'ljapi_highest_comment_id' );
|
---|
| 862 | if ( $maxid > $highest_id ) {
|
---|
| 863 | $batch = $maxid > 5000 ? ceil( $maxid / 5000 ) : 1;
|
---|
| 864 | ?>
|
---|
| 865 | <form action="admin.php?import=livejournal" method="post" id="ljapi-auto-repost">
|
---|
| 866 | <p><strong><?php printf( __( 'Imported comment batch %d of <strong>approximately</strong> %d' ), get_option( 'ljapi_comment_batch' ), $batch ) ?></strong></p>
|
---|
| 867 | <?php wp_nonce_field( 'lj-api-import' ) ?>
|
---|
| 868 | <input type="hidden" name="step" id="step" value="2" />
|
---|
| 869 | <p><input type="submit" class="button-primary" value="<?php esc_attr_e( 'Import the next batch' ) ?>" /> <span id="auto-message"></span></p>
|
---|
| 870 | </form>
|
---|
| 871 | <?php $this->auto_ajax( 'ljapi-auto-repost', 'auto-message', 0 ); ?>
|
---|
| 872 | <?php
|
---|
| 873 | } else {
|
---|
| 874 | echo '<p>' . __( 'Your comments have all been imported now, but we still need to rebuild your conversation threads.' ) . '</p>';
|
---|
| 875 | echo $this->next_step( 3, __( 'Rebuild my comment threads »' ) );
|
---|
| 876 | $this->auto_submit();
|
---|
| 877 | }
|
---|
| 878 | echo '</div>';
|
---|
| 879 | }
|
---|
| 880 |
|
---|
| 881 | // Re-thread comments already in the DB
|
---|
| 882 | function step3() {
|
---|
| 883 | global $wpdb;
|
---|
| 884 | set_time_limit( 0 );
|
---|
| 885 | update_option( 'ljapi_step', 3 );
|
---|
| 886 |
|
---|
| 887 | echo '<div id="ljapi-status">';
|
---|
| 888 | echo '<h3>' . __( 'Threading Comments' ) . '</h3>';
|
---|
| 889 | 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>';
|
---|
| 890 | ob_flush(); flush();
|
---|
| 891 |
|
---|
| 892 | // Only bother adding indexes if they have over 5000 comments (arbitrary number)
|
---|
| 893 | $imported_comments = $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->comments} WHERE comment_type = 'livejournal'" );
|
---|
| 894 | $added_indices = false;
|
---|
| 895 | if ( 5000 < $imported_comments ) {
|
---|
| 896 | include_once(ABSPATH . 'wp-admin/includes/upgrade.php');
|
---|
| 897 | $added_indices = true;
|
---|
| 898 | add_clean_index( $wpdb->comments, 'comment_type' );
|
---|
| 899 | add_clean_index( $wpdb->comments, 'comment_karma' );
|
---|
| 900 | add_clean_index( $wpdb->comments, 'comment_agent' );
|
---|
| 901 | }
|
---|
| 902 |
|
---|
| 903 | // Get LJ comments, which haven't been threaded yet, 5000 at a time and thread them
|
---|
| 904 | while ( $comments = $wpdb->get_results( "SELECT comment_ID, comment_agent FROM {$wpdb->comments} WHERE comment_type = 'livejournal' AND comment_agent != '0' LIMIT 5000", OBJECT ) ) {
|
---|
| 905 | foreach ( $comments as $comment ) {
|
---|
| 906 | $wpdb->update( $wpdb->comments,
|
---|
| 907 | array( 'comment_parent' => $this->get_wp_comment_ID( $comment->comment_agent ), 'comment_type' => 'livejournal-done' ),
|
---|
| 908 | array( 'comment_ID' => $comment->comment_ID ) );
|
---|
| 909 | }
|
---|
| 910 | wp_cache_flush();
|
---|
| 911 | $wpdb->flush();
|
---|
| 912 | }
|
---|
| 913 |
|
---|
| 914 | // Revert the comments table back to normal and optimize it to reclaim space
|
---|
| 915 | if ( $added_indices ) {
|
---|
| 916 | drop_index( $wpdb->comments, 'comment_type' );
|
---|
| 917 | drop_index( $wpdb->comments, 'comment_karma' );
|
---|
| 918 | drop_index( $wpdb->comments, 'comment_agent' );
|
---|
| 919 | $wpdb->query( "OPTIMIZE TABLE {$wpdb->comments}" );
|
---|
| 920 | }
|
---|
| 921 |
|
---|
| 922 | // Clean up database and we're out
|
---|
| 923 | $this->cleanup();
|
---|
| 924 | do_action( 'import_done', 'livejournal' );
|
---|
| 925 | if ( $imported_comments > 1 )
|
---|
| 926 | echo '<p>' . sprintf( __( "Successfully re-threaded %s comments." ), number_format( $imported_comments ) ) . '</p>';
|
---|
| 927 | echo '<h3>';
|
---|
| 928 | printf( __( 'All done. <a href="%s">Have fun!</a>' ), get_option( 'home' ) );
|
---|
| 929 | echo '</h3>';
|
---|
| 930 | echo '</div>';
|
---|
| 931 | }
|
---|
| 932 |
|
---|
| 933 | // Output an error message with a button to try again.
|
---|
| 934 | function throw_error( $error, $step ) {
|
---|
| 935 | echo '<p><strong>' . $error->get_error_message() . '</strong></p>';
|
---|
| 936 | echo $this->next_step( $step, __( 'Try Again' ) );
|
---|
| 937 | }
|
---|
| 938 |
|
---|
| 939 | // Returns the HTML for a link to the next page
|
---|
| 940 | function next_step( $next_step, $label, $id = 'ljapi-next-form' ) {
|
---|
| 941 | $str = '<form action="admin.php?import=livejournal" method="post" id="' . $id . '">';
|
---|
| 942 | $str .= wp_nonce_field( 'lj-api-import', '_wpnonce', true, false );
|
---|
| 943 | $str .= wp_referer_field( false );
|
---|
| 944 | $str .= '<input type="hidden" name="step" id="step" value="' . esc_attr($next_step) . '" />';
|
---|
| 945 | $str .= '<p><input type="submit" class="button-primary" value="' . esc_attr( $label ) . '" /> <span id="auto-message"></span></p>';
|
---|
| 946 | $str .= '</form>';
|
---|
| 947 |
|
---|
| 948 | return $str;
|
---|
| 949 | }
|
---|
| 950 |
|
---|
| 951 | // Automatically submit the specified form after $seconds
|
---|
| 952 | // Include a friendly countdown in the element with id=$msg
|
---|
| 953 | function auto_submit( $id = 'ljapi-next-form', $msg = 'auto-message', $seconds = 10 ) {
|
---|
| 954 | ?><script type="text/javascript">
|
---|
| 955 | next_counter = <?php echo $seconds ?>;
|
---|
| 956 | jQuery(document).ready(function(){
|
---|
| 957 | ljapi_msg();
|
---|
| 958 | });
|
---|
| 959 |
|
---|
| 960 | function ljapi_msg() {
|
---|
| 961 | str = '<?php _e( "Continuing in %d" ) ?>';
|
---|
| 962 | jQuery( '#<?php echo $msg ?>' ).text( str.replace( /%d/, next_counter ) );
|
---|
| 963 | if ( next_counter <= 0 ) {
|
---|
| 964 | if ( jQuery( '#<?php echo $id ?>' ).length ) {
|
---|
| 965 | jQuery( "#<?php echo $id ?> input[type='submit']" ).hide();
|
---|
| 966 | str = '<?php _e( "Continuing" ) ?> <img src="images/wpspin_light.gif" alt="" id="processing" align="top" />';
|
---|
| 967 | jQuery( '#<?php echo $msg ?>' ).html( str );
|
---|
| 968 | jQuery( '#<?php echo $id ?>' ).submit();
|
---|
| 969 | return;
|
---|
| 970 | }
|
---|
| 971 | }
|
---|
| 972 | next_counter = next_counter - 1;
|
---|
| 973 | setTimeout('ljapi_msg()', 1000);
|
---|
| 974 | }
|
---|
| 975 | </script><?php
|
---|
| 976 | }
|
---|
| 977 |
|
---|
| 978 | // Automatically submit the form with #id to continue the process
|
---|
| 979 | // Hide any submit buttons to avoid people clicking them
|
---|
| 980 | // Display a countdown in the element indicated by $msg for "Continuing in x"
|
---|
| 981 | function auto_ajax( $id = 'ljapi-next-form', $msg = 'auto-message', $seconds = 5 ) {
|
---|
| 982 | ?><script type="text/javascript">
|
---|
| 983 | next_counter = <?php echo $seconds ?>;
|
---|
| 984 | jQuery(document).ready(function(){
|
---|
| 985 | ljapi_msg();
|
---|
| 986 | });
|
---|
| 987 |
|
---|
| 988 | function ljapi_msg() {
|
---|
| 989 | str = '<?php _e( "Continuing in %d" ) ?>';
|
---|
| 990 | jQuery( '#<?php echo $msg ?>' ).text( str.replace( /%d/, next_counter ) );
|
---|
| 991 | if ( next_counter <= 0 ) {
|
---|
| 992 | if ( jQuery( '#<?php echo $id ?>' ).length ) {
|
---|
| 993 | jQuery( "#<?php echo $id ?> input[type='submit']" ).hide();
|
---|
| 994 | jQuery.ajaxSetup({'timeout':3600000});
|
---|
| 995 | str = '<?php _e( "Processing next batch." ) ?> <img src="images/wpspin_light.gif" alt="" id="processing" align="top" />';
|
---|
| 996 | jQuery( '#<?php echo $msg ?>' ).html( str );
|
---|
| 997 | jQuery('#ljapi-status').load(ajaxurl, {'action':'lj-importer',
|
---|
| 998 | 'step':jQuery('#step').val(),
|
---|
| 999 | '_wpnonce':'<?php echo wp_create_nonce( 'lj-api-import' ) ?>',
|
---|
| 1000 | '_wp_http_referer':'<?php echo $_SERVER['REQUEST_URI'] ?>'});
|
---|
| 1001 | return;
|
---|
| 1002 | }
|
---|
| 1003 | }
|
---|
| 1004 | next_counter = next_counter - 1;
|
---|
| 1005 | setTimeout('ljapi_msg()', 1000);
|
---|
| 1006 | }
|
---|
| 1007 | </script><?php
|
---|
| 1008 | }
|
---|
| 1009 |
|
---|
| 1010 | // Remove all options used during import process and
|
---|
| 1011 | // set wp_comments entries back to "normal" values
|
---|
| 1012 | function cleanup() {
|
---|
| 1013 | global $wpdb;
|
---|
| 1014 |
|
---|
| 1015 | delete_option( 'ljapi_username' );
|
---|
| 1016 | delete_option( 'ljapi_password' );
|
---|
| 1017 | delete_option( 'ljapi_protected_password' );
|
---|
| 1018 | delete_option( 'ljapi_verified' );
|
---|
| 1019 | delete_option( 'ljapi_total' );
|
---|
| 1020 | delete_option( 'ljapi_count' );
|
---|
| 1021 | delete_option( 'ljapi_lastsync' );
|
---|
| 1022 | delete_option( 'ljapi_last_sync_count' );
|
---|
| 1023 | delete_option( 'ljapi_sync_item_times' );
|
---|
| 1024 | delete_option( 'ljapi_lastsync_posts' );
|
---|
| 1025 | delete_option( 'ljapi_post_batch' );
|
---|
| 1026 | delete_option( 'ljapi_imported_count' );
|
---|
| 1027 | delete_option( 'ljapi_maxid' );
|
---|
| 1028 | delete_option( 'ljapi_usermap' );
|
---|
| 1029 | delete_option( 'ljapi_highest_id' );
|
---|
| 1030 | delete_option( 'ljapi_highest_comment_id' );
|
---|
| 1031 | delete_option( 'ljapi_comment_batch' );
|
---|
| 1032 | delete_option( 'ljapi_step' );
|
---|
| 1033 |
|
---|
| 1034 | $wpdb->update( $wpdb->comments,
|
---|
| 1035 | array( 'comment_karma' => 0, 'comment_agent' => 'WP LJ Importer', 'comment_type' => '' ),
|
---|
| 1036 | array( 'comment_type' => 'livejournal-done' ) );
|
---|
| 1037 | $wpdb->update( $wpdb->comments,
|
---|
| 1038 | array( 'comment_karma' => 0, 'comment_agent' => 'WP LJ Importer', 'comment_type' => '' ),
|
---|
| 1039 | array( 'comment_type' => 'livejournal' ) );
|
---|
| 1040 | }
|
---|
| 1041 |
|
---|
| 1042 | function LJ_API_Import() {
|
---|
| 1043 | $this->__construct();
|
---|
| 1044 | }
|
---|
| 1045 |
|
---|
| 1046 | function __construct() {
|
---|
| 1047 | // Nothing
|
---|
| 1048 | }
|
---|
| 1049 | }
|
---|
| 1050 |
|
---|
| 1051 | $lj_api_import = new LJ_API_Import();
|
---|
| 1052 |
|
---|
| 1053 | register_importer( 'livejournal', __( 'LiveJournal' ), __( 'Import posts from LiveJournal using their API.' ), array( $lj_api_import, 'dispatch' ) );
|
---|
| 1054 | ?>
|
---|