Tumblr_Import

The Tumblr Importer Tumblr Import class.

Defined (1)

The class is defined in the following location(s).

/tumblr-importer.php  
  1. class Tumblr_Import extends WP_Importer_Cron { 
  2.  
  3. /** 
  4. * Constructor 
  5. */ 
  6. function __construct() { 
  7. add_action( 'tumblr_importer_metadata', array( $this, 'tumblr_importer_metadata' ) ); 
  8. add_filter( 'tumblr_importer_format_post', array( $this, 'filter_format_post' ) ); 
  9. add_filter( 'tumblr_importer_get_consumer_key', array( $this, 'get_consumer_key' ) ); 
  10. add_filter( 'wp_insert_post_empty_content', array( $this, 'filter_allow_empty_content' ), 10, 2 ); 
  11. parent::__construct(); 
  12.  
  13. // Figures out what to do, then does it. 
  14. function start() { 
  15. if ( isset($_POST['restart']) ) 
  16. $this->restart(); 
  17.  
  18. if ( !isset($this->error) ) $this->error = null; 
  19.  
  20. @ $this->consumerkey = defined ('TUMBLR_CONSUMER_KEY') ? TUMBLR_CONSUMER_KEY : ( !empty($_POST['consumerkey']) ? $_POST['consumerkey'] : $this->consumerkey ); 
  21. @ $this->secretkey = defined ('TUMBLR_SECRET_KEY') ? TUMBLR_SECRET_KEY : ( !empty($_POST['secretkey']) ? $_POST['secretkey'] : $this->secretkey ); 
  22.  
  23. // if we have access tokens, verify that they work 
  24. if ( !empty( $this->access_tokens ) ) { 
  25. // TODO 
  26. } else if ( isset( $_GET['oauth_verifier'] ) ) { 
  27. $this->check_permissions(); 
  28. } else if ( !empty( $this->consumerkey ) && !empty( $this->secretkey ) ) { 
  29. $this->check_credentials(); 
  30. if ( isset( $_POST['blogurl'] ) ) { 
  31. $this->start_blog_import(); 
  32. if ( isset( $this->blogs ) ) { 
  33. $this->show_blogs($this->error); 
  34. } else { 
  35. $this->greet($this->error); 
  36.  
  37. unset ($this->error); 
  38.  
  39. if ( !isset($_POST['restart']) ) $saved = $this->save_vars(); 
  40.  
  41. if ( $saved && !isset($_GET['noheader']) ) { 
  42. ?> 
  43. <p><?php _e('We have saved some information about your Tumblr account in your WordPress database. Clearing this information will allow you to start over. Restarting will not affect any posts you have already imported. If you attempt to re-import a blog, duplicate posts will be skipped.', 'tumblr-importer'); ?></p> 
  44. <p><?php _e('Note: This will stop any import currently in progress.', 'tumblr-importer'); ?></p> 
  45. <form method='post' action='?import=tumblr&noheader=true'> 
  46. <p class='submit' style='text-align:left;'> 
  47. <input type='submit' class='button' value='<?php esc_attr_e('Clear account information', 'tumblr-importer'); ?>' name='restart' /> 
  48. </p> 
  49. </form> 
  50. <?php 
  51.  
  52. function greet($error=null) { 
  53.  
  54. if ( !empty( $error ) ) 
  55. echo "<div class='error'><p>{$error}</p></div>"; 
  56. ?> 
  57.  
  58. <div class='wrap'><?php echo screen_icon(); ?> 
  59. <h2><?php _e('Import Tumblr', 'tumblr-importer'); ?></h2> 
  60. <?php if ( empty($this->request_tokens) ) { ?> 
  61. <p><?php _e('Howdy! This importer allows you to import posts from your Tumblr account into your WordPress site.', 'tumblr-importer'); ?></p> 
  62. <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> 
  63.  
  64. <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> 
  65. <ol> 
  66. <li><?php _e('Click the large green "Register Application" button.', 'tumblr-importer'); ?></li> 
  67. <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> 
  68. <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> 
  69. <li><?php _e('Note: It is important that you put in that URL <em>exactly as given</em>.', 'tumblr-importer'); ?></li> 
  70. </ol> 
  71.  
  72. <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> 
  73.  
  74. <form action='?import=tumblr' method='post'> 
  75. <table class="form-table"> 
  76. <tr> 
  77. <th scope="row"><label for='consumerkey'><?php _e('OAuth Consumer Key:', 'tumblr-importer'); ?></label></label></th> 
  78. <td><input type='text' class="regular-text" name='consumerkey' value='<?php if (isset($this->consumerkey)) echo esc_attr($this->consumerkey); ?>' /></td> 
  79. </tr> 
  80. <tr> 
  81. <th scope="row"><label for='secretkey'><?php _e('Secret Key:', 'tumblr-importer'); ?></label></label></th> 
  82. <td><input type='text' class="regular-text" name='secretkey' value='<?php if (isset($this->secretkey)) echo esc_attr($this->secretkey); ?>' /></td> 
  83. </tr> 
  84. </table> 
  85. <p class='submit'> 
  86. <input type='submit' class='button' value="<?php _e('Connect to Tumblr', 'tumblr-importer'); ?>" /> 
  87. </p> 
  88. </form> 
  89. </div> 
  90. <?php } else { 
  91. ?> 
  92. <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> 
  93. <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> 
  94.  
  95. <p><a href="<?php echo $this->authorize_url; ?>"><?php _e('Authorize the Application', 'tumblr-importer'); ?></a></p> 
  96. <?php 
  97.  
  98. function check_credentials() {  
  99. if ( !( $response = $this->oauth_get_request_token() ) ) 
  100. return; 
  101.  
  102. if ( is_wp_error( $response ) || 200 != wp_remote_retrieve_response_code( $response ) ) { 
  103. $this->error = __('Tumblr returned an error: ', 'tumblr-importer') . wp_remote_retrieve_response_code( $response ) .' '. wp_remote_retrieve_body( $response ); 
  104. return; 
  105. // parse the body 
  106. $this->request_tokens = array(); 
  107. wp_parse_str( wp_remote_retrieve_body( $response ), $this->request_tokens); 
  108. $this->authorize_url = add_query_arg(array( 
  109. 'oauth_token' => $this->request_tokens ['oauth_token'],  
  110. ), 'http://www.tumblr.com/oauth/authorize'); 
  111.  
  112. return; 
  113.  
  114. function check_permissions() { 
  115. $verifier = $_GET['oauth_verifier']; 
  116. $token = $_GET['oauth_token']; 
  117.  
  118. // get the access_tokens 
  119. $url = 'http://www.tumblr.com/oauth/access_token'; 
  120.  
  121. $params = array('oauth_consumer_key' => $this->consumerkey,  
  122. "oauth_nonce" => time().rand(),  
  123. "oauth_timestamp" => time(),  
  124. "oauth_token" => $this->request_tokens['oauth_token'],  
  125. "oauth_signature_method" => "HMAC-SHA1",  
  126. "oauth_verifier" => $verifier,  
  127. "oauth_version" => "1.0",  
  128. ); 
  129.  
  130. $params['oauth_signature'] = $this->oauth_signature(array($this->secretkey, $this->request_tokens['oauth_token_secret']), 'GET', $url, $params); 
  131.  
  132. $url = add_query_arg( array_map('urlencode', $params), $url); 
  133. $response = wp_remote_get( $url );  
  134. unset($this->request_tokens);  
  135. if ( is_wp_error( $response ) || 200 != wp_remote_retrieve_response_code( $response ) ) { 
  136. $this->error = __('Tumblr returned an error: ', 'tumblr-importer') . wp_remote_retrieve_response_code( $response ) .' '. wp_remote_retrieve_body( $response ); 
  137. return; 
  138. } else { 
  139. $this->access_tokens = array(); 
  140. wp_parse_str( wp_remote_retrieve_body( $response ), $this->access_tokens); 
  141.  
  142. // try to get the list of blogs on the account 
  143.  
  144. $blogs = $this->get_blogs(); 
  145. if ( is_wp_error ($blogs) ) { 
  146. $this->error = $blogs->get_error_message(); 
  147. } else { 
  148. $this->blogs = $blogs; 
  149. return;  
  150.  
  151. function show_blogs($error=null) { 
  152.  
  153. if ( !empty( $error ) ) 
  154. echo "<div class='error'><p>{$error}</p></div>"; 
  155.  
  156. $authors = get_users( array('who' => 'authors') ); 
  157. ?> 
  158. <div class='wrap'><?php echo screen_icon(); ?> 
  159. <h2><?php _e('Import Tumblr', 'tumblr-importer'); ?></h2> 
  160. <p><?php _e('Please select the Tumblr blog you would like to import into your WordPress site and then click on the "Import this Blog" button to continue.'); ?></p> 
  161. <p><?php _e('If your import gets stuck for a long time or you would like to import from a different Tumblr account instead then click on the "Clear account information" button below to reset the importer.', 'tumblr-importer'); ?></p> 
  162. <?php if ( 1 < count( $authors ) ) : ?> 
  163. <p><?php _e('As Tumblr does not expose the "author", even from multi-author blogs you will need to select which WordPress user will be listed as the author of the imported posts.', 'tumblr-importer'); ?></p> 
  164. <?php endif; ?> 
  165. <table class="widefat" cellspacing="0"><thead> 
  166. <tr> 
  167. <th><?php _e('Tumblr Blog', 'tumblr-importer'); ?></th> 
  168. <th><?php _e('URL', 'tumblr-importer'); ?></th> 
  169. <th><?php _e('Posts Imported', 'tumblr-importer'); ?></th> 
  170. <th><?php _e('Drafts Imported', 'tumblr-importer'); ?></th> 
  171. <!--<th><?php _e('Queued Imported', 'tumblr-importer'); ?></th>--> 
  172. <th><?php _e('Pages Imported', 'tumblr-importer'); ?></th> 
  173. <th><?php _e('Author', 'tumblr-importer'); ?></th> 
  174. <th><?php _e('Action/Status', 'tumblr-importer'); ?></th> 
  175. </tr></thead> 
  176. <tbody> 
  177. <?php 
  178. $style = ''; 
  179. $custom_domains = false; 
  180. foreach ($this->blogs as $blog) { 
  181. $url = $blog['url']; 
  182. $style = ( 'alternate' == $style ) ? '' : 'alternate'; 
  183. if ( !isset( $this->blog[$url] ) ) { 
  184. $this->blog[$url]['posts_complete'] = 0; 
  185. $this->blog[$url]['drafts_complete'] = 0; 
  186. $this->blog[$url]['queued_complete'] = 0; 
  187. $this->blog[$url]['pages_complete'] = 0; 
  188. $this->blog[$url]['total_posts'] = $blog['posts'];  
  189. $this->blog[$url]['total_drafts'] = $blog['drafts']; 
  190. $this->blog[$url]['total_queued'] = $blog['queued']; 
  191. $this->blog[$url]['name'] = $blog['name']; 
  192.  
  193. if ( empty( $this->blog[$url]['progress'] ) ) { 
  194. $submit = "<input type='submit' value='". __('Import this blog', 'tumblr-importer') ."' />"; 
  195. } else if ( $this->blog[$url]['progress'] == 'finish' ) { 
  196. $submit = '<img src="' . admin_url( 'images/yes.png' ) . '" style="vertical-align: top; padding: 0 4px;" alt="' . __( 'Finished!', 'tumblr-importer' ) . '" title="' . __( 'Finished!', 'tumblr-importer' ) . '" /><span>' . __( 'Finished!', 'tumblr-importer' ) . '</span>'; 
  197. } else { 
  198. $submit = '<img src="' . admin_url( 'images/loading.gif' ) . '" style="vertical-align: top; padding: 0 4px;" alt="' . __( 'In Progress', 'tumblr-importer' ) . '" title="' . __( 'In Progress', 'tumblr-importer' ) . '" /><span>' . __( 'In Progress', 'tumblr-importer' ) . '</span>'; 
  199. // Just a little js page reload to show progress if we're in the in-progress phase of the import. 
  200. $submit .= "<script type='text/javascript'>setTimeout( 'window.location.href = window.location.href', 15000);</script>"; 
  201.  
  202. // Check to see if this url is a custom domain. The API doesn't play nicely with these 
  203. // (intermittently returns 408 status), so make the user disable the custom domain 
  204. // before importing. 
  205. if ( !preg_match( '|tumblr.com/$|', $url ) ) { 
  206. $submit = '<nobr><img src="' . admin_url( 'images/no.png' ) . '" style="vertical-align:top; padding: 0 4px;" alt="' . __( 'Tumblr Blogs with Custom Domains activated cannot be imported, please disable the custom domain first.', 'tumblr-importer' ) . '" title="' . __( 'Tumblr Blogs with Custom Domains activated cannot be imported, please disable the custom domain first.', 'tumblr-importer' ) . '" /><span style="cursor: pointer;" title="' . __( 'Tumblr Blogs with Custom Domains activated cannot be imported, please disable the custom domain first.' ) . '">' . __( 'Custom Domain', 'tumblr-importer' ) . '</nobr></span>'; 
  207. $custom_domains = true; 
  208.  
  209. // Build an author selector / static name depending on number 
  210. if ( 1 == count( $authors ) ) { 
  211. $author_selection = "<input type='hidden' value='{$authors[0]->ID}' name='post_author' />{$authors[0]->display_name}"; 
  212. } else { 
  213. $args = array('who' => 'authors', 'name' => 'post_author', 'echo' => false ); 
  214. if ( isset( $this->blog[$url]['post_author'] ) ) 
  215. $args['selected'] = $this->blog[$url]['post_author']; 
  216. $author_selection = wp_dropdown_users( $args ); 
  217. ?> 
  218. <tr class="<?php echo $style; ?>"> 
  219. <form action='?import=tumblr' method='post'> 
  220. <?php wp_nonce_field( 'tumblr-import' ); ?> 
  221. <input type='hidden' name='blogurl' value='<?php echo esc_attr($blog['url']); ?>' /> 
  222.  
  223. <td><?php echo esc_html($blog['title']); ?></td> 
  224. <td><?php echo esc_html($blog['url']); ?></td> 
  225. <td><?php echo $this->blog[$url]['posts_complete'] . ' / ' . $this->blog[$url]['total_posts']; ?></td> 
  226. <td><?php echo $this->blog[$url]['drafts_complete'] . ' / ' . $this->blog[$url]['total_drafts']; ?></td> 
  227. <!--<td><?php echo $this->blog[$url]['queued_complete']; ?></td>--> 
  228. <td><?php echo $this->blog[$url]['pages_complete']; ?></td> 
  229. <td><?php echo $author_selection ?></td> 
  230. <td><?php echo $submit; ?></td> 
  231. </form> 
  232. </tr> 
  233. <?php 
  234. ?> 
  235. </tbody> 
  236. </table> 
  237. <?php if ( $custom_domains ) : ?> 
  238. <p><strong> 
  239. <?php _e( 'As one or more of your Tumblr blogs has a Custom Domain mapped to it. If you would like to import one of these sites you will need to temporarily remove the custom domain mapping and clear the account information from the importer to import. Once the import is completed you can re-enable the custom domain for your site.' ); ?> 
  240. </strong></p> 
  241. <?php endif; ?> 
  242. <p><?php _e("Importing your Tumblr blog can take a while so the importing process happens in the background and you may not see immediate results here. Come back to this page later to check on the importer's progress.", 'tumblr-importer'); ?></p> 
  243. </div> 
  244. <?php 
  245.  
  246. function start_blog_import() { 
  247. check_admin_referer( 'tumblr-import' ); 
  248. $url = $_POST['blogurl']; 
  249.  
  250. if ( !isset( $this->blog[$url] ) ) { 
  251. $this->error = __('The specified blog cannot be found.', 'tumblr-importer'); 
  252. return; 
  253. }  
  254.  
  255. if ( !empty($this->blog[$url]['progress']) ) { 
  256. $this->error = __('This blog is currently being imported.', 'tumblr-importer'); 
  257. return; 
  258.  
  259. $this->blog[$url]['progress'] = 'start'; 
  260. $this->blog[$url]['post_author'] = (int) $_POST['post_author']; 
  261.  
  262. $this->schedule_import_job( 'do_blog_import', array($url) ); 
  263.  
  264. function restart() { 
  265. delete_option(get_class($this)); 
  266. wp_redirect('?import=tumblr'); 
  267.  
  268. function do_blog_import($url) { 
  269.  
  270. // default to the done state 
  271. $done = true; 
  272.  
  273. $this->error=null; 
  274. if ( !empty( $this->blog[$url]['progress'] ) ) { 
  275. $done = false; 
  276. do { 
  277. switch ($this->blog[$url]['progress']) { 
  278. case 'start': 
  279. case 'posts': 
  280. $this->do_posts_import($url); 
  281. break; 
  282. case 'drafts': 
  283. $this->do_drafts_import($url); 
  284. break; 
  285. case 'queued': 
  286. // TODO Tumblr's API is broken for queued posts 
  287. $this->blog[$url]['progress'] = 'pages'; 
  288. //$this->do_queued_import($url); 
  289. break; 
  290. case 'pages': 
  291. // TODO Tumblr's new API has no way to retrieve pages that I can find 
  292. $this->blog[$url]['progress'] = 'finish'; 
  293. //$this->do_pages_import($url); 
  294. break; 
  295. case 'finish': 
  296. default: 
  297. $done = true; 
  298. break; 
  299. }  
  300. $this->save_vars(); 
  301. } while ( empty($this->error) && !$done && $this->have_time() ); 
  302. }  
  303.  
  304. return $done; 
  305.  
  306. function do_posts_import($url) { 
  307. $start = $this->blog[$url]['posts_complete']; 
  308. $total = $this->blog[$url]['total_posts']; 
  309.  
  310. // check for posts completion 
  311. if ( $start >= $total ) { 
  312. $this->blog[$url]['progress'] = 'drafts'; 
  313. return; 
  314.  
  315. // get the already imported posts to prevent dupes 
  316. $dupes = $this->get_imported_posts( 'tumblr', $this->blog[$url]['name'] ); 
  317.  
  318. if ($this->blog[$url]['posts_complete'] + TUMBLR_MAX_IMPORT > $total) $count = $total - $start; 
  319. else $count = TUMBLR_MAX_IMPORT; 
  320.  
  321. $imported_posts = $this->fetch_posts($url, $start, $count, $this->email, $this->password ); 
  322.  
  323. if ( false === $imported_posts ) { 
  324. $this->error = __('Problem communicating with Tumblr, retrying later', 'tumblr-importer'); 
  325. return; 
  326.  
  327. if ( is_array($imported_posts) && !empty($imported_posts) ) { 
  328. reset($imported_posts); 
  329. $post = current($imported_posts); 
  330. do { 
  331. // skip dupes 
  332. if ( !empty( $dupes[$post['tumblr_url']] ) ) { 
  333. $this->blog[$url]['posts_complete']++; 
  334. $this->save_vars(); 
  335. continue; 
  336.  
  337. if ( isset( $post['private'] ) ) $post['post_status'] = 'private'; 
  338. else $post['post_status']='publish'; 
  339.  
  340. $post['post_author'] = $this->blog[$url]['post_author']; 
  341.  
  342. do_action( 'tumblr_importing_post', $post ); 
  343. $id = wp_insert_post( $post ); 
  344.  
  345. if ( !is_wp_error( $id ) ) { 
  346. $post['ID'] = $id; // Allows for the media importing to wp_update_post() 
  347. if ( isset( $post['format'] ) ) set_post_format($id, $post['format']); 
  348.  
  349. // @todo: Add basename of the permalink as a 404 redirect handler for when a custom domain has been brought accross 
  350. add_post_meta( $id, 'tumblr_'.$this->blog[$url]['name'].'_permalink', $post['tumblr_url'] ); 
  351. add_post_meta( $id, 'tumblr_'.$this->blog[$url]['name'].'_id', $post['tumblr_id'] ); 
  352.  
  353. $import_result = $this->handle_sideload($post); 
  354.  
  355. // Handle failed imports.. If empty content and failed to import media.. 
  356. if ( is_wp_error($import_result) ) { 
  357. if ( empty($post['post_content']) ) { 
  358. wp_delete_post($id, true); 
  359.  
  360. $this->blog[$url]['posts_complete']++; 
  361. $this->save_vars(); 
  362.  
  363. } while ( false != ($post = next($imported_posts) ) && $this->have_time() ); 
  364.  
  365. function get_draft_post_type( $post_type ) { 
  366. return 'draft'; 
  367.  
  368. function do_drafts_import($url) { 
  369. $start = $this->blog[$url]['drafts_complete']; 
  370. $total = $this->blog[$url]['total_drafts']; 
  371.  
  372. // check for posts completion 
  373. if ( $start >= $total ) { 
  374. $this->blog[$url]['progress'] = 'queued'; 
  375. return; 
  376.  
  377. // get the already imported posts to prevent dupes 
  378. $dupes = $this->get_imported_posts( 'tumblr', $this->blog[$url]['name'] ); 
  379.  
  380. if ($this->blog[$url]['posts_complete'] + TUMBLR_MAX_IMPORT > $total) $count = $total - $start; 
  381. else $count = TUMBLR_MAX_IMPORT; 
  382.  
  383. add_filter( 'tumblr_post_type', array( $this, 'get_draft_post_type' ) ); 
  384. $imported_posts = $this->fetch_posts($url, $start, $count, $this->email, $this->password, 'draft' ); 
  385.  
  386. if ( empty($imported_posts) ) { 
  387. $this->error = __('Problem communicating with Tumblr, retrying later', 'tumblr-importer'); 
  388. return; 
  389.  
  390. if ( is_array($imported_posts) && !empty($imported_posts) ) { 
  391. reset($imported_posts); 
  392. $post = current($imported_posts); 
  393. do { 
  394. // skip dupes 
  395. if ( !empty( $dupes[$post['tumblr_url']] ) ) { 
  396. $this->blog[$url]['drafts_complete']++; 
  397. $this->save_vars(); 
  398. continue; 
  399.  
  400. $post['post_status'] = 'draft'; 
  401. $post['post_author'] = $this->blog[$url]['post_author']; 
  402.  
  403. do_action( 'tumblr_importing_post', $post ); 
  404. $id = wp_insert_post( $post ); 
  405. if ( !is_wp_error( $id ) ) { 
  406. $post['ID'] = $id; 
  407. if ( isset( $post['format'] ) ) set_post_format($id, $post['format']); 
  408.  
  409. add_post_meta( $id, 'tumblr_'.$this->blog[$url]['name'].'_permalink', $post['tumblr_url'] ); 
  410. add_post_meta( $id, 'tumblr_'.$this->blog[$url]['name'].'_id', $post['tumblr_id'] ); 
  411.  
  412. $this->handle_sideload($post); 
  413.  
  414. $this->blog[$url]['drafts_complete']++; 
  415. $this->save_vars(); 
  416. } while ( false != ($post = next($imported_posts) ) && $this->have_time() ); 
  417.  
  418. function do_pages_import($url) { 
  419. $start = $this->blog[$url]['pages_complete']; 
  420.  
  421. // get the already imported posts to prevent dupes 
  422. $dupes = $this->get_imported_posts( 'tumblr', $this->blog[$url]['name'] ); 
  423.  
  424. $imported_pages = $this->fetch_pages($url, $this->email, $this->password ); 
  425.  
  426. if ( false === $imported_pages ) { 
  427. $this->error = __('Problem communicating with Tumblr, retrying later', 'tumblr-importer'); 
  428. return; 
  429.  
  430. if ( is_array($imported_pages) && !empty($imported_pages) ) { 
  431. reset($imported_pages); 
  432. $post = current($imported_pages); 
  433. do { 
  434. // skip dupes 
  435. if ( !empty( $dupes[$post['tumblr_url']] ) ) { 
  436. continue; 
  437.  
  438. $post['post_type'] = 'page'; 
  439. $post['post_status'] = 'publish'; 
  440. $post['post_author'] = $this->blog[$url]['post_author']; 
  441.  
  442. $id = wp_insert_post( $post ); 
  443. if ( !is_wp_error( $id ) ) { 
  444. add_post_meta( $id, 'tumblr_'.$this->blog[$url]['name'].'_permalink', $post['tumblr_url'] ); 
  445. $post['ID'] = $id; 
  446. $this->handle_sideload($post); 
  447.  
  448. $this->blog[$url]['pages_complete']++; 
  449. $this->save_vars(); 
  450. } while ( false != ($post = next($imported_pages) ) ); 
  451. }  
  452. $this->blog[$url]['progress'] = 'finish'; 
  453.  
  454. function handle_sideload_import($post, $source, $description = '', $filename = false) { 
  455. // Make a HEAD request to get the filename: 
  456. if ( empty($filename) ) { 
  457. $head = wp_remote_request( $source, array('method' => 'HEAD') ); 
  458. if ( !empty($head['headers']['location']) ) { 
  459. $source = $head['headers']['location']; 
  460. $filename = preg_replace('!\?.*!', '', basename($source) ); // Strip off the Query vars 
  461.  
  462. // still empty? Darned inconsistent tumblr... 
  463. if ( empty($filename) ) { 
  464. $path = parse_url($source, PHP_URL_PATH); 
  465. $filename = basename($path); 
  466. // Download file to temp location 
  467. $tmp = download_url( $source ); 
  468. if ( is_wp_error($tmp) ) 
  469. return $tmp; 
  470.  
  471. $file_array['name'] = !empty($filename) ? $filename : basename($tmp); 
  472. $file_array['tmp_name'] = $tmp; 
  473. // do the validation and storage stuff 
  474. $id = media_handle_sideload( $file_array, $post['ID'], $description, array( 'post_excerpt' => $description ) ); 
  475.  
  476. if ( $id && ! is_wp_error($id) ) { 
  477. // Update the date/time on the attachment to that of the Tumblr post. 
  478. $attachment = get_post($id, ARRAY_A); 
  479. foreach ( array('post_date', 'post_date_gmt', 'post_modified', 'post_modified_gmt') as $field ) { 
  480. if ( isset($post[ $field]) ) 
  481. $attachment[ $field ] = $post[ $field ]; 
  482. wp_update_post($attachment); 
  483.  
  484. // If error storing permanently, unlink 
  485. if ( is_wp_error($id) ) 
  486. @unlink($file_array['tmp_name']); 
  487. return $id; 
  488.  
  489. function handle_sideload($post) { 
  490.  
  491. if ( empty( $post['format'] ) ) 
  492. return; // Nothing to import. 
  493.  
  494. switch ( $post['format'] ) { 
  495. case 'gallery': 
  496. if ( !empty( $post['gallery'] ) ) { 
  497. foreach ( $post['gallery'] as $i => $photo ) { 
  498. $id = $this->handle_sideload_import( $post, (string)$photo['src'], (string)$photo['caption']); 
  499. if ( is_wp_error($id) ) 
  500. return $id; 
  501. $post['post_content'] = "[gallery]\n" . $post['post_content']; 
  502. $post = apply_filters( 'tumblr_importer_format_post', $post ); 
  503. do_action( 'tumblr_importer_metadata', $post ); 
  504. wp_update_post($post); 
  505. break; // If we processed a gallery, break, otherwise let it fall through to the Image handler 
  506.  
  507. case 'image': 
  508. if ( isset( $post['media']['src'] ) ) { 
  509. $id = $this->handle_sideload_import( $post, (string)$post['media']['src'], (string)$post['post_title']); 
  510. if ( is_wp_error($id) ) 
  511. return $id; 
  512.  
  513. $link = !empty($post['media']['link']) ? $post['media']['link'] : null; 
  514. // image_send_to_editor has a filter to wrap in a shortcode. 
  515. $post_content = $post['post_content']; 
  516. $post['post_content'] = get_image_send_to_editor($id, (string)$post['post_title'], (string)$post['post_title'], 'none', $link, true, 'full' ); 
  517. $post['post_content'] .= $post_content; 
  518. $post['meta']['attribution'] = $link; 
  519. $post = apply_filters( 'tumblr_importer_format_post', $post ); 
  520. do_action( 'tumblr_importer_metadata', $post ); 
  521. //$post['post_content'] .= "\n" . $post['post_content']; // the [caption] shortcode doesn't allow HTML, but this might have some extra markup 
  522. wp_update_post($post); 
  523.  
  524. break; 
  525.  
  526. case 'audio': 
  527. // Handle Tumblr Hosted Audio 
  528. if ( isset( $post['media']['audio'] ) ) { 
  529. $id = $this->handle_sideload_import( $post, (string)$post['media']['audio'], $post['post_title'], (string)$post['media']['filename'] ); 
  530. if ( is_wp_error($id) ) 
  531. return $id; 
  532. $post['post_content'] = wp_get_attachment_link($id) . "\n" . $post['post_content']; 
  533. } else { 
  534. // Try to work out a "source" link to display Tumblr-style. 
  535. preg_match( '/(http[^ "<>\']+)/', $post['post_content'], $matches ); 
  536. if ( isset( $matches[1] ) ) { 
  537. $url_parts = parse_url( $matches[1] ); 
  538. $post['meta']['attribution'] = $url_parts['scheme'] . "://" . $url_parts['host'] . "/"; 
  539. $post = apply_filters( 'tumblr_importer_format_post', $post ); 
  540. do_action( 'tumblr_importer_metadata', $post ); 
  541. wp_update_post($post); 
  542. break; 
  543.  
  544. case 'video': 
  545. // Handle Tumblr hosted video 
  546. if ( isset( $post['media']['video'] ) ) { 
  547. $id = $this->handle_sideload_import( $post, (string)$post['media']['video'], $post['post_title'], (string)$post['media']['filename'] ); 
  548. if ( is_wp_error($id) ) 
  549. return $id; 
  550.  
  551. // @TODO: Check/change this to embed the imported video.  
  552. $link = wp_get_attachment_link($id) . "\n" . $post['post_content']; 
  553. $post['post_content'] = $link; 
  554. $post['meta']['attribution'] = $link; 
  555. } else { 
  556. // Try to work out a "source" link to mimic Tumblr's post formatting. 
  557. preg_match( '/(http[^ "<>\']+)/', $post['post_content'], $matches ); 
  558. if ( isset( $matches[1] ) ) { 
  559. $url_parts = parse_url( $matches[1] ); 
  560. $post['meta']['attribution'] = $url_parts['scheme'] . "://" . $url_parts['host'] . "/"; 
  561. $post = apply_filters( 'tumblr_importer_format_post', $post ); 
  562. do_action( 'tumblr_importer_metadata', $post ); 
  563. wp_update_post($post); 
  564.  
  565. // Else, Check to see if the url embedded is handled by oEmbed (or not) 
  566. break; 
  567.  
  568. return true; // all processed 
  569.  
  570.  
  571. /**  
  572. * Get a request token from the OAuth endpoint (also serves as a test) 
  573. */ 
  574. function oauth_get_request_token() { 
  575. if ( empty($this->consumerkey) || empty ($this->secretkey) ) 
  576. return false; 
  577.  
  578. $url = 'http://www.tumblr.com/oauth/request_token'; 
  579.  
  580. $params = array('oauth_callback' => self_admin_url('admin.php?import=tumblr'),  
  581. 'oauth_consumer_key' => $this->consumerkey,  
  582. "oauth_version" => "1.0",  
  583. "oauth_nonce" => time(),  
  584. "oauth_timestamp" => time(),  
  585. "oauth_signature_method" => "HMAC-SHA1",  
  586. ); 
  587.  
  588. $params['oauth_signature'] = $this->oauth_signature(array($this->secretkey, ''), 'POST', $url, $params); 
  589.  
  590. $response = wp_remote_post( $url, array('body' => $params)); 
  591.  
  592. return $response; 
  593.  
  594. /** 
  595. * Fetch a list of blogs for a user 
  596. * @param $email 
  597. * @param $password 
  598. * @returns array of blog info or a WP_Error 
  599. */ 
  600. function get_blogs() { 
  601. $url = 'http://api.tumblr.com/v2/user/info'; 
  602. $response = $this->oauth_get_request($url); 
  603.  
  604. switch ( $response->meta->status ) { 
  605. case 403: // Bad Username / Password 
  606. do_action( 'tumblr_importer_handle_error', 'get_blogs_403' ); 
  607. 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' ) ); 
  608. case 200: // OK 
  609. break; 
  610. default: 
  611. $_error = sprintf( __( 'Tumblr replied with an error: %s', 'tumblr-importer' ), $response->meta->msg ); 
  612. do_action( 'tumblr_importer_handle_error', 'response_' . $response->meta->status ); 
  613. return new WP_Error('tumblr_error', $_error ); 
  614.  
  615. $blogs = array(); 
  616. foreach ( $response->response->user->blogs as $tblog ) { 
  617. $blog = array(); 
  618. $blog['title'] = (string) $tblog->title; 
  619. $blog['posts'] = (int) $tblog->posts; 
  620. $blog['drafts'] = (int) $tblog->drafts; 
  621. $blog['queued'] = (int) $tblog->queue; 
  622. $blog['avatar'] = ''; 
  623. $blog['url'] = (string) $tblog->url; 
  624. $blog['name'] = (string) $tblog->name; 
  625.  
  626. $blogs[] = $blog; 
  627. $this->blogs = $blogs; 
  628. return $this->blogs; 
  629.  
  630. function get_consumer_key() { 
  631. return $this->consumerkey; 
  632.  
  633. /** 
  634. * Fetch a subset of posts from a tumblr blog 
  635. * @param $start index to start at 
  636. * @param $count how many posts to get (max 50) 
  637. * @param $state can be empty for normal posts, or "draft", "queue", or "submission" to get those posts 
  638. * @returns false on error, array of posts on success 
  639. */ 
  640. function fetch_posts($url, $start=0, $count = 50, $email = null, $password = null, $state = null ) { 
  641. $url = parse_url( $url, PHP_URL_HOST ); 
  642. $post_type = apply_filters( 'tumblr_post_type', '' ); 
  643. $url = trailingslashit( "http://api.tumblr.com/v2/blog/$url/posts/$post_type" ); 
  644.  
  645. do_action( 'tumblr_importer_pre_fetch_posts' ); 
  646.  
  647. // These extra params hose up the auth if passed for oauth requests e.g. for drafts, so use them only for normal posts. 
  648. if ( '' == $post_type ) { 
  649. $params = array( 
  650. 'offset' => $start,  
  651. 'limit' => $count,  
  652. 'api_key' => apply_filters( 'tumblr_importer_get_consumer_key', '' ),  
  653. ); 
  654. $url = add_query_arg( $params, $url ); 
  655.  
  656. $response = $this->oauth_get_request($url); 
  657.  
  658. switch ( $response->meta->status ) { 
  659. case 200: // OK 
  660. break; 
  661. default: 
  662. $_error = sprintf( __( 'Tumblr replied with an error: %s', 'tumblr-importer' ), $response->meta->msg ); 
  663. do_action( 'tumblr_importer_handle_error', 'response_' . $response->meta->status ); 
  664. return new WP_Error('tumblr_error', $_error ); 
  665.  
  666. $posts = array(); 
  667. $tposts = $response->response->posts; 
  668. foreach( $tposts as $tpost ) { 
  669. $post = array(); 
  670. $post['tumblr_id'] = (string) $tpost->id; 
  671. $post['tumblr_url'] = (string) $tpost->post_url; 
  672. $post['post_date'] = date( 'Y-m-d H:i:s', strtotime ( (string) $tpost->date ) ); 
  673. $post['post_date_gmt'] = date( 'Y-m-d H:i:s', strtotime ( (string) $tpost->date ) ); 
  674. $post['post_name'] = (string) $tpost->slug; 
  675. if ( 'private' == $tpost->state )  
  676. $post['private'] = (string) $tpost->state; 
  677. if ( isset( $tpost->tags ) ) { 
  678. $post['tags_input'] = array(); 
  679. foreach ( $tpost->tags as $tag ) 
  680. $post['tags_input'][] = rtrim( (string) $tag, ', '); // Strip trailing Commas off it too. 
  681.  
  682. switch ( (string) $tpost->type ) { 
  683. case 'photo': 
  684. $post['format'] = 'image'; 
  685. $post['media']['src'] = (string) $tpost->photos[0]->original_size->url; 
  686. $post['media']['link'] = '';//TODO: Find out what to use here.(string) $tpost->{'photo-link-url'}; 
  687. $post['media']['width'] = (string) $tpost->photos[0]->original_size->width; 
  688. $post['media']['height'] = (string) $tpost->photos[0]->original_size->height; 
  689. $post['post_content'] = (string) $tpost->caption; 
  690. if ( ! empty( $tpost->photos ) ) { 
  691. $post['format'] = 'gallery'; 
  692. foreach ( $tpost->photos as $photo ) { 
  693. $post['gallery'][] = array ( 
  694. 'src' => $photo->original_size->url,  
  695. 'width' => $photo->original_size->width,  
  696. 'height' => $photo->original_size->height,  
  697. 'caption' => $photo->caption,  
  698. ); 
  699. break; 
  700. case 'quote': 
  701. $post['format'] = 'quote'; 
  702. $post['post_content'] = '<blockquote>' . (string) $tpost->text . '</blockquote>'; 
  703. $post['post_content'] .= "\n\n<div class='attribution'>" . (string) $tpost->source . '</div>'; 
  704. break; 
  705. case 'link': 
  706. $post['format'] = 'link'; 
  707. $linkurl = (string) $tpost->url; 
  708. $linktext = (string) $tpost->title; 
  709. $post['post_content'] = "<a href='$linkurl'>$linktext</a>"; 
  710. if ( ! empty( $tpost->description ) ) 
  711. $post['post_content'] .= '<div class="link_description">' . (string) $tpost->description . '</div>'; 
  712. $post['post_title'] = (string) $tpost->title; 
  713. break; 
  714. case 'chat': 
  715. $post['format'] = 'chat'; 
  716. $post['post_title'] = (string) $tpost->title; 
  717. $post['post_content'] = (string) $tpost->body; 
  718. break; 
  719. case 'audio': 
  720. $post['format'] = 'audio'; 
  721. $post['media']['filename'] = basename( (string) $tpost->audio_url ); 
  722. // If no .mp3 extension, add one so that sideloading works. 
  723. if ( ! preg_match( '/\.mp3$/', $post['media']['filename'] ) ) 
  724. $post['media']['filename'] .= '.mp3'; 
  725. $post['media']['audio'] = (string) $tpost->audio_url .'?plead=please-dont-download-this-or-our-lawyers-wont-let-us-host-audio'; 
  726. $post['post_content'] = (string) $tpost->player . "\n" . (string) $tpost->caption; 
  727. break; 
  728. case 'video': 
  729. $post['format'] = 'video'; 
  730. $post['post_content'] = ''; 
  731.  
  732. $video = array_shift( $tpost->player ); 
  733.  
  734. if ( false !== strpos( (string) $video->embed_code, 'embed' ) ) { 
  735. if ( preg_match_all('/<embed (.+?)>/', (string) $video->embed_code, $matches) ) { 
  736. foreach ($matches[1] as $match) { 
  737. foreach ( wp_kses_hair( $match, array( 'http' ) ) as $attr ) 
  738. $embed[ $attr['name'] ] = $attr['value']; 
  739.  
  740. // special case for weird youtube vids 
  741. $embed['src'] = preg_replace( '|http://www.youtube.com/v/([a-zA-Z0-9_]+).*|i', 'http://www.youtube.com/watch?v=$1', $embed['src'] ); 
  742.  
  743. // TODO find other special cases, since tumblr is full of them 
  744. $post['post_content'] = $embed['src']; 
  745.  
  746. // Sometimes, video-source contains iframe markup. 
  747. if ( preg_match( '/<iframe/', $video->embed_code ) ) { 
  748. $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 ); 
  749. $post['post_content'] = $embed['src']; 
  750. } elseif ( preg_match( '/<iframe.*vimeo/', $video->embed_code ) ) { 
  751. $embed['src'] = preg_replace( '|<iframe.*src="(http://player.vimeo.com/video/([a-zA-Z0-9_\-]+))\??.*".*</iframe>.*|', 'http://vimeo.com/$2', $video->embed_code ); 
  752. $post['post_content'] = $embed['src']; 
  753. } else { 
  754. // @todo: See if the video source is going to be oEmbed'able before adding the flash player 
  755. $post['post_content'] .= $video->embed_code; 
  756.  
  757. $post['post_content'] .= "\n" . (string) $tpost->caption; 
  758. break; 
  759. case 'answer': 
  760. // TODO: Include asking_name and asking_url values? 
  761. $post['post_title'] = (string) $tpost->question; 
  762. $post['post_content'] = (string) $tpost->answer; 
  763. break; 
  764. case 'regular': 
  765. case 'text': 
  766. default: 
  767. $post['post_title'] = (string) $tpost->title; 
  768. $post['post_content'] = (string) $tpost->body; 
  769. break; 
  770. $posts[] = $post; 
  771.  
  772. return $posts; 
  773.  
  774. /** 
  775. * Fetch the Pages from a tumblr blog 
  776. * @returns false on error, array of page contents on success 
  777. */ 
  778. function fetch_pages($url, $email = null, $password = null) { 
  779. $tumblrurl = trailingslashit($url).'api/pages'; 
  780. $params = array( 
  781. 'email'=>$email,  
  782. 'password'=>$password,  
  783. ); 
  784. $options = array( 'body' => $params ); 
  785.  
  786. // fetch the pages 
  787. $out = wp_remote_post($tumblrurl, $options); 
  788. if (wp_remote_retrieve_response_code($out) != 200) return false; 
  789. $body = wp_remote_retrieve_body($out); 
  790.  
  791. // parse the XML into something useful 
  792. $xml = simplexml_load_string($body); 
  793.  
  794. if (!isset($xml->pages)) return false; 
  795.  
  796. $tpages = $xml->pages; 
  797. $pages = array(); 
  798. foreach($tpages->page as $tpage) { 
  799. if ( !empty($tpage['title']) ) 
  800. $page['post_title'] = (string) $tpage['title']; 
  801. else if (!empty($tpage['link-title']) ) 
  802. $page['post_title'] = (string) $tpage['link-title']; 
  803. else 
  804. $page['post_title'] = ''; 
  805. $page['post_name'] = str_replace( $url, '', (string) $tpage['url'] ); 
  806. $page['post_content'] = (string) $tpage; 
  807. $page['tumblr_url'] = (string) $tpage['url']; 
  808. $pages[] = $page; 
  809.  
  810. return $pages; 
  811.  
  812. function filter_format_post( $_post ) { 
  813. if ( isset( $_post['meta']['attribution'] ) ) { 
  814. $attribution = $_post['meta']['attribution']; 
  815. if ( preg_match( '/^http[^ ]+$/', $_post['meta']['attribution'] ) ) 
  816. $attribution = sprintf( '<a href="%s">%s</a>', $_post['meta']['attribution'], $_post['meta']['attribution'] ); 
  817. $_post['post_content'] .= sprintf( '<div class="attribution">(<span>' . __( 'Source:', 'tumblr-importer' ) . '</span> %s)</div>', $attribution ); 
  818.  
  819. return $_post; 
  820.  
  821. function tumblr_importer_metadata( $_post ) { 
  822. if ( isset( $_post['meta'] ) ) { 
  823. foreach ( $_post['meta'] as $key => $val ) { 
  824. add_post_meta( $_post['ID'], 'tumblr_' . $key, $val ); 
  825. }  
  826.  
  827. /** 
  828. * When galleries have no caption, the post_content field is empty, which 
  829. * along with empty title and excerpt causes the post not to insert. 
  830. * Here we override the default behavior. 
  831. */ 
  832. function filter_allow_empty_content( $maybe_empty, $_post ) { 
  833. if ( 'gallery' == $_post['format'] ) 
  834. return false; 
  835.  
  836. return $maybe_empty; 
  837.  
  838.  
  839. /** 
  840. * OAuth Signature creation 
  841. */ 
  842. function oauth_signature($secret, $method, $url, $params = array()) { 
  843. uksort($params, 'strcmp'); 
  844. foreach ($params as $k => $v) { 
  845. $pairs[] = $this->_urlencode_rfc3986($k).'='.$this->_urlencode_rfc3986($v); 
  846. $concatenatedParams = implode('&', $pairs); 
  847. $baseString= $method."&". $this->_urlencode_rfc3986($url)."&".$this->_urlencode_rfc3986($concatenatedParams); 
  848. if (!is_array($secret)) { 
  849. $secret[0] = $secret; 
  850. $secret[1] = ''; 
  851. $secret = $this->_urlencode_rfc3986($secret[0])."&".$this->_urlencode_rfc3986($secret[1]); 
  852. $oauth_signature = base64_encode(hash_hmac('sha1', $baseString, $secret, TRUE));  
  853. return $oauth_signature; 
  854.  
  855. /** 
  856. * Helper function for OAuth Signature creation 
  857. */  
  858. function _urlencode_rfc3986($input) 
  859. if (is_array($input)) { 
  860. return array_map(array($this, '_urlencode_rfc3986'), $input); 
  861. } else if (is_scalar($input)) { 
  862. return str_replace(array('+', '%7E'), array(' ', '~'), rawurlencode($input)); 
  863. } else { 
  864. return ''; 
  865.  
  866. /** 
  867. * Do a GET request with the access tokens 
  868. */ 
  869. function oauth_get_request($url) { 
  870. if ( empty( $this->access_tokens ) )  
  871. return false; 
  872.  
  873. $params = array('oauth_consumer_key' => $this->get_consumer_key(),  
  874. "oauth_nonce" => time(),  
  875. "oauth_timestamp" => time(),  
  876. "oauth_token" => $this->access_tokens['oauth_token'],  
  877. "oauth_signature_method" => "HMAC-SHA1",  
  878. "oauth_version" => "1.0",  
  879. ); 
  880.  
  881. $params['oauth_signature'] = $this->oauth_signature(array($this->secretkey, $this->access_tokens['oauth_token_secret']), 'GET', $url, $params); 
  882.  
  883. $url = add_query_arg( array_map('urlencode', $params), $url); 
  884.  
  885. $response = wp_remote_get( $url ); 
  886.  
  887. if ( is_wp_error( $response ) || 200 != wp_remote_retrieve_response_code( $response ) ) { 
  888. return false; 
  889. } else { 
  890. $body = wp_remote_retrieve_body( $response ); 
  891. return json_decode($body); 
  892.  
  893.