| 1 | <?php |
| 2 | |
| 3 | class MT_Atom_Import { |
| 4 | |
| 5 | // General |
| 6 | var $username; |
| 7 | var $password; |
| 8 | |
| 9 | // XML parsing |
| 10 | var $parser; |
| 11 | var $inside_tag = ''; |
| 12 | var $active_tag = ''; |
| 13 | var $entry_tag = ''; |
| 14 | var $last = ''; |
| 15 | var $start_byte = ''; |
| 16 | var $first_child = 0; |
| 17 | var $inside_entry = 0; |
| 18 | var $channel = array(); |
| 19 | var $items = array(); |
| 20 | var $item = array(); |
| 21 | |
| 22 | // The data |
| 23 | var $posts = array(); |
| 24 | var $site_url; |
| 25 | var $xmlrpc_url; |
| 26 | var $next_url; |
| 27 | var $post_count = 0; |
| 28 | var $current_post = 0; |
| 29 | var $more_posts = true; |
| 30 | var $first_run = true; |
| 31 | |
| 32 | function header() { |
| 33 | echo '<div class="wrap">'; |
| 34 | echo '<h2>'.__('Import Movable Type').'</h2>'; |
| 35 | } |
| 36 | |
| 37 | function footer() { |
| 38 | echo '</div>'; |
| 39 | } |
| 40 | |
| 41 | function greet() { |
| 42 | $this->header(); |
| 43 | ?> |
| 44 | <div class="narrow"> |
| 45 | <p><?php _e('Howdy! We’re about to begin importing all of your Movable Type entries into WordPress. To begin, enter the URL of your blog followed by the username and password of an administrator account. When you’re finished, click "Start Importing".'); ?></p> |
| 46 | <p><?php _e('<strong>Note:</strong> Use your web services password instead of your regular account password. To obtain this password, log in to your MT blog and follow these steps:'); ?></p> |
| 47 | <ol> |
| 48 | <li><?php _e('In the upper right, click Hi [username].'); ?></li> |
| 49 | <li><?php _e('Scroll down to the Preferences section.'); ?></li> |
| 50 | <li><?php _e('Under Web Services Password, click reveal.'); ?></li> |
| 51 | <li><?php _e('Enter the password displayed in the password box below.'); ?></li> |
| 52 | </ol> |
| 53 | |
| 54 | <form method="post" action="<?php echo add_query_arg('step', 1); ?>" class="import-upload-form"> |
| 55 | |
| 56 | <?php wp_nonce_field('import-mt-atom'); ?> |
| 57 | <table class="form-table"> |
| 58 | <tr> |
| 59 | <td><label for="mturl"><?php _e('Blog URL:') ?></label></td> |
| 60 | <td><input type="text" style="width:300px" name="mturl" id="mturl" value="http://" /></td> |
| 61 | </tr> |
| 62 | <tr> |
| 63 | <td><label for="mtuser"><?php _e('Username:') ?></label></td> |
| 64 | <td><input type="text" style="width:300px" name="mtuser" id="mtuser" value="" /></td> |
| 65 | </tr> |
| 66 | <tr> |
| 67 | <td><label for="mtpass"><?php _e("Password:") ?></label></td> |
| 68 | <td><input type="password" style="width:300px" name="mtpass" id="mtpass" value="" /></td> |
| 69 | </tr> |
| 70 | </table> |
| 71 | <p class="submit"> |
| 72 | <input type="submit" value="<?php echo attribute_escape(__('Start Importing')); ?>" id="atom-submit" onclick="jQuery('#atom-loading').show();jQuery('#atom-submit').val('<?php echo attribute_escape(__('Importing...')); ?>');" /> <span style="display: none;" id="atom-loading"><img src="<?php echo get_option('home'); ?>/wp-admin/images/loading.gif" alt="Loading" style="margin-bottom: -3px;" /> <?php echo attribute_escape(__('Retrieving entries from server. Do not navigate away from this page.')); ?></span> |
| 73 | </p> |
| 74 | </form> |
| 75 | <p><?php _e('The importer is smart enough not to import duplicates, so you can run this multiple times without worry if—for whatever reason—it doesn\'t finish.'); ?> </p> |
| 76 | </div> |
| 77 | <?php |
| 78 | $this->footer(); |
| 79 | } |
| 80 | |
| 81 | function detect_atom_uri($url) { |
| 82 | // Set the RSD URL |
| 83 | $rsd_url = $url . '/rsd.xml'; |
| 84 | |
| 85 | // Grab the RSD page |
| 86 | $ch2 = curl_init(); |
| 87 | curl_setopt($ch2, CURLOPT_URL, $rsd_url); |
| 88 | curl_setopt($ch2, CURLOPT_RETURNTRANSFER, 1); |
| 89 | curl_setopt($ch2, CURLOPT_TIMEOUT, 5); |
| 90 | $output = @curl_exec($ch2); |
| 91 | |
| 92 | // Parse out the version number |
| 93 | preg_match('#<engineName>([^"]*)</engineName>#i', $output, $version); |
| 94 | |
| 95 | // If the MT version is less than supported, report an error |
| 96 | $ver = trim(strrchr($version[1], ' ')); |
| 97 | if ( $ver < '4.2' ) |
| 98 | return 'version error'; |
| 99 | |
| 100 | // Parse out the xmlrpc URI |
| 101 | preg_match('#<api name="MovableType" preferred="false" apiLink="([^"]*)" blogid="([^"]*)" \/>#i', $output, $xmlrpc); |
| 102 | $this->xmlrpc_url = $xmlrpc[1]; |
| 103 | |
| 104 | // Parse out the Atom URI |
| 105 | preg_match('#<api name="Atom" preferred="false" apiLink="([^"]*)" blogid="([^"]*)" \/>#i', $output, $matches); |
| 106 | |
| 107 | return $matches[1] . '/blog_id=' . $matches[2]; |
| 108 | } |
| 109 | |
| 110 | function fetch_atom($url, $username, $password) { |
| 111 | include_once(ABSPATH . '/wp-admin/includes/class-atom-api.php'); |
| 112 | |
| 113 | // If the MT blog is not a supported version |
| 114 | if ( $url == 'version error/offset=0/limit=20' ) { |
| 115 | $this->version_error(); |
| 116 | return 'error'; |
| 117 | } |
| 118 | |
| 119 | |
| 120 | $atom_api = new AtomAPI($url, $username, $password, 'WSSE'); // Authenticate to the AtomPub feed using WSSE |
| 121 | |
| 122 | // If the login failed, throw an error message |
| 123 | if ( ( $atom_api->err_no != '' ) && ( count($this->posts) == 0 ) ) { |
| 124 | $this->error(); |
| 125 | return 'error'; |
| 126 | } |
| 127 | |
| 128 | // Grab the raw feed data and pass it to the parser |
| 129 | $this->parse_atom( $atom_api->get_feeds( $xml = false ) ); |
| 130 | } |
| 131 | |
| 132 | function parse_atom($xml) { |
| 133 | // Reset the data before parsing a new feed |
| 134 | unset($this->parser); |
| 135 | unset($this->inside_tag); |
| 136 | unset($this->active_tag); |
| 137 | unset($this->channel); |
| 138 | unset($this->items); |
| 139 | unset($this->item); |
| 140 | $this->inside_tag = ''; |
| 141 | $this->active_tag = ''; |
| 142 | $this->entry_tag = ''; |
| 143 | $this->last = ''; |
| 144 | $this->start_byte = ''; |
| 145 | $this->first_child = 0; |
| 146 | $this->inside_entry = 0; |
| 147 | $this->channel = array(); |
| 148 | $this->items = array(); |
| 149 | $this->item = array(); |
| 150 | |
| 151 | // Create an XML parser |
| 152 | $this->parser = xml_parser_create(); |
| 153 | |
| 154 | // Used to make the XML parser work in a class |
| 155 | xml_set_object($this->parser, $this); |
| 156 | |
| 157 | // Set the start and ending element functions |
| 158 | xml_set_element_handler($this->parser, "start_element", "end_element"); |
| 159 | |
| 160 | // Set the character data functions |
| 161 | xml_set_character_data_handler($this->parser, "character_data"); |
| 162 | |
| 163 | // Begin parsing the XML |
| 164 | xml_parse($this->parser, $xml) |
| 165 | or die(sprintf("XML error: %s at line %d", xml_error_string(xml_get_error_code($this->parser)), xml_get_current_line_number($this->parser))); |
| 166 | |
| 167 | // Clean up after the parse |
| 168 | xml_parser_free($this->parser); |
| 169 | } |
| 170 | |
| 171 | function start_element($parser, $element, $attrs) { |
| 172 | switch ($element) { |
| 173 | case 'FEED': |
| 174 | case 'ENTRY': |
| 175 | $this->inside_tag = $element; |
| 176 | break; |
| 177 | |
| 178 | case 'CONTENT': |
| 179 | case 'SUMMARY': |
| 180 | if ( $this->inside_tag == 'ENTRY' ) { |
| 181 | $this->inside_entry = 1; |
| 182 | $this->entry_tag = strtolower($element); |
| 183 | } |
| 184 | break; |
| 185 | |
| 186 | case 'LINK' : |
| 187 | if ( $this->inside_tag == 'FEED' ) { |
| 188 | if ( $attrs['REL'] == 'alternate' || !$attrs['REL'] ) { |
| 189 | $this->_add('channel', 'link', $attrs['HREF']); |
| 190 | } elseif ( $attrs['REL'] == 'next' ) { |
| 191 | $this->_add('channel', 'next', $attrs['HREF']); |
| 192 | } |
| 193 | } elseif ( $this->inside_tag == 'ENTRY' ) { |
| 194 | if ( $attrs['REL'] == 'alternate' || !$attrs['REL'] ) { |
| 195 | $this->_add('item', 'link', $attrs['HREF']); |
| 196 | } elseif ( $attrs['REL'] == 'service.edit' ) { |
| 197 | $this->_add('item', 'link:service.edit', $attrs['HREF']); |
| 198 | } elseif ( $attrs['REL'] == 'replies' ) { |
| 199 | $this->_add('item', 'link:replies', $attrs['HREF']); |
| 200 | } |
| 201 | } elseif ( $this->inside_tag != 'FEED' && $this->inside_tag != 'ENTRY' ) { |
| 202 | if ( $attrs['REL'] == 'next' ) { |
| 203 | $this->_add('channel', 'next', $attrs['HREF']); |
| 204 | } |
| 205 | } |
| 206 | break; |
| 207 | |
| 208 | case 'CATEGORY': |
| 209 | if ( $this->inside_tag == 'ENTRY' ) { |
| 210 | $cats = array ( 'type' => $attrs['SCHEME'], 'term' => $attrs["TERM"] ); |
| 211 | $this->_add('item', 'categories', $cats, 1); |
| 212 | } |
| 213 | break; |
| 214 | |
| 215 | case 'AUTHOR': |
| 216 | if ( $this->inside_tag == 'ENTRY' ) { |
| 217 | $this->inside_tag = 'ENTRY|AUTHOR'; |
| 218 | } |
| 219 | break; |
| 220 | |
| 221 | default : |
| 222 | $this->active_tag = $element; |
| 223 | } |
| 224 | |
| 225 | // Deal with tags inside of content and summary |
| 226 | if ( $this->inside_entry && $element != 'CONTENT' && $element != 'SUMMARY' ) { |
| 227 | // If tags are inlined, then flatten |
| 228 | $attrs = array_change_key_case($attrs, CASE_LOWER); |
| 229 | $attrs_str = implode(' ', |
| 230 | array_map(array($this, 'map_attrs'), |
| 231 | array_keys($attrs), |
| 232 | array_values($attrs) ) ); |
| 233 | |
| 234 | // Add a space if there are attrs |
| 235 | if ( $attrs_str != '' ) |
| 236 | $attrs_str = ' ' . $attrs_str; |
| 237 | |
| 238 | // Make the element lowercase |
| 239 | $el = strtolower($element); |
| 240 | |
| 241 | // Close an opening tag if it had no data |
| 242 | if ( $this->first_child ) |
| 243 | $this->_add('item', $this->entry_tag, ">"); |
| 244 | |
| 245 | // Add the start tag |
| 246 | $this->_add('item', $this->entry_tag, "<$el" . "$attrs_str"); |
| 247 | |
| 248 | // Handle self-closing tags |
| 249 | $this->first_child = 1; |
| 250 | $this->start_byte = xml_get_current_byte_index($parser); |
| 251 | } |
| 252 | } |
| 253 | |
| 254 | function character_data($parser, $cdata) { |
| 255 | switch ($this->inside_tag) { |
| 256 | |
| 257 | // Grab general channel information |
| 258 | case 'FEED': |
| 259 | switch ($this->active_tag) { |
| 260 | case 'TITLE': |
| 261 | $this->_add('channel', strtolower($this->active_tag), $cdata); |
| 262 | break; |
| 263 | case 'FULLCOUNT': |
| 264 | $this->_add('channel', strtolower($this->active_tag), $cdata); |
| 265 | break; |
| 266 | } |
| 267 | break; |
| 268 | |
| 269 | // Grab item information |
| 270 | case 'ENTRY': |
| 271 | switch ($this->active_tag) { |
| 272 | case 'TITLE': |
| 273 | $this->_add('item', strtolower($this->active_tag), $cdata); |
| 274 | break; |
| 275 | |
| 276 | case 'CONTENT': |
| 277 | case 'SUMMARY': |
| 278 | $this->_add('item', $this->inside_tag, $cdata); |
| 279 | break; |
| 280 | |
| 281 | case 'ISSUED': |
| 282 | $this->_add('item', strtolower($this->active_tag), $cdata); |
| 283 | break; |
| 284 | |
| 285 | case 'PUBLISHED': |
| 286 | $this->_add('item', strtolower($this->active_tag), $cdata); |
| 287 | break; |
| 288 | |
| 289 | case 'ID': |
| 290 | $this->_add('item', strtolower($this->active_tag), $cdata); |
| 291 | break; |
| 292 | } |
| 293 | break; |
| 294 | |
| 295 | // For author tags |
| 296 | case 'ENTRY|AUTHOR': |
| 297 | switch ($this->active_tag) { |
| 298 | case 'NAME': |
| 299 | $this->_add('item', 'author', $cdata); |
| 300 | break; |
| 301 | case 'URI': |
| 302 | $this->_add('item', 'author_uri', $cdata); |
| 303 | break; |
| 304 | case 'EMAIL': |
| 305 | $this->_add('item', 'author_email', $cdata); |
| 306 | break; |
| 307 | } |
| 308 | break; |
| 309 | |
| 310 | } |
| 311 | |
| 312 | // Deal with data inside content tags |
| 313 | if ( $this->inside_entry ) { |
| 314 | // Append the start tag close if first_child |
| 315 | if ( $this->first_child ) { |
| 316 | $this->_add('item', $this->entry_tag, '>'); |
| 317 | $this->first_child = 0; |
| 318 | } |
| 319 | |
| 320 | $this->_add('item', $this->entry_tag, $cdata); |
| 321 | } |
| 322 | } |
| 323 | |
| 324 | function end_element($parser, $element) { |
| 325 | // Deal with tags inside of content and summary |
| 326 | if ( $this->inside_entry && $element != 'CONTENT' && $element != 'SUMMARY' ) { |
| 327 | $el = strtolower($element); |
| 328 | |
| 329 | // Add the appropriate end tag depending if the element is a self-closing element |
| 330 | if ( xml_get_current_byte_index($parser) - $this->start_byte > 2 ) { |
| 331 | if ( $this->first_child ) |
| 332 | $this->_add('item', $this->entry_tag, ">"); |
| 333 | $this->_add('item', $this->entry_tag, "</$el>"); |
| 334 | } else { |
| 335 | $this->_add('item', $this->entry_tag, " />"); |
| 336 | } |
| 337 | $this->first_child = 0; |
| 338 | } |
| 339 | |
| 340 | // Reset inside tag back to entry for author tags |
| 341 | if ( $element == 'AUTHOR' && $this->inside_tag == 'ENTRY|AUTHOR' ) { |
| 342 | $this->inside_tag = 'ENTRY'; |
| 343 | } |
| 344 | |
| 345 | if ( $element == $this->inside_tag ) { |
| 346 | $this->inside_tag = ''; |
| 347 | $this->struct[] = array_merge(array('type' => strtolower($element)), $this->last); |
| 348 | } |
| 349 | |
| 350 | if ( $element == 'ENTRY' ) { |
| 351 | $this->items[] = $this->item; |
| 352 | $this->item = ''; |
| 353 | } |
| 354 | |
| 355 | if ( $element == 'CONTENT' || $element == 'SUMMARY' ) { |
| 356 | $this->inside_entry = 0; |
| 357 | } |
| 358 | |
| 359 | $this->active_tag = ''; |
| 360 | } |
| 361 | |
| 362 | function _add($type, $field, $value, $array = 0) { |
| 363 | if ( $array ) { |
| 364 | $this->{$type}[$field][] = $value; |
| 365 | } else { |
| 366 | if ( empty($this->{$type}) || empty($this->{$type}[$field]) ) { |
| 367 | $this->{$type}[$field] = $value; |
| 368 | } else { |
| 369 | $this->{$type}[$field] .= $value; |
| 370 | } |
| 371 | } |
| 372 | |
| 373 | $this->last = $this->{$type}; |
| 374 | } |
| 375 | |
| 376 | function map_attrs($k, $v) { |
| 377 | return "$k=\"$v\""; |
| 378 | } |
| 379 | |
| 380 | function get_entries() { |
| 381 | // Set the URL |
| 382 | if ( $this->next_url != '' ) |
| 383 | $url = $this->detect_atom_uri(trim($_POST['mturl'])) . '/offset=' . $this->next_url . '/limit=20'; |
| 384 | else |
| 385 | $url = $this->detect_atom_uri(trim($_POST['mturl'])) . '/offset=0/limit=20'; |
| 386 | |
| 387 | // Get the entries from the atom feed |
| 388 | $result = $this->fetch_atom($url, $this->username, $this->password); |
| 389 | if ( $result == 'error' ) return $result; |
| 390 | |
| 391 | // Set the site URL and next URLs |
| 392 | $this->site_url = $this->channel['link']; |
| 393 | $this->next_url = $this->next_url + 20; |
| 394 | // $this->post_count = $this->channel['fullcount']; |
| 395 | |
| 396 | // Convert the parsed atom feed to the posts / pages array |
| 397 | foreach ( $this->items AS $item ) { |
| 398 | $this->posts[] = $item; |
| 399 | } |
| 400 | } |
| 401 | |
| 402 | function get_comments($comment_feed) { |
| 403 | $comments = array(); |
| 404 | |
| 405 | // While there are more comments |
| 406 | do { |
| 407 | |
| 408 | // Select the right comments feed URL |
| 409 | if ( $comments_next != '' ) |
| 410 | $comment_uri = $comment_feed . '/offset=' . $comments_next . '/limit=20'; |
| 411 | else |
| 412 | $comment_uri = $comment_feed . '/offset=0/limit=20'; |
| 413 | |
| 414 | // Get the comments from the atom feed |
| 415 | if ( !empty($comment_uri) ) |
| 416 | $this->fetch_atom($comment_uri, $this->username, $this->password); |
| 417 | |
| 418 | // Convert the parsed atom feed to the comments array |
| 419 | foreach ( $this->items AS $item ) { |
| 420 | $comments[] = $item; |
| 421 | } |
| 422 | |
| 423 | $comments_next = $comments_next + 20; |
| 424 | $more_comments = ( count($this->items) > 0 ) ? true : false; |
| 425 | |
| 426 | } while ( $more_comments ); |
| 427 | |
| 428 | return $comments; |
| 429 | } |
| 430 | |
| 431 | function get_additional_data($post_id) { |
| 432 | include_once(ABSPATH . WPINC . '/class-IXR.php'); |
| 433 | |
| 434 | $rpc = new IXR_Client($this->xmlrpc_url); |
| 435 | if ( !$rpc->query('metaWeblog.getPost', $post_id, $this->username, $this->password) ) { |
| 436 | // print("Error (" . $rpc->getErrorCode() . "): "); |
| 437 | // print($rpc->getErrorMessage() . "\n\n"); |
| 438 | } |
| 439 | |
| 440 | return $rpc->getResponse(); |
| 441 | } |
| 442 | |
| 443 | function get_trackbacks($post_id) { |
| 444 | include_once(ABSPATH . WPINC . '/class-IXR.php'); |
| 445 | |
| 446 | $rpc = new IXR_Client($this->xmlrpc_url); |
| 447 | if ( !$rpc->query('mt.getTrackbackPings', $post_id) ) { |
| 448 | // print("Error (" . $rpc->getErrorCode() . "): "); |
| 449 | // print($rpc->getErrorMessage() . "\n\n"); |
| 450 | } |
| 451 | |
| 452 | return $rpc->getResponse(); |
| 453 | } |
| 454 | |
| 455 | function check_draft($url) { |
| 456 | $ch = curl_init(); |
| 457 | curl_setopt($ch, CURLOPT_URL, $url); |
| 458 | curl_setopt($ch, CURLOPT_HEADER, 1); |
| 459 | curl_setopt($ch, CURLOPT_NOBODY, 1); |
| 460 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); |
| 461 | curl_setopt($ch, CURLOPT_TIMEOUT, 5); |
| 462 | $output = @curl_exec($ch); |
| 463 | $response = @curl_getinfo($ch, CURLINFO_HTTP_CODE); |
| 464 | |
| 465 | // If 404 assume this a draft |
| 466 | if ( $response == '404' ) |
| 467 | return 'draft'; |
| 468 | else |
| 469 | return 'publish'; |
| 470 | } |
| 471 | |
| 472 | function process_posts() { |
| 473 | // Start the output list if this is the first run |
| 474 | if ( $this->first_run == true ) { |
| 475 | echo '<div class="wrap"><ol>'; |
| 476 | $this->first_run = false; |
| 477 | } |
| 478 | |
| 479 | // Use output buffering to show the current import progress |
| 480 | if (ob_get_level() == 0) { |
| 481 | ob_start(); |
| 482 | } |
| 483 | // Pad the page with some data so output buffering works across browsers |
| 484 | echo str_pad('',4096); |
| 485 | |
| 486 | foreach ( $this->posts AS $entry ) { |
| 487 | |
| 488 | // Construct the post class from the AtomPub feed |
| 489 | $post = new StdClass(); |
| 490 | |
| 491 | // The entry type (over 1 and we have a post) |
| 492 | if ( count(explode('/', substr($entry['link'], strlen($this->site_url)))) > 1 ) |
| 493 | $post->post_type = 'post'; |
| 494 | else |
| 495 | $post->post_type = 'page'; |
| 496 | // The entry title |
| 497 | if ( isset($entry['title']) ) |
| 498 | $post->post_title = trim($entry['title']); |
| 499 | else |
| 500 | $post->post_title = ''; |
| 501 | // The post content |
| 502 | if ( isset($entry['content']) ) |
| 503 | $post->post_content = trim($entry['content']); |
| 504 | // The post excerpt |
| 505 | if ( isset($entry['summary']) ) |
| 506 | $post->post_excerpt = trim($entry['summary']); |
| 507 | // The post date |
| 508 | $date = strtotime(trim($entry['issued'])); |
| 509 | $date = date('Y-m-d H:i:s', $date); |
| 510 | $date_gmt = get_gmt_from_date($date); |
| 511 | $post->post_modified = $date; |
| 512 | $post->post_modified_gmt = $date_gmt; |
| 513 | $post->post_date = $date; |
| 514 | $post->post_date_gmt = $date_gmt; |
| 515 | // The post slug |
| 516 | $slug = array_reverse(explode('/', trim($entry['link']))); |
| 517 | $slug = substr($slug[0], 0 , -5); |
| 518 | $post->post_name = $slug; |
| 519 | // The categories and tags |
| 520 | if ( isset($entry['categories']) ) { |
| 521 | foreach ( $entry['categories'] AS $cat ) { |
| 522 | $post->categories[] = trim($cat['term']); |
| 523 | $post_keywords = ''; |
| 524 | } |
| 525 | } else { |
| 526 | $post->categories = array(); |
| 527 | $post->post_keywords = ''; |
| 528 | } |
| 529 | // The post author |
| 530 | if ( isset($entry['author']) ) |
| 531 | $post->post_author = trim($entry['author']); |
| 532 | // The post id |
| 533 | $post_id = trim($entry['id']); |
| 534 | $post_id = substr(strrchr($post_id, '.'), 1); |
| 535 | // The additional data |
| 536 | $additional_data = $this->get_additional_data($post_id); |
| 537 | // The comment status |
| 538 | if ( $additional_data['mt_allow_comments'] == 1 ) |
| 539 | $post->comment_status = 'open'; |
| 540 | else |
| 541 | $post->comment_status = 'closed'; |
| 542 | if ( $additional_data['mt_allow_pings'] == 1 ) |
| 543 | $post->ping_status = 'open'; |
| 544 | else |
| 545 | $post->ping_status = 'closed'; |
| 546 | // The tags |
| 547 | $post->post_keywords = $additional_data['mt_tags']; |
| 548 | // The draft status |
| 549 | $post->post_status = $this->check_draft(trim($entry['link'])); |
| 550 | |
| 551 | // Set the post count if we weren't able to determine it earlier. Asssume the current ID count is the number of posts |
| 552 | if ( $this->post_count == '' ) |
| 553 | $this->post_count = $post_id; |
| 554 | |
| 555 | unset($comments); |
| 556 | $comments = array(); |
| 557 | |
| 558 | // Fetch the comments if the post has comments |
| 559 | $coms = $this->get_comments(trim($entry['link:replies'])); |
| 560 | |
| 561 | if ( count($coms) > 0 ) { |
| 562 | foreach ( $coms AS $com ) { |
| 563 | // Construct the comment class from the AtomPub feed |
| 564 | $comment = new StdClass(); |
| 565 | |
| 566 | // The comment date |
| 567 | $date = strtotime(trim($com['published'])); |
| 568 | $date = date('Y-m-d H:i:s', $date); |
| 569 | $comment->comment_date = $date; |
| 570 | // The comment content |
| 571 | $comment->comment_content = trim($com['content']); |
| 572 | // The comment author |
| 573 | $comment->comment_author = trim($com['author']); |
| 574 | // The comment author uri |
| 575 | $comment->comment_author_url = trim($com['author_uri']); |
| 576 | // The comment author email |
| 577 | $comment->comment_author_email = trim($com['author_email']); |
| 578 | // Set the unknown variables |
| 579 | $comment->comment_author_IP = ''; |
| 580 | |
| 581 | // Add the comment to the comments array |
| 582 | $comments[] = $comment; |
| 583 | } |
| 584 | } |
| 585 | |
| 586 | unset($trackbacks); |
| 587 | $pings = array(); |
| 588 | |
| 589 | // Fetch the trackbacks |
| 590 | $trackbacks = $this->get_trackbacks($post_id); |
| 591 | if ( count($trackbacks) > 0 ) { |
| 592 | foreach ( $trackbacks AS $trackback ) { |
| 593 | $ping = new StdClass(); |
| 594 | // The ping date (the date of the post since we don't know the real one) |
| 595 | $ping->comment_date = $post->post_date; |
| 596 | // The ping IP address |
| 597 | $ping->comment_author_IP = $trackback['pingIP']; |
| 598 | // The ping URL |
| 599 | $ping->comment_author_url = $trackback['pingURL']; |
| 600 | // The ping author |
| 601 | $ping->comment_author = $trackback['pingTitle']; |
| 602 | // Set the unknow variables |
| 603 | $ping->comment_author_email = ''; |
| 604 | $ping->comment_content = ''; |
| 605 | $ping->comment_type = 'pingback'; |
| 606 | |
| 607 | // Add the ping to the pings array |
| 608 | $pings[] = $ping; |
| 609 | } |
| 610 | } |
| 611 | |
| 612 | $result = $this->save_post($post, $comments, $pings); |
| 613 | if ( is_wp_error( $result ) ) |
| 614 | return $result; |
| 615 | |
| 616 | // Increase the post count |
| 617 | $this->current_post++; |
| 618 | |
| 619 | // Update the progress bar |
| 620 | $progress_bar = round(( $this->current_post / $this->post_count ) * 500); |
| 621 | $progress_percent = round(( $this->current_post / $this->post_count ) * 100, 1); |
| 622 | ?> |
| 623 | <script type="text/javascript"> |
| 624 | jQuery('.progress_bar .progress_display').animate({ |
| 625 | width: "<?php echo $progress_bar; ?>px" |
| 626 | }, 200); |
| 627 | jQuery('.progress_percent span.percent').html('<?php echo $progress_percent; ?>'); |
| 628 | <?php if ( $progress_percent == 100 ) { ?> |
| 629 | jQuery('.progress_percent img').hide(); |
| 630 | <?php } ?> |
| 631 | </script> |
| 632 | <?php |
| 633 | |
| 634 | // Flush the output buffer to show current state |
| 635 | ob_flush(); |
| 636 | flush(); |
| 637 | usleep(50000); |
| 638 | } |
| 639 | |
| 640 | // Clean up after using the output buffer |
| 641 | ob_end_flush(); |
| 642 | |
| 643 | // If there are no more posts end the list tags |
| 644 | if ( $this->more_posts == false ) { |
| 645 | |
| 646 | // Update the progress bar |
| 647 | $progress_bar = 500; |
| 648 | $progress_percent = 100; |
| 649 | ?> |
| 650 | <script type="text/javascript"> |
| 651 | jQuery('.progress_bar .progress_display').animate({ |
| 652 | width: "<?php echo $progress_bar; ?>px" |
| 653 | }, 200); |
| 654 | jQuery('.progress_percent span.percent').html('<?php echo $progress_percent; ?>'); |
| 655 | <?php if ( $progress_percent == 100 ) { ?> |
| 656 | jQuery('.progress_percent img').hide(); |
| 657 | <?php } ?> |
| 658 | </script> |
| 659 | <?php |
| 660 | |
| 661 | echo '</ol>'; |
| 662 | do_action('import_done', 'mt-atom'); |
| 663 | echo '<h3>'.sprintf(__('All done. <a href="%s">Have fun!</a>'), get_option('home')).'</h3></div>'; |
| 664 | } |
| 665 | } |
| 666 | |
| 667 | function save_post(&$post, &$comments, &$pings) { |
| 668 | $post = get_object_vars($post); |
| 669 | $post = add_magic_quotes($post); |
| 670 | $post = (object) $post; |
| 671 | |
| 672 | if ( $post_id = post_exists($post->post_title, '', $post->post_date) ) { |
| 673 | echo '<li>'; |
| 674 | printf(__('Post <em>%s</em> already exists.'), stripslashes($post->post_title)); |
| 675 | } else { |
| 676 | echo '<li>'; |
| 677 | printf(__('Importing post <em>%s</em>...'), stripslashes($post->post_title)); |
| 678 | |
| 679 | $post->post_author = $this->check_author($post->post_author); //just so that if a post already exists, new users are not created by checkauthor |
| 680 | $post_id = wp_insert_post($post); |
| 681 | if ( is_wp_error( $post_id ) ) |
| 682 | return $post_id; |
| 683 | |
| 684 | // Add categories. |
| 685 | if ( 0 != count($post->categories) ) { |
| 686 | wp_create_categories($post->categories, $post_id); |
| 687 | } |
| 688 | |
| 689 | // Add tags or keywords |
| 690 | if ( 1 < strlen($post->post_keywords) ) { |
| 691 | // Keywords exist. |
| 692 | printf(__('<br />Adding tags <i>%s</i>...'), stripslashes($post->post_keywords)); |
| 693 | wp_add_post_tags($post_id, $post->post_keywords); |
| 694 | } |
| 695 | |
| 696 | $num_comments = 0; |
| 697 | foreach ( $comments as $comment ) { |
| 698 | $comment = get_object_vars($comment); |
| 699 | $comment = add_magic_quotes($comment); |
| 700 | |
| 701 | if ( !comment_exists($comment['comment_author'], $comment['comment_date'])) { |
| 702 | $comment['comment_post_ID'] = $post_id; |
| 703 | $comment = wp_filter_comment($comment); |
| 704 | wp_insert_comment($comment); |
| 705 | $num_comments++; |
| 706 | } |
| 707 | } |
| 708 | |
| 709 | if ( $num_comments ) |
| 710 | printf(' '.__ngettext('(%s comment)', '(%s comments)', $num_comments), $num_comments); |
| 711 | |
| 712 | $num_pings = 0; |
| 713 | foreach ( $pings as $ping ) { |
| 714 | $ping = get_object_vars($ping); |
| 715 | $ping = add_magic_quotes($ping); |
| 716 | |
| 717 | if ( !comment_exists($ping['comment_author'], $ping['comment_date'])) { |
| 718 | $ping['comment_content'] = "<strong>{$ping['comment_author']}</strong>"; |
| 719 | $ping['comment_post_ID'] = $post_id; |
| 720 | $ping = wp_filter_comment($ping); |
| 721 | wp_insert_comment($ping); |
| 722 | $num_pings++; |
| 723 | } |
| 724 | } |
| 725 | |
| 726 | if ( $num_pings ) |
| 727 | printf(' '.__ngettext('(%s ping)', '(%s pings)', $num_pings), $num_pings); |
| 728 | } |
| 729 | |
| 730 | echo '</li>'; |
| 731 | } |
| 732 | |
| 733 | function check_author($author) { |
| 734 | global $wpdb; |
| 735 | |
| 736 | $user_id = username_exists($author); |
| 737 | |
| 738 | // If the username does not exist |
| 739 | if ( !$user_id ) { |
| 740 | $pass = wp_generate_password(); |
| 741 | $user_id = wp_create_user($author, $pass); |
| 742 | } |
| 743 | |
| 744 | return $user_id; |
| 745 | } |
| 746 | |
| 747 | function error() { |
| 748 | ?> |
| 749 | <div class="narrow"> |
| 750 | <h3><?php _e('Import Failed'); ?></h3> |
| 751 | <p><?php _e('There was an error starting the import process. Please go back and verify that the URL, username, and password were entered correctly.'); ?></p> |
| 752 | <p><a href="<?php echo add_query_arg('step', 0); ?>"><?php _e('Restart the Import Process »')?></a></p> |
| 753 | </div> |
| 754 | <?php |
| 755 | } |
| 756 | |
| 757 | function version_error() { |
| 758 | ?> |
| 759 | <div class="narrow"> |
| 760 | <h3><?php _e('Older Movable Type Version Detected'); ?></h3> |
| 761 | <p><?php _e('The importer has detected you are running an older version of Movable Type. To use this importer you must be running version 4.2 or higher. No worries; just use the Movable Type file-based importer.') ?></p> |
| 762 | <p><a href="?import=mt"><?php _e('Restart the Import Process Using the File Importer »')?></a></p> |
| 763 | </div> |
| 764 | <?php |
| 765 | } |
| 766 | |
| 767 | function import() { |
| 768 | $this->header(); |
| 769 | |
| 770 | // Add the username and password as a global |
| 771 | $this->username = $_POST['mtuser']; |
| 772 | $this->password = $_POST['mtpass']; |
| 773 | |
| 774 | // Use output buffering so the progress bar appears immediately |
| 775 | if (ob_get_level() == 0) { |
| 776 | ob_start(); |
| 777 | } |
| 778 | |
| 779 | // Pad the page with some data so output buffering works across browsers |
| 780 | echo str_pad('',4096); |
| 781 | |
| 782 | ?> |
| 783 | <h3><?php _e('Import in Progress, Results Will Appear Momentarily'); ?></h3> |
| 784 | |
| 785 | <p><?php _e('While the importer is running do not navigate away from this page.'); ?></p> |
| 786 | |
| 787 | <div class="progress_bar" style="float:left; width: 500px; height; 20px; padding: 1px; border: 1px solid #dadada;"> |
| 788 | <div class="progress_display" style="width: 0px; background: #ccc"> </div> |
| 789 | </div> |
| 790 | <div class="progress_percent" style="padding: 2px;"> <img src="<?php echo get_option('home'); ?>/wp-admin/images/loading.gif" alt="Loading" style="margin-bottom: -3px;" /> <span class="percent">0</span>%</div> |
| 791 | <?php |
| 792 | |
| 793 | // Clear the output buffer |
| 794 | ob_flush(); |
| 795 | flush(); |
| 796 | ob_end_flush(); |
| 797 | |
| 798 | // While we have more posts |
| 799 | do { |
| 800 | |
| 801 | $result = $this->get_entries(); |
| 802 | |
| 803 | $this->more_posts = ( count($this->posts) > 0 ) ? true : false; |
| 804 | |
| 805 | if ( $result != 'error' ) |
| 806 | $result = $this->process_posts(); |
| 807 | |
| 808 | if ( is_wp_error( $result ) ) |
| 809 | echo $result->get_error_message(); |
| 810 | |
| 811 | // Free memory for next round of post |
| 812 | unset($this->posts); |
| 813 | $this->posts = array(); |
| 814 | |
| 815 | } while ( $this->more_posts ); |
| 816 | |
| 817 | $this->footer(); |
| 818 | } |
| 819 | |
| 820 | function dispatch() { |
| 821 | if (empty ($_GET['step'])) |
| 822 | $step = 0; |
| 823 | else |
| 824 | $step = (int) $_GET['step']; |
| 825 | |
| 826 | switch ($step) { |
| 827 | case 0 : |
| 828 | $this->greet(); |
| 829 | break; |
| 830 | case 1 : |
| 831 | check_admin_referer('import-mt-atom'); |
| 832 | $this->import(); |
| 833 | break; |
| 834 | } |
| 835 | } |
| 836 | |
| 837 | function MT_Atom_Import() { |
| 838 | // Nothing. |
| 839 | } |
| 840 | } |
| 841 | |
| 842 | $mt_atom_import = new MT_Atom_Import(); |
| 843 | |
| 844 | register_importer('mt-atom', __('Movable Type - Web'), __('Import posts and comments from a Movable Type blog with only your login credentials.'), array ($mt_atom_import, 'dispatch')); |
| 845 | ?> |
| 846 | No newline at end of file |