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 | ?>
|
---|