Tumblr Importer - Version 0.7

Version Description

  • Update to use new Tumblr API, many fixes and improvements.
Download this release

Release Info

Developer Otto42
Plugin Icon 128x128 Tumblr Importer
Version 0.7
Comparing to
See all releases

Code changes from version 0.6 to 0.7

Files changed (2) hide show
  1. readme.txt +7 -1
  2. tumblr-importer.php +299 -154
readme.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: wordpressdotorg, Otto42, dd32, westi, dllh
3
  Tags: tumblr, import
4
  Requires at least: 3.2
5
  Tested up to: 3.4
6
- Stable tag: 0.5
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
@@ -25,7 +25,13 @@ Imports a Tumblr blog into a WordPress blog.
25
 
26
  == Upgrade Notice ==
27
 
 
 
28
  == Changelog ==
 
 
 
 
29
  = 0.6 =
30
  * Significant improvements in the performance of the importer
31
  * Improves import of images from Tumblr - better choice of images sizes for theme display
3
  Tags: tumblr, import
4
  Requires at least: 3.2
5
  Tested up to: 3.4
6
+ Stable tag: 0.7
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
25
 
26
  == Upgrade Notice ==
27
 
28
+ Version 0.7 fixes problems caused by Tumblr's removal of the old API, and now uses their new API.
29
+
30
  == Changelog ==
31
+
32
+ = 0.7 =
33
+ * Update to use new Tumblr API, many fixes and improvements.
34
+
35
  = 0.6 =
36
  * Significant improvements in the performance of the importer
37
  * Improves import of images from Tumblr - better choice of images sizes for theme display
tumblr-importer.php CHANGED
@@ -5,7 +5,7 @@ Plugin URI: http://wordpress.org/extend/plugins/tumblr-importer/
5
  Description: Import posts from a Tumblr blog.
6
  Author: wordpressdotorg
7
  Author URI: http://wordpress.org/
8
- Version: 0.6
9
  License: GPL v2 - http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
10
  */
11
 
@@ -49,6 +49,7 @@ class Tumblr_Import extends WP_Importer_Cron {
49
  function __construct() {
50
  add_action( 'tumblr_importer_metadata', array( $this, 'tumblr_importer_metadata' ) );
51
  add_filter( 'tumblr_importer_format_post', array( $this, 'filter_format_post' ) );
 
52
  add_filter( 'wp_insert_post_empty_content', array( $this, 'filter_allow_empty_content' ), 10, 2 );
53
  parent::__construct();
54
  }
@@ -60,9 +61,17 @@ class Tumblr_Import extends WP_Importer_Cron {
60
 
61
  if ( !isset($this->error) ) $this->error = null;
62
 
63
- if ( isset( $_POST['email'] ) && isset( $_POST['password'] ) ) {
 
 
 
 
 
 
 
 
64
  $this->check_credentials();
65
- }
66
  if ( isset( $_POST['blogurl'] ) ) {
67
  $this->start_blog_import();
68
  }
@@ -97,18 +106,29 @@ class Tumblr_Import extends WP_Importer_Cron {
97
 
98
  <div class='wrap'><?php echo screen_icon(); ?>
99
  <h2><?php _e('Import Tumblr', 'tumblr-importer'); ?></h2>
 
100
  <p><?php _e('Howdy! This importer allows you to import posts from your Tumblr account into your WordPress site.', 'tumblr-importer'); ?></p>
101
- <p><?php _e('Firstly, you need to provide your email and password for Tumblr, so that WordPress can access your account.', 'tumblr-importer'); ?></p>
 
 
 
 
 
 
 
 
 
 
 
102
  <form action='?import=tumblr' method='post'>
103
- <?php wp_nonce_field( 'tumblr-import' ) ?>
104
  <table class="form-table">
105
  <tr>
106
- <th scope="row"><label for='email'><?php _e('Email:','tumblr-importer'); ?></label></label></th>
107
- <td><input type='text' class="regular-text" name='email' value='<?php if (isset($this->email)) echo esc_attr($this->email); ?>' /></td>
108
  </tr>
109
  <tr>
110
- <th scope="row"><label for='email'><?php _e('Password:','tumblr-importer'); ?></label></label></th>
111
- <td><input type='password' class="regular-text" name='password' value='<?php if (isset($this->password)) echo esc_attr($this->password); ?>' /></td>
112
  </tr>
113
  </table>
114
  <p class='submit'>
@@ -116,26 +136,73 @@ class Tumblr_Import extends WP_Importer_Cron {
116
  </p>
117
  </form>
118
  </div>
 
 
 
 
 
 
119
  <?php
 
120
  }
121
 
122
- function check_credentials() {
123
- check_admin_referer( 'tumblr-import' );
124
-
125
- $this->email = $_POST['email'];
126
- $this->password = $_POST['password'];
127
-
128
- if ( !is_email( $_POST['email'] ) ) {
129
- $error = __("This doesn't appear to be a valid email address. Please check it and try again.",'tumblr-importer');
130
- $this->error = $error;
131
  }
132
-
133
- $blogs = $this->get_blogs($this->email, $this->password);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
134
  if ( is_wp_error ($blogs) ) {
135
  $this->error = $blogs->get_error_message();
136
  } else {
137
  $this->blogs = $blogs;
138
  }
 
139
  }
140
 
141
  function show_blogs($error=null) {
@@ -270,7 +337,6 @@ class Tumblr_Import extends WP_Importer_Cron {
270
  $done = true;
271
 
272
  $this->error=null;
273
-
274
  if ( !empty( $this->blog[$url]['progress'] ) ) {
275
  $done = false;
276
  do {
@@ -288,7 +354,9 @@ class Tumblr_Import extends WP_Importer_Cron {
288
  //$this->do_queued_import($url);
289
  break;
290
  case 'pages':
291
- $this->do_pages_import($url);
 
 
292
  break;
293
  case 'finish':
294
  default:
@@ -343,7 +411,7 @@ class Tumblr_Import extends WP_Importer_Cron {
343
 
344
  do_action( 'tumblr_importing_post', $post );
345
  $id = wp_insert_post( $post );
346
-
347
  if ( !is_wp_error( $id ) ) {
348
  $post['ID'] = $id; // Allows for the media importing to wp_update_post()
349
  if ( isset( $post['format'] ) ) set_post_format($id, $post['format']);
@@ -368,7 +436,11 @@ class Tumblr_Import extends WP_Importer_Cron {
368
  } while ( false != ($post = next($imported_posts) ) && $this->have_time() );
369
  }
370
  }
371
-
 
 
 
 
372
  function do_drafts_import($url) {
373
  $start = $this->blog[$url]['drafts_complete'];
374
  $total = $this->blog[$url]['total_drafts'];
@@ -385,6 +457,7 @@ class Tumblr_Import extends WP_Importer_Cron {
385
  if ($this->blog[$url]['posts_complete'] + TUMBLR_MAX_IMPORT > $total) $count = $total - $start;
386
  else $count = TUMBLR_MAX_IMPORT;
387
 
 
388
  $imported_posts = $this->fetch_posts($url, $start, $count, $this->email, $this->password, 'draft' );
389
 
390
  if ( empty($imported_posts) ) {
@@ -423,7 +496,7 @@ class Tumblr_Import extends WP_Importer_Cron {
423
  } while ( false != ($post = next($imported_posts) ) && $this->have_time() );
424
  }
425
  }
426
-
427
  function do_pages_import($url) {
428
  $start = $this->blog[$url]['pages_complete'];
429
 
@@ -479,7 +552,6 @@ class Tumblr_Import extends WP_Importer_Cron {
479
  $path = parse_url($source,PHP_URL_PATH);
480
  $filename = basename($path);
481
  }
482
-
483
  // Download file to temp location
484
  $tmp = download_url( $source );
485
  if ( is_wp_error($tmp) )
@@ -546,7 +618,7 @@ class Tumblr_Import extends WP_Importer_Cron {
546
 
547
  break;
548
 
549
- case 'audio':
550
  // Handle Tumblr Hosted Audio
551
  if ( isset( $post['media']['audio'] ) ) {
552
  $id = $this->handle_sideload_import( $post, (string)$post['media']['audio'], $post['post_title'], (string)$post['media']['filename'] );
@@ -596,6 +668,32 @@ class Tumblr_Import extends WP_Importer_Cron {
596
  return true; // all processed
597
  }
598
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
599
  /**
600
  * Fetch a list of blogs for a user
601
  *
@@ -603,61 +701,41 @@ class Tumblr_Import extends WP_Importer_Cron {
603
  * @param $password
604
  * @returns array of blog info or a WP_Error
605
  */
606
- function get_blogs($email, $password) {
607
- $url = 'http://www.tumblr.com/api/authenticate';
608
-
609
- $params = array(
610
- 'email'=>$email,
611
- 'password'=>$password,
612
- );
613
- $options = array( 'body' => $params );
614
-
615
- // fetch the list
616
- $out = wp_remote_post($url,$options);
617
 
618
- switch ( wp_remote_retrieve_response_code( $out ) ) {
619
  case 403: // Bad Username / Password
620
  do_action( 'tumblr_importer_handle_error', 'get_blogs_403' );
621
- return new WP_Error('tumblr_error', __('Tumblr says that the username and password you provided were not valid. Please check you entered them correctly and try to connect again.', 'tumblr-importer' ) );
622
- break;
623
  case 200: // OK
624
  break;
625
  default:
626
- $_error = sprintf( __( 'Tumblr replied with an error: %s', 'tumblr-importer' ), wp_remote_retrieve_body( $out ) );
627
- do_action( 'tumblr_importer_handle_error', 'response_' . wp_remote_retrieve_response_code( $out ) );
628
  return new WP_Error('tumblr_error', $_error );
629
-
630
  }
631
- $body = wp_remote_retrieve_body($out);
632
-
633
- // parse the XML into something useful
634
- $xml = simplexml_load_string($body);
635
 
636
  $blogs = array();
637
-
638
- if (!isset($xml->tumblelog)) {
639
- new WP_Error('tumblr_error', __('No blog information found for this account. ', 'tumblr-importer' ));
640
- do_action( 'tumblr_importer_handle_error', 'no_blog_found' );
641
- }
642
-
643
- $tblogs = $xml->tumblelog;
644
- foreach ($tblogs as $tblog) {
645
  $blog = array();
646
-
647
- if ((string) $tblog['is-admin'] != '1') continue; // we'll only allow admins to import their blogs
648
-
649
- $blog['title'] = (string) $tblog['title'];
650
- $blog['posts'] = (int) $tblog['posts'];
651
- $blog['drafts'] = (int) $tblog['draft-count'];
652
- $blog['queued'] = (int) $tblog['queue-count'];
653
- $blog['avatar'] = (string) $tblog['avatar-url'];
654
- $blog['url'] = (string) $tblog['url'];
655
- $blog['name'] = (string) $tblog['name'];
656
 
657
  $blogs[] = $blog;
658
  }
 
 
 
659
 
660
- return $blogs;
 
661
  }
662
 
663
  /**
@@ -668,141 +746,144 @@ class Tumblr_Import extends WP_Importer_Cron {
668
  * @param $state can be empty for normal posts, or "draft", "queue", or "submission" to get those posts
669
  * @returns false on error, array of posts on success
670
  */
671
- function fetch_posts($url, $start=0, $count = 50, $email = null, $password = null, $state = null) {
672
- $url = trailingslashit($url).'api/read';
673
- $params = array(
674
- 'start'=>$start,
675
- 'num'=>$count,
676
- );
677
- if ( !empty($email) && !empty($password) ) {
678
- $params['email'] = $email;
679
- $params['password'] = $password;
 
 
 
 
 
 
680
  }
681
 
682
- if ( !empty($state) ) $params['state'] = $state;
683
 
684
- $options = array( 'body' => $params );
685
-
686
- // fetch the posts
687
- $out = wp_remote_post($url,$options);
688
- if (wp_remote_retrieve_response_code($out) != 200) return false;
689
- $body = wp_remote_retrieve_body($out);
690
-
691
- // parse the XML into something useful
692
- $xml = simplexml_load_string($body);
693
-
694
- if (!isset($xml->posts->post)) return false;
695
 
696
- $tposts = $xml->posts;
697
  $posts = array();
698
- foreach($tposts->post as $tpost) {
 
699
  $post = array();
700
- $post['tumblr_id'] = (string) $tpost['id'];
701
- $post['tumblr_url'] = (string) $tpost['url-with-slug'];
702
- $post['post_date'] = date( 'Y-m-d H:i:s', strtotime ( (string) $tpost['date'] ) );
703
- $post['post_date_gmt'] = date( 'Y-m-d H:i:s', strtotime ( (string) $tpost['date-gmt'] ) );
704
- $post['post_name'] = (string) $tpost['slug'];
705
- if ( isset($tpost['private']) ) $post['private'] = (string) $tpost['private'];
706
- if ( isset($tpost->{'tag'}) ) {
 
707
  $post['tags_input'] = array();
708
- foreach ( $tpost->{'tag'} as $tag )
709
  $post['tags_input'][] = rtrim( (string) $tag, ','); // Strip trailing Commas off it too.
710
  }
711
 
712
- // set the various post info for each special format tumblr offers
713
- // TODO reorg this as needed
714
- switch ((string) $tpost['type']) {
715
  case 'photo':
716
  $post['format'] = 'image';
717
- $post['media']['src'] = (string) $tpost->{'photo-url'}[0];
718
- $post['media']['link'] =(string) $tpost->{'photo-link-url'};
719
- $post['media']['width'] = (string) $tpost['width'];
720
- $post['media']['height'] = (string) $tpost['height'];
721
- $post['post_content'] = (string) $tpost->{'photo-caption'};
722
- if ( !empty( $tpost->{'photoset'} ) ) {
723
  $post['format'] = 'gallery';
724
- foreach ( $tpost->{'photoset'}->{'photo'} as $photo ) {
725
  $post['gallery'][] = array (
726
- 'src'=>$photo->{'photo-url'}[0],
727
- 'width'=>$photo['width'],
728
- 'height'=>$photo['height'],
729
- 'caption'=>$photo['caption'],
730
  );
731
  }
732
  }
733
  break;
734
  case 'quote':
735
  $post['format'] = 'quote';
736
- $post['post_content'] = (string) $tpost->{'quote-text'};
737
- $post['post_content'] .= "\n\n" . (string) $tpost->{'quote-source'};
738
  break;
739
  case 'link':
740
  $post['format'] = 'link';
741
- $linkurl = (string) $tpost->{'link-url'};
742
- $linktext = (string) $tpost->{'link-text'};
743
- $post['post_content'] = "<a href='{$linkurl}'>{$linktext}</a>";
744
- $post['post_title'] = (string) $tpost->{'link-description'};
 
 
745
  break;
746
- case 'conversation':
747
  $post['format'] = 'chat';
748
- $post['post_title'] = (string) $tpost->{'conversation-title'};
749
- $post['post_content'] = (string) $tpost->{'conversation-text'};
750
  break;
751
  case 'audio':
752
  $post['format'] = 'audio';
753
- $post['media']['filename'] = basename( (string) $tpost->{'authorized-download-url'} ) . '.mp3';
754
- $post['media']['audio'] = (string) $tpost->{'authorized-download-url'} .'?plead=please-dont-download-this-or-our-lawyers-wont-let-us-host-audio';
755
- $post['post_content'] = (string) $tpost->{'audio-player'} . "\n" . (string) $tpost->{'audio-caption'};
756
- if ( !empty($tpost->{'id3-artist'}) )
757
- $post['post_title'] = $tpost->{'id3-artist'} . ' - ' . $tpost->{'id3-title'};
 
758
  break;
759
  case 'video':
760
  $post['format'] = 'video';
761
  $post['post_content'] = '';
762
- if ( is_serialized( (string) $tpost->{'video-source'} ) ) {
763
- if ( preg_match('|\'(http://.*video_file.*)\'|U', $tpost->{'video-player'}[0], $matches) ) {
764
- $post['media']['video'] = $matches[1];
765
- $val = unserialize( (string) $tpost->{'video-source'} );
766
- $vidmeta = $val['o1'];
767
- $post['media']['filename'] = basename($post['media']['video']) . '.' . $vidmeta['extension'];
768
- $post['media']['width'] = $vidmeta['width'];
769
- $post['media']['height'] = $vidmeta['height'];
770
- }
771
- } else if ( false !== strpos( (string) $tpost->{'video-source'}, 'embed' ) ) {
772
- if ( preg_match_all('/<embed (.+?)>/', (string) $tpost->{'video-source'}, $matches) ) {
773
  foreach ($matches[1] as $match) {
774
- foreach ( wp_kses_hair($match, array('http')) as $attr)
775
- $embed[$attr['name']] = $attr['value'];
776
  }
777
-
778
  // special case for weird youtube vids
779
- $embed['src'] = preg_replace('|http://www.youtube.com/v/([a-zA-Z0-9_]+).*|i', 'http://www.youtube.com/watch?v=$1', $embed['src']);
780
-
781
  // TODO find other special cases, since tumblr is full of them
782
-
783
  $post['post_content'] = $embed['src'];
784
  }
 
785
  // Sometimes, video-source contains iframe markup.
786
- if ( preg_match( '/<iframe/', $tpost->{'video-source'} ) ) {
787
- $embed['src'] = preg_replace( '|<iframe.*src="http://www.youtube.com/embed/([a-zA-Z0-9_\-]+)\??.*".*</iframe>|', 'http://www.youtube.com/watch/?v=$1', $tpost->{'video-source'} );
788
  $post['post_content'] = $embed['src'];
789
  }
790
-
 
 
791
  } else {
792
- // @todo: See if the video-source is going to be oEmbed'able before adding the flash player
793
- // 1 Seems to be "original" size, with 0 being set otherwise.
794
- $post['post_content'] .= isset($tpost->{'video-player'}[1]) ? $tpost->{'video-player'}[1] : (string) $tpost->{'video-player'}[0];
795
  }
796
- $post['post_content'] .= "\n" . (string) $tpost->{'video-caption'};
 
797
  break;
798
  case 'answer':
799
- $post['post_title'] = (string) $tpost->{'question'};
800
- $post['post_content'] = (string) $tpost->{'answer'};
 
801
  break;
802
  case 'regular':
 
803
  default:
804
- $post['post_title'] = (string) $tpost->{'regular-title'};
805
- $post['post_content'] = (string) $tpost->{'regular-body'};
806
  break;
807
  }
808
  $posts[] = $post;
@@ -883,5 +964,69 @@ class Tumblr_Import extends WP_Importer_Cron {
883
  return $maybe_empty;
884
  }
885
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
886
  }
887
  }
5
  Description: Import posts from a Tumblr blog.
6
  Author: wordpressdotorg
7
  Author URI: http://wordpress.org/
8
+ Version: 0.7
9
  License: GPL v2 - http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
10
  */
11
 
49
  function __construct() {
50
  add_action( 'tumblr_importer_metadata', array( $this, 'tumblr_importer_metadata' ) );
51
  add_filter( 'tumblr_importer_format_post', array( $this, 'filter_format_post' ) );
52
+ add_filter( 'tumblr_importer_get_consumer_key', array( $this, 'get_consumer_key' ) );
53
  add_filter( 'wp_insert_post_empty_content', array( $this, 'filter_allow_empty_content' ), 10, 2 );
54
  parent::__construct();
55
  }
61
 
62
  if ( !isset($this->error) ) $this->error = null;
63
 
64
+ $this->consumerkey = defined ('TUMBLR_CONSUMER_KEY') ? TUMBLR_CONSUMER_KEY : ( !empty($_POST['consumerkey']) ? $_POST['consumerkey'] : $this->consumerkey );
65
+ $this->secretkey = defined ('TUMBLR_SECRET_KEY') ? TUMBLR_SECRET_KEY : ( !empty($_POST['secretkey']) ? $_POST['secretkey'] : $this->secretkey );
66
+
67
+ // if we have access tokens, verify that they work
68
+ if ( !empty( $this->access_tokens ) ) {
69
+ // TODO
70
+ } else if ( isset( $_GET['oauth_verifier'] ) ) {
71
+ $this->check_permissions();
72
+ } else if ( !empty( $this->consumerkey ) && !empty( $this->secretkey ) ) {
73
  $this->check_credentials();
74
+ }
75
  if ( isset( $_POST['blogurl'] ) ) {
76
  $this->start_blog_import();
77
  }
106
 
107
  <div class='wrap'><?php echo screen_icon(); ?>
108
  <h2><?php _e('Import Tumblr', 'tumblr-importer'); ?></h2>
109
+ <?php if ( empty($this->request_tokens) ) { ?>
110
  <p><?php _e('Howdy! This importer allows you to import posts from your Tumblr account into your WordPress site.', 'tumblr-importer'); ?></p>
111
+ <p><?php _e("First, you will need to create an 'app' on Tumblr. The app provides a connection point between your blog and Tumblr's servers.", 'tumblr-importer'); ?></p>
112
+
113
+ <p><?php _e('To create an app, visit this page:', 'tumblr-importer'); ?><a href="http://www.tumblr.com/oauth/apps">http://www.tumblr.com/oauth/apps</a></p>
114
+ <ol>
115
+ <li><?php _e('Click the large green "Register Application" button.','tumblr-importer'); ?></li>
116
+ <li><?php _e('You need to fill in the "Application Name", "Application Website", and "Default Callback URL" fields. All the rest can be left blank.','tumblr-importer'); ?></li>
117
+ <li><?php _e('For the "Application Website" and "Default Callback URL" fields, please put in this URL: ','tumblr-importer'); echo '<strong>'.home_url().'</strong>'; ?></li>
118
+ <li><?php _e('Note: It is important that you put in that URL <em>exactly as given</em>.','tumblr-importer'); ?></li>
119
+ </ol>
120
+
121
+ <p><?php _e('After creating the application, copy and paste the "OAuth Consumer Key" and "Secret Key" into the given fields below.', 'tumblr-importer'); ?></p>
122
+
123
  <form action='?import=tumblr' method='post'>
 
124
  <table class="form-table">
125
  <tr>
126
+ <th scope="row"><label for='consumerkey'><?php _e('OAuth Consumer Key:','tumblr-importer'); ?></label></label></th>
127
+ <td><input type='text' class="regular-text" name='consumerkey' value='<?php if (isset($this->consumerkey)) echo esc_attr($this->consumerkey); ?>' /></td>
128
  </tr>
129
  <tr>
130
+ <th scope="row"><label for='secretkey'><?php _e('Secret Key:','tumblr-importer'); ?></label></label></th>
131
+ <td><input type='text' class="regular-text" name='secretkey' value='<?php if (isset($this->secretkey)) echo esc_attr($this->secretkey); ?>' /></td>
132
  </tr>
133
  </table>
134
  <p class='submit'>
136
  </p>
137
  </form>
138
  </div>
139
+ <?php } else {
140
+ ?>
141
+ <p><?php _e("Everything seems to be in order, so now you need to tell Tumblr to allow the plugin to access your account.", 'tumblr-importer'); ?></p>
142
+ <p><?php _e("To do this, click the Authorize link below. You will be redirected back to this page when you've granted the permission.", 'tumblr-importer'); ?></p>
143
+
144
+ <p><a href="<?php echo $this->authorize_url; ?>"><?php _e('Authorize the Application','tumblr-importer'); ?></a></p>
145
  <?php
146
+ }
147
  }
148
 
149
+ function check_credentials() {
150
+ if ( !( $response = $this->oauth_get_request_token() ) )
151
+ return;
152
+
153
+ if ( is_wp_error( $response ) || 200 != wp_remote_retrieve_response_code( $response ) ) {
154
+ $this->error = __('Tumblr returned an error: ', 'tumblr-importer') . wp_remote_retrieve_response_code( $response ) .' '. wp_remote_retrieve_body( $response );
155
+ return;
 
 
156
  }
157
+ // parse the body
158
+ $this->request_tokens = array();
159
+ wp_parse_str( wp_remote_retrieve_body( $response ), $this->request_tokens);
160
+ $this->authorize_url = add_query_arg(array(
161
+ 'oauth_token' => $this->request_tokens ['oauth_token'],
162
+ 'oauth_callback' => urlencode( self_admin_url('admin.php?import=tumblr') ),
163
+ ), 'http://www.tumblr.com/oauth/authorize');
164
+
165
+ return;
166
+ }
167
+
168
+ function check_permissions() {
169
+ $verifier = $_GET['oauth_verifier'];
170
+ $token = $_GET['oauth_token'];
171
+
172
+ // get the access_tokens
173
+ $url = 'http://www.tumblr.com/oauth/access_token';
174
+
175
+ $params = array('oauth_consumer_key' => $this->consumerkey,
176
+ "oauth_nonce" => time().rand(),
177
+ "oauth_timestamp" => time(),
178
+ "oauth_token" => $this->request_tokens['oauth_token'],
179
+ "oauth_signature_method" => "HMAC-SHA1",
180
+ "oauth_verifier" => $verifier,
181
+ "oauth_version" => "1.0",
182
+ );
183
+
184
+ $params['oauth_signature'] = $this->oauth_signature(array($this->secretkey,$this->request_tokens['oauth_token_secret']), 'GET', $url, $params);
185
+
186
+ $url = add_query_arg( array_map('urlencode', $params), $url);
187
+ $response = wp_remote_get( $url );
188
+ unset($this->request_tokens);
189
+ if ( is_wp_error( $response ) || 200 != wp_remote_retrieve_response_code( $response ) ) {
190
+ $this->error = __('Tumblr returned an error: ', 'tumblr-importer') . wp_remote_retrieve_response_code( $response ) .' '. wp_remote_retrieve_body( $response );
191
+ return;
192
+ } else {
193
+ $this->access_tokens = array();
194
+ wp_parse_str( wp_remote_retrieve_body( $response ), $this->access_tokens);
195
+ }
196
+
197
+ // try to get the list of blogs on the account
198
+
199
+ $blogs = $this->get_blogs();
200
  if ( is_wp_error ($blogs) ) {
201
  $this->error = $blogs->get_error_message();
202
  } else {
203
  $this->blogs = $blogs;
204
  }
205
+ return;
206
  }
207
 
208
  function show_blogs($error=null) {
337
  $done = true;
338
 
339
  $this->error=null;
 
340
  if ( !empty( $this->blog[$url]['progress'] ) ) {
341
  $done = false;
342
  do {
354
  //$this->do_queued_import($url);
355
  break;
356
  case 'pages':
357
+ // TODO Tumblr's new API has no way to retrieve pages that I can find
358
+ $this->blog[$url]['progress'] = 'finish';
359
+ //$this->do_pages_import($url);
360
  break;
361
  case 'finish':
362
  default:
411
 
412
  do_action( 'tumblr_importing_post', $post );
413
  $id = wp_insert_post( $post );
414
+
415
  if ( !is_wp_error( $id ) ) {
416
  $post['ID'] = $id; // Allows for the media importing to wp_update_post()
417
  if ( isset( $post['format'] ) ) set_post_format($id, $post['format']);
436
  } while ( false != ($post = next($imported_posts) ) && $this->have_time() );
437
  }
438
  }
439
+
440
+ function get_draft_post_type( $post_type ) {
441
+ return 'draft';
442
+ }
443
+
444
  function do_drafts_import($url) {
445
  $start = $this->blog[$url]['drafts_complete'];
446
  $total = $this->blog[$url]['total_drafts'];
457
  if ($this->blog[$url]['posts_complete'] + TUMBLR_MAX_IMPORT > $total) $count = $total - $start;
458
  else $count = TUMBLR_MAX_IMPORT;
459
 
460
+ add_filter( 'tumblr_post_type', array( $this, 'get_draft_post_type' ) );
461
  $imported_posts = $this->fetch_posts($url, $start, $count, $this->email, $this->password, 'draft' );
462
 
463
  if ( empty($imported_posts) ) {
496
  } while ( false != ($post = next($imported_posts) ) && $this->have_time() );
497
  }
498
  }
499
+
500
  function do_pages_import($url) {
501
  $start = $this->blog[$url]['pages_complete'];
502
 
552
  $path = parse_url($source,PHP_URL_PATH);
553
  $filename = basename($path);
554
  }
 
555
  // Download file to temp location
556
  $tmp = download_url( $source );
557
  if ( is_wp_error($tmp) )
618
 
619
  break;
620
 
621
+ case 'audio':
622
  // Handle Tumblr Hosted Audio
623
  if ( isset( $post['media']['audio'] ) ) {
624
  $id = $this->handle_sideload_import( $post, (string)$post['media']['audio'], $post['post_title'], (string)$post['media']['filename'] );
668
  return true; // all processed
669
  }
670
 
671
+
672
+ /**
673
+ * Get a request token from the OAuth endpoint (also serves as a test)
674
+ *
675
+ */
676
+ function oauth_get_request_token() {
677
+ if ( empty($this->consumerkey) || empty ($this->secretkey) )
678
+ return false;
679
+
680
+ $url = 'http://www.tumblr.com/oauth/request_token';
681
+
682
+ $params = array('oauth_callback' => urlencode( self_admin_url('admin.php?import=tumblr') ),
683
+ 'oauth_consumer_key' => $this->consumerkey,
684
+ "oauth_version" => "1.0",
685
+ "oauth_nonce" => time(),
686
+ "oauth_timestamp" => time(),
687
+ "oauth_signature_method" => "HMAC-SHA1",
688
+ );
689
+
690
+ $params['oauth_signature'] = $this->oauth_signature(array($this->secretkey,''), 'POST', $url, $params);
691
+
692
+ $response = wp_remote_post( $url, array('body' => $params));
693
+
694
+ return $response;
695
+ }
696
+
697
  /**
698
  * Fetch a list of blogs for a user
699
  *
701
  * @param $password
702
  * @returns array of blog info or a WP_Error
703
  */
704
+ function get_blogs() {
705
+ $url = 'http://api.tumblr.com/v2/user/info';
706
+ $response = $this->oauth_get_request($url);
 
 
 
 
 
 
 
 
707
 
708
+ switch ( $response->meta->status ) {
709
  case 403: // Bad Username / Password
710
  do_action( 'tumblr_importer_handle_error', 'get_blogs_403' );
711
+ return new WP_Error('tumblr_error', __('Tumblr says that the the app is not authorized. Please check the settings and try to connect again.', 'tumblr-importer' ) );
 
712
  case 200: // OK
713
  break;
714
  default:
715
+ $_error = sprintf( __( 'Tumblr replied with an error: %s', 'tumblr-importer' ), $response->meta->msg );
716
+ do_action( 'tumblr_importer_handle_error', 'response_' . $response->meta->status );
717
  return new WP_Error('tumblr_error', $_error );
 
718
  }
 
 
 
 
719
 
720
  $blogs = array();
721
+ foreach ( $response->response->user->blogs as $tblog ) {
 
 
 
 
 
 
 
722
  $blog = array();
723
+ $blog['title'] = (string) $tblog->title;
724
+ $blog['posts'] = (int) $tblog->posts;
725
+ $blog['drafts'] = (int) $tblog->drafts;
726
+ $blog['queued'] = (int) $tblog->queue;
727
+ $blog['avatar'] = '';
728
+ $blog['url'] = (string) $tblog->url;
729
+ $blog['name'] = (string) $tblog->name;
 
 
 
730
 
731
  $blogs[] = $blog;
732
  }
733
+ $this->blogs = $blogs;
734
+ return $this->blogs;
735
+ }
736
 
737
+ function get_consumer_key() {
738
+ return $this->consumerkey;
739
  }
740
 
741
  /**
746
  * @param $state can be empty for normal posts, or "draft", "queue", or "submission" to get those posts
747
  * @returns false on error, array of posts on success
748
  */
749
+ function fetch_posts($url, $start=0, $count = 50, $email = null, $password = null, $state = null ) {
750
+ $url = parse_url( $url, PHP_URL_HOST );
751
+ $post_type = apply_filters( 'tumblr_post_type', '' );
752
+ $url = trailingslashit( "http://api.tumblr.com/v2/blog/$url/posts/$post_type" );
753
+
754
+ do_action( 'tumblr_importer_pre_fetch_posts' );
755
+
756
+ // These extra params hose up the auth if passed for oauth requests e.g. for drafts, so use them only for normal posts.
757
+ if ( '' == $post_type ) {
758
+ $params = array(
759
+ 'offset' => $start,
760
+ 'limit' => $count,
761
+ 'api_key' => apply_filters( 'tumblr_importer_get_consumer_key', '' ),
762
+ );
763
+ $url = add_query_arg( $params, $url );
764
  }
765
 
766
+ $response = $this->oauth_get_request($url);
767
 
768
+ switch ( $response->meta->status ) {
769
+ case 200: // OK
770
+ break;
771
+ default:
772
+ $_error = sprintf( __( 'Tumblr replied with an error: %s', 'tumblr-importer' ), $response->meta->msg );
773
+ do_action( 'tumblr_importer_handle_error', 'response_' . $response->meta->status );
774
+ return new WP_Error('tumblr_error', $_error );
775
+ }
 
 
 
776
 
 
777
  $posts = array();
778
+ $tposts = $response->response->posts;
779
+ foreach( $tposts as $tpost ) {
780
  $post = array();
781
+ $post['tumblr_id'] = (string) $tpost->id;
782
+ $post['tumblr_url'] = (string) $tpost->post_url;
783
+ $post['post_date'] = date( 'Y-m-d H:i:s', strtotime ( (string) $tpost->date ) );
784
+ $post['post_date_gmt'] = date( 'Y-m-d H:i:s', strtotime ( (string) $tpost->date ) );
785
+ $post['post_name'] = (string) $tpost->slug;
786
+ if ( 'private' == $tpost->state )
787
+ $post['private'] = (string) $tpost->state;
788
+ if ( isset( $tpost->tags ) ) {
789
  $post['tags_input'] = array();
790
+ foreach ( $tpost->tags as $tag )
791
  $post['tags_input'][] = rtrim( (string) $tag, ','); // Strip trailing Commas off it too.
792
  }
793
 
794
+ switch ( (string) $tpost->type ) {
 
 
795
  case 'photo':
796
  $post['format'] = 'image';
797
+ $post['media']['src'] = (string) $tpost->photos[0]->original_size->url;
798
+ $post['media']['link'] = '';//TODO: Find out what to use here.(string) $tpost->{'photo-link-url'};
799
+ $post['media']['width'] = (string) $tpost->photos[0]->original_size->width;
800
+ $post['media']['height'] = (string) $tpost->photos[0]->original_size->height;
801
+ $post['post_content'] = (string) $tpost->caption;
802
+ if ( ! empty( $tpost->photos ) ) {
803
  $post['format'] = 'gallery';
804
+ foreach ( $tpost->photos as $photo ) {
805
  $post['gallery'][] = array (
806
+ 'src' => $photo->original_size->url,
807
+ 'width' => $photo->original_size->width,
808
+ 'height' => $photo->original_size->height,
809
+ 'caption' => $photo->caption,
810
  );
811
  }
812
  }
813
  break;
814
  case 'quote':
815
  $post['format'] = 'quote';
816
+ $post['post_content'] = '<blockquote>' . (string) $tpost->text . '</blockquote>';
817
+ $post['post_content'] .= "\n\n<div class='attribution'>" . (string) $tpost->source . '</div>';
818
  break;
819
  case 'link':
820
  $post['format'] = 'link';
821
+ $linkurl = (string) $tpost->url;
822
+ $linktext = (string) $tpost->title;
823
+ $post['post_content'] = "<a href='$linkurl'>$linktext</a>";
824
+ if ( ! empty( $tpost->description ) )
825
+ $post['post_content'] .= '<div class="link_description">' . (string) $tpost->description . '</div>';
826
+ $post['post_title'] = (string) $tpost->title;
827
  break;
828
+ case 'chat':
829
  $post['format'] = 'chat';
830
+ $post['post_title'] = (string) $tpost->title;
831
+ $post['post_content'] = (string) $tpost->body;
832
  break;
833
  case 'audio':
834
  $post['format'] = 'audio';
835
+ $post['media']['filename'] = basename( (string) $tpost->audio_url );
836
+ // If no .mp3 extension, add one so that sideloading works.
837
+ if ( ! preg_match( '/\.mp3$/', $post['media']['filename'] ) )
838
+ $post['media']['filename'] .= '.mp3';
839
+ $post['media']['audio'] = (string) $tpost->audio_url .'?plead=please-dont-download-this-or-our-lawyers-wont-let-us-host-audio';
840
+ $post['post_content'] = (string) $tpost->player . "\n" . (string) $tpost->caption;
841
  break;
842
  case 'video':
843
  $post['format'] = 'video';
844
  $post['post_content'] = '';
845
+
846
+ $video = array_shift( $tpost->player );
847
+
848
+ if ( false !== strpos( (string) $video->embed_code, 'embed' ) ) {
849
+ if ( preg_match_all('/<embed (.+?)>/', (string) $video->embed_code, $matches) ) {
 
 
 
 
 
 
850
  foreach ($matches[1] as $match) {
851
+ foreach ( wp_kses_hair( $match, array( 'http' ) ) as $attr )
852
+ $embed[ $attr['name'] ] = $attr['value'];
853
  }
854
+
855
  // special case for weird youtube vids
856
+ $embed['src'] = preg_replace( '|http://www.youtube.com/v/([a-zA-Z0-9_]+).*|i', 'http://www.youtube.com/watch?v=$1', $embed['src'] );
857
+
858
  // TODO find other special cases, since tumblr is full of them
 
859
  $post['post_content'] = $embed['src'];
860
  }
861
+
862
  // Sometimes, video-source contains iframe markup.
863
+ if ( preg_match( '/<iframe/', $video->embed_code ) ) {
864
+ $embed['src'] = preg_replace( '|<iframe.*src="http://www.youtube.com/embed/([a-zA-Z0-9_\-]+)\??.*".*</iframe>|', 'http://www.youtube.com/watch?v=$1', $video->embed_code );
865
  $post['post_content'] = $embed['src'];
866
  }
867
+ } elseif ( preg_match( '/<iframe.*vimeo/', $video->embed_code ) ) {
868
+ $embed['src'] = preg_replace( '|<iframe.*src="(http://player.vimeo.com/video/([a-zA-Z0-9_\-]+))\??.*".*</iframe>.*|', 'http://vimeo.com/$2', $video->embed_code );
869
+ $post['post_content'] = $embed['src'];
870
  } else {
871
+ // @todo: See if the video source is going to be oEmbed'able before adding the flash player
872
+ $post['post_content'] .= $video->embed_code;
 
873
  }
874
+
875
+ $post['post_content'] .= "\n" . (string) $tpost->caption;
876
  break;
877
  case 'answer':
878
+ // TODO: Include asking_name and asking_url values?
879
+ $post['post_title'] = (string) $tpost->question;
880
+ $post['post_content'] = (string) $tpost->answer;
881
  break;
882
  case 'regular':
883
+ case 'text':
884
  default:
885
+ $post['post_title'] = (string) $tpost->title;
886
+ $post['post_content'] = (string) $tpost->body;
887
  break;
888
  }
889
  $posts[] = $post;
964
  return $maybe_empty;
965
  }
966
 
967
+
968
+ /**
969
+ * OAuth Signature creation
970
+ */
971
+ function oauth_signature($secret, $method, $url, $params = array()) {
972
+ uksort($params, 'strcmp');
973
+ foreach ($params as $k => $v) {
974
+ $pairs[] = $this->_urlencode_rfc3986($k).'='.$this->_urlencode_rfc3986($v);
975
+ }
976
+ $concatenatedParams = implode('&', $pairs);
977
+ $baseString= $method."&". $this->_urlencode_rfc3986($url)."&".$this->_urlencode_rfc3986($concatenatedParams);
978
+ if (!is_array($secret)) {
979
+ $secret[0] = $secret;
980
+ $secret[1] = '';
981
+ }
982
+ $secret = $this->_urlencode_rfc3986($secret[0])."&".$this->_urlencode_rfc3986($secret[1]);
983
+ $oauth_signature = base64_encode(hash_hmac('sha1', $baseString, $secret, TRUE));
984
+ return $oauth_signature;
985
+ }
986
+
987
+ /**
988
+ * Helper function for OAuth Signature creation
989
+ */
990
+ function _urlencode_rfc3986($input)
991
+ {
992
+ if (is_array($input)) {
993
+ return array_map(array($this, '_urlencode_rfc3986'), $input);
994
+ } else if (is_scalar($input)) {
995
+ return str_replace(array('+', '%7E'), array(' ', '~'), rawurlencode($input));
996
+ } else {
997
+ return '';
998
+ }
999
+ }
1000
+
1001
+ /**
1002
+ * Do a GET request with the access tokens
1003
+ */
1004
+ function oauth_get_request($url) {
1005
+ if ( empty( $this->access_tokens ) )
1006
+ return false;
1007
+
1008
+ $params = array('oauth_consumer_key' => $this->get_consumer_key(),
1009
+ "oauth_nonce" => time(),
1010
+ "oauth_timestamp" => time(),
1011
+ "oauth_token" => $this->access_tokens['oauth_token'],
1012
+ "oauth_signature_method" => "HMAC-SHA1",
1013
+ "oauth_version" => "1.0",
1014
+ );
1015
+
1016
+ $params['oauth_signature'] = $this->oauth_signature(array($this->secretkey,$this->access_tokens['oauth_token_secret']), 'GET', $url, $params);
1017
+
1018
+ $url = add_query_arg( array_map('urlencode', $params), $url);
1019
+
1020
+ $response = wp_remote_get( $url );
1021
+
1022
+ if ( is_wp_error( $response ) || 200 != wp_remote_retrieve_response_code( $response ) ) {
1023
+ return false;
1024
+ } else {
1025
+ $body = wp_remote_retrieve_body( $response );
1026
+ return json_decode($body);
1027
+ }
1028
+ }
1029
+
1030
+
1031
  }
1032
  }