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