Tumblr Importer - Version 0.6

Version Description

  • Significant improvements in the performance of the importer
  • Improves import of images from Tumblr - better choice of images sizes for theme display
  • Improved author selection logic on single author blogs
  • Auto refreshing to show import progress and give clearer feedback
  • Improves import videos from Tumble - enable auto-embedding for for content.
  • Block imports from Tumblr sites with mapped domains enabled because they don't work well - you have to temporarily disable the mapping.
Download this release

Release Info

Developer westi
Plugin Icon 128x128 Tumblr Importer
Version 0.6
Comparing to
See all releases

Code changes from version 0.5 to 0.6

Files changed (5) hide show
  1. class-wp-importer-cron.php +89 -89
  2. languages/tumblr-importer.pot +213 -0
  3. license.txt +281 -281
  4. readme.txt +58 -48
  5. tumblr-importer.php +887 -787
class-wp-importer-cron.php CHANGED
@@ -1,90 +1,90 @@
1
- <?php
2
- /**
3
- * WP_Importer_Cron base class
4
- *
5
- * Adds cron based importing functionality to WP_Importer
6
- */
7
-
8
- if ( !class_exists( 'WP_Importer_Cron' ) ) :
9
-
10
- require_once ABSPATH . 'wp-admin/includes/import.php';
11
-
12
- if ( !class_exists( 'WP_Importer' ) ) {
13
- $class_wp_importer = ABSPATH . 'wp-admin/includes/class-wp-importer.php';
14
- if ( file_exists( $class_wp_importer ) ) {
15
- require_once $class_wp_importer;
16
- } else {
17
- return;
18
- }
19
- }
20
-
21
- class WP_Importer_Cron extends WP_Importer {
22
-
23
- function __construct() {
24
- // start the clock
25
- $this->_importer_started = time();
26
- $this->_max_execution_time = 30; // default to 30 seconds of time on the clock
27
- parent::__construct();
28
-
29
- // add the importer schedule
30
- add_filter( 'cron_schedules', array( $this, 'importer_schedule' ) );
31
-
32
- // add the importer hook
33
- add_action( 'wp_cron_importer_hook', array( $this, 'importer_callback' ) );
34
-
35
- //load the variables
36
- $options = get_option( get_class($this) );
37
-
38
- if ( is_array($options) )
39
- foreach ( $options as $key => $value )
40
- $this->$key = $value;
41
- }
42
-
43
- // Check to see if you have time remaining on the clock
44
- function have_time() {
45
- if ( time() - $this->_importer_started > $this->_max_execution_time ) return false;
46
- return true;
47
- }
48
-
49
- // add the once every three minute schedule
50
- function importer_schedule( $schedules ) {
51
- $schedules['everyminute'] = array( 'interval' => 60, 'display' => __('Every Minute') );
52
- return $schedules;
53
- }
54
-
55
- // schedule an importer job
56
- function schedule_import_job( $function_name, $args=array() ) {
57
- $this->callback = $function_name;
58
- wp_schedule_event(time(), 'everyminute', 'wp_cron_importer_hook' , $args);
59
- }
60
-
61
- // internal callback that checks for a finished import and clears old jobs out
62
- function importer_callback( $args=array() ) {
63
- $args = (array)$args;
64
-
65
- if ( isset($this->callback) ) {
66
- $complete = call_user_func_array( array( $this, $this->callback ), $args );
67
- } else {
68
- // no callback, force the cron job to end
69
- $complete = true;
70
- }
71
-
72
- if ( $complete ) {
73
- // importer is finished, stop the scheduler
74
- wp_clear_scheduled_hook( 'wp_cron_importer_hook', $args);
75
- }
76
- }
77
-
78
- // function to let the class save its own variables
79
- function save_vars() {
80
- $vars = get_object_vars($this);
81
- foreach($vars as $var=>$val) {
82
- if ($var[0] == "_") unset ($vars[$var]);
83
- }
84
- update_option( get_class($this), $vars );
85
-
86
- return !empty($vars);
87
- }
88
- }
89
-
90
  endif; // class_exists
1
+ <?php
2
+ /**
3
+ * WP_Importer_Cron base class
4
+ *
5
+ * Adds cron based importing functionality to WP_Importer
6
+ */
7
+
8
+ if ( !class_exists( 'WP_Importer_Cron' ) ) :
9
+
10
+ require_once ABSPATH . 'wp-admin/includes/import.php';
11
+
12
+ if ( !class_exists( 'WP_Importer' ) ) {
13
+ $class_wp_importer = ABSPATH . 'wp-admin/includes/class-wp-importer.php';
14
+ if ( file_exists( $class_wp_importer ) ) {
15
+ require_once $class_wp_importer;
16
+ } else {
17
+ return;
18
+ }
19
+ }
20
+
21
+ class WP_Importer_Cron extends WP_Importer {
22
+
23
+ function __construct() {
24
+ // start the clock
25
+ $this->_importer_started = time();
26
+ $this->_max_execution_time = 30; // default to 30 seconds of time on the clock
27
+ parent::__construct();
28
+
29
+ // add the importer schedule
30
+ add_filter( 'cron_schedules', array( $this, 'importer_schedule' ) );
31
+
32
+ // add the importer hook
33
+ add_action( 'wp_cron_importer_hook', array( $this, 'importer_callback' ) );
34
+
35
+ //load the variables
36
+ $options = get_option( get_class($this) );
37
+
38
+ if ( is_array($options) )
39
+ foreach ( $options as $key => $value )
40
+ $this->$key = $value;
41
+ }
42
+
43
+ // Check to see if you have time remaining on the clock
44
+ function have_time() {
45
+ if ( time() - $this->_importer_started > $this->_max_execution_time ) return false;
46
+ return true;
47
+ }
48
+
49
+ // add the once every three minute schedule
50
+ function importer_schedule( $schedules ) {
51
+ $schedules['everyminute'] = array( 'interval' => 60, 'display' => __('Every Minute') );
52
+ return $schedules;
53
+ }
54
+
55
+ // schedule an importer job
56
+ function schedule_import_job( $function_name, $args=array() ) {
57
+ $this->callback = $function_name;
58
+ wp_schedule_event(time(), 'everyminute', 'wp_cron_importer_hook' , $args);
59
+ }
60
+
61
+ // internal callback that checks for a finished import and clears old jobs out
62
+ function importer_callback( $args=array() ) {
63
+ $args = (array)$args;
64
+
65
+ if ( isset($this->callback) ) {
66
+ $complete = call_user_func_array( array( $this, $this->callback ), $args );
67
+ } else {
68
+ // no callback, force the cron job to end
69
+ $complete = true;
70
+ }
71
+
72
+ if ( $complete ) {
73
+ // importer is finished, stop the scheduler
74
+ wp_clear_scheduled_hook( 'wp_cron_importer_hook', $args);
75
+ }
76
+ }
77
+
78
+ // function to let the class save its own variables
79
+ function save_vars() {
80
+ $vars = get_object_vars($this);
81
+ foreach($vars as $var=>$val) {
82
+ if ($var[0] == "_") unset ($vars[$var]);
83
+ }
84
+ update_option( get_class($this), $vars );
85
+
86
+ return !empty($vars);
87
+ }
88
+ }
89
+
90
  endif; // class_exists
languages/tumblr-importer.pot ADDED
@@ -0,0 +1,213 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (C) 2012 Tumblr Importer
2
+ # This file is distributed under the same license as the Tumblr Importer package.
3
+ msgid ""
4
+ msgstr ""
5
+ "Project-Id-Version: Tumblr Importer 0.6\n"
6
+ "Report-Msgid-Bugs-To: http://wordpress.org/tag/tumblr-importer\n"
7
+ "POT-Creation-Date: 2012-06-14 15:24:25+00:00\n"
8
+ "MIME-Version: 1.0\n"
9
+ "Content-Type: text/plain; charset=UTF-8\n"
10
+ "Content-Transfer-Encoding: 8bit\n"
11
+ "PO-Revision-Date: 2012-MO-DA HO:MI+ZONE\n"
12
+ "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13
+ "Language-Team: LANGUAGE <LL@li.org>\n"
14
+
15
+ #: class-wp-importer-cron.php:51
16
+ msgid "Every Minute"
17
+ msgstr ""
18
+
19
+ #: tumblr-importer.php:31
20
+ msgid "Tumblr"
21
+ msgstr ""
22
+
23
+ #. #-#-#-#-# plugin.pot (Tumblr Importer 0.6) #-#-#-#-#
24
+ #. Description of the plugin/theme
25
+ #: tumblr-importer.php:31
26
+ msgid "Import posts from a Tumblr blog."
27
+ msgstr ""
28
+
29
+ #: tumblr-importer.php:81
30
+ msgid ""
31
+ "We have saved some information about your Tumblr account in your WordPress "
32
+ "database. Clearing this information will allow you to start over. Restarting "
33
+ "will not affect any posts you have already imported. If you attempt to re-"
34
+ "import a blog, duplicate posts will be skipped."
35
+ msgstr ""
36
+
37
+ #: tumblr-importer.php:82
38
+ msgid "Note: This will stop any import currently in progress."
39
+ msgstr ""
40
+
41
+ #: tumblr-importer.php:85
42
+ msgid "Clear account information"
43
+ msgstr ""
44
+
45
+ #: tumblr-importer.php:99 tumblr-importer.php:149
46
+ msgid "Import Tumblr"
47
+ msgstr ""
48
+
49
+ #: tumblr-importer.php:100
50
+ msgid ""
51
+ "Howdy! This importer allows you to import posts from your Tumblr account "
52
+ "into your WordPress site."
53
+ msgstr ""
54
+
55
+ #: tumblr-importer.php:101
56
+ msgid ""
57
+ "Firstly, you need to provide your email and password for Tumblr, so that "
58
+ "WordPress can access your account."
59
+ msgstr ""
60
+
61
+ #: tumblr-importer.php:106
62
+ msgid "Email:"
63
+ msgstr ""
64
+
65
+ #: tumblr-importer.php:110
66
+ msgid "Password:"
67
+ msgstr ""
68
+
69
+ #: tumblr-importer.php:115
70
+ msgid "Connect to Tumblr"
71
+ msgstr ""
72
+
73
+ #: tumblr-importer.php:129
74
+ msgid ""
75
+ "This doesn't appear to be a valid email address. Please check it and try "
76
+ "again."
77
+ msgstr ""
78
+
79
+ #: tumblr-importer.php:150
80
+ msgid ""
81
+ "Please select the Tumblr blog you would like to import into your WordPress "
82
+ "site and then click on the \"Import this Blog\" button to continue."
83
+ msgstr ""
84
+
85
+ #: tumblr-importer.php:151
86
+ msgid ""
87
+ "If your import gets stuck for a long time or you would like to import from a "
88
+ "different Tumblr account instead then click on the \"Clear account "
89
+ "information\" button below to reset the importer."
90
+ msgstr ""
91
+
92
+ #: tumblr-importer.php:153
93
+ msgid ""
94
+ "As Tumblr does not expose the \"author\", even from multi-author blogs you "
95
+ "will need to select which WordPress user will be listed as the author of the "
96
+ "imported posts."
97
+ msgstr ""
98
+
99
+ #: tumblr-importer.php:157
100
+ msgid "Tumblr Blog"
101
+ msgstr ""
102
+
103
+ #: tumblr-importer.php:158
104
+ msgid "URL"
105
+ msgstr ""
106
+
107
+ #: tumblr-importer.php:159
108
+ msgid "Posts Imported"
109
+ msgstr ""
110
+
111
+ #: tumblr-importer.php:160
112
+ msgid "Drafts Imported"
113
+ msgstr ""
114
+
115
+ #: tumblr-importer.php:161
116
+ msgid "Queued Imported"
117
+ msgstr ""
118
+
119
+ #: tumblr-importer.php:162
120
+ msgid "Pages Imported"
121
+ msgstr ""
122
+
123
+ #: tumblr-importer.php:163
124
+ msgid "Author"
125
+ msgstr ""
126
+
127
+ #: tumblr-importer.php:164
128
+ msgid "Action/Status"
129
+ msgstr ""
130
+
131
+ #: tumblr-importer.php:185
132
+ msgid "Import this blog"
133
+ msgstr ""
134
+
135
+ #: tumblr-importer.php:187
136
+ msgid "Finished!"
137
+ msgstr ""
138
+
139
+ #: tumblr-importer.php:189
140
+ msgid "In Progress"
141
+ msgstr ""
142
+
143
+ #: tumblr-importer.php:198
144
+ msgid ""
145
+ "Tumblr Blogs with Custom Domains activated cannot be imported, please "
146
+ "disable the custom domain first."
147
+ msgstr ""
148
+
149
+ #: tumblr-importer.php:198
150
+ msgid "Custom Domain"
151
+ msgstr ""
152
+
153
+ #: tumblr-importer.php:234
154
+ msgid ""
155
+ "As one or more of your Tumblr blogs has a Custom Domain mapped to it. If you "
156
+ "would like to import one of these sites you will need to temporarily remove "
157
+ "the custom domain mapping and clear the account information from the "
158
+ "importer to import. Once the import is completed you can re-enable the "
159
+ "custom domain for your site."
160
+ msgstr ""
161
+
162
+ #: tumblr-importer.php:237
163
+ msgid ""
164
+ "Importing your Tumblr blog can take a while so the importing process happens "
165
+ "in the background and you may not see immediate results here. Come back to "
166
+ "this page later to check on the importer's progress."
167
+ msgstr ""
168
+
169
+ #: tumblr-importer.php:247
170
+ msgid "The specified blog cannot be found."
171
+ msgstr ""
172
+
173
+ #: tumblr-importer.php:252
174
+ msgid "This blog is currently being imported."
175
+ msgstr ""
176
+
177
+ #: tumblr-importer.php:324 tumblr-importer.php:391 tumblr-importer.php:436
178
+ msgid "Problem communicating with Tumblr, retrying later"
179
+ msgstr ""
180
+
181
+ #: tumblr-importer.php:621
182
+ msgid ""
183
+ "Tumblr says that the username and password you provided were not valid. "
184
+ "Please check you entered them correctly and try to connect again."
185
+ msgstr ""
186
+
187
+ #: tumblr-importer.php:626
188
+ msgid "Tumblr replied with an error: %s"
189
+ msgstr ""
190
+
191
+ #: tumblr-importer.php:639
192
+ msgid "No blog information found for this account. "
193
+ msgstr ""
194
+
195
+ #: tumblr-importer.php:860
196
+ msgid "Source:"
197
+ msgstr ""
198
+
199
+ #. Plugin Name of the plugin/theme
200
+ msgid "Tumblr Importer"
201
+ msgstr ""
202
+
203
+ #. Plugin URI of the plugin/theme
204
+ msgid "http://wordpress.org/extend/plugins/tumblr-importer/"
205
+ msgstr ""
206
+
207
+ #. Author of the plugin/theme
208
+ msgid "wordpressdotorg"
209
+ msgstr ""
210
+
211
+ #. Author URI of the plugin/theme
212
+ msgid "http://wordpress.org/"
213
+ msgstr ""
license.txt CHANGED
@@ -1,281 +1,281 @@
1
- GNU GENERAL PUBLIC LICENSE
2
- Version 2, June 1991
3
-
4
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
5
- 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
6
-
7
- Everyone is permitted to copy and distribute verbatim copies
8
- of this license document, but changing it is not allowed.
9
-
10
- Preamble
11
-
12
- The licenses for most software are designed to take away your
13
- freedom to share and change it. By contrast, the GNU General Public
14
- License is intended to guarantee your freedom to share and change free
15
- software--to make sure the software is free for all its users. This
16
- General Public License applies to most of the Free Software
17
- Foundation's software and to any other program whose authors commit to
18
- using it. (Some other Free Software Foundation software is covered by
19
- the GNU Library General Public License instead.) You can apply it to
20
- your programs, too.
21
-
22
- When we speak of free software, we are referring to freedom, not
23
- price. Our General Public Licenses are designed to make sure that you
24
- have the freedom to distribute copies of free software (and charge for
25
- this service if you wish), that you receive source code or can get it
26
- if you want it, that you can change the software or use pieces of it
27
- in new free programs; and that you know you can do these things.
28
-
29
- To protect your rights, we need to make restrictions that forbid
30
- anyone to deny you these rights or to ask you to surrender the rights.
31
- These restrictions translate to certain responsibilities for you if you
32
- distribute copies of the software, or if you modify it.
33
-
34
- For example, if you distribute copies of such a program, whether
35
- gratis or for a fee, you must give the recipients all the rights that
36
- you have. You must make sure that they, too, receive or can get the
37
- source code. And you must show them these terms so they know their
38
- rights.
39
-
40
- We protect your rights with two steps: (1) copyright the software, and
41
- (2) offer you this license which gives you legal permission to copy,
42
- distribute and/or modify the software.
43
-
44
- Also, for each author's protection and ours, we want to make certain
45
- that everyone understands that there is no warranty for this free
46
- software. If the software is modified by someone else and passed on, we
47
- want its recipients to know that what they have is not the original, so
48
- that any problems introduced by others will not reflect on the original
49
- authors' reputations.
50
-
51
- Finally, any free program is threatened constantly by software
52
- patents. We wish to avoid the danger that redistributors of a free
53
- program will individually obtain patent licenses, in effect making the
54
- program proprietary. To prevent this, we have made it clear that any
55
- patent must be licensed for everyone's free use or not licensed at all.
56
-
57
- The precise terms and conditions for copying, distribution and
58
- modification follow.
59
-
60
- GNU GENERAL PUBLIC LICENSE
61
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
62
-
63
- 0. This License applies to any program or other work which contains
64
- a notice placed by the copyright holder saying it may be distributed
65
- under the terms of this General Public License. The "Program", below,
66
- refers to any such program or work, and a "work based on the Program"
67
- means either the Program or any derivative work under copyright law:
68
- that is to say, a work containing the Program or a portion of it,
69
- either verbatim or with modifications and/or translated into another
70
- language. (Hereinafter, translation is included without limitation in
71
- the term "modification".) Each licensee is addressed as "you".
72
-
73
- Activities other than copying, distribution and modification are not
74
- covered by this License; they are outside its scope. The act of
75
- running the Program is not restricted, and the output from the Program
76
- is covered only if its contents constitute a work based on the
77
- Program (independent of having been made by running the Program).
78
- Whether that is true depends on what the Program does.
79
-
80
- 1. You may copy and distribute verbatim copies of the Program's
81
- source code as you receive it, in any medium, provided that you
82
- conspicuously and appropriately publish on each copy an appropriate
83
- copyright notice and disclaimer of warranty; keep intact all the
84
- notices that refer to this License and to the absence of any warranty;
85
- and give any other recipients of the Program a copy of this License
86
- along with the Program.
87
-
88
- You may charge a fee for the physical act of transferring a copy, and
89
- you may at your option offer warranty protection in exchange for a fee.
90
-
91
- 2. You may modify your copy or copies of the Program or any portion
92
- of it, thus forming a work based on the Program, and copy and
93
- distribute such modifications or work under the terms of Section 1
94
- above, provided that you also meet all of these conditions:
95
-
96
- a) You must cause the modified files to carry prominent notices
97
- stating that you changed the files and the date of any change.
98
-
99
- b) You must cause any work that you distribute or publish, that in
100
- whole or in part contains or is derived from the Program or any
101
- part thereof, to be licensed as a whole at no charge to all third
102
- parties under the terms of this License.
103
-
104
- c) If the modified program normally reads commands interactively
105
- when run, you must cause it, when started running for such
106
- interactive use in the most ordinary way, to print or display an
107
- announcement including an appropriate copyright notice and a
108
- notice that there is no warranty (or else, saying that you provide
109
- a warranty) and that users may redistribute the program under
110
- these conditions, and telling the user how to view a copy of this
111
- License. (Exception: if the Program itself is interactive but
112
- does not normally print such an announcement, your work based on
113
- the Program is not required to print an announcement.)
114
-
115
- These requirements apply to the modified work as a whole. If
116
- identifiable sections of that work are not derived from the Program,
117
- and can be reasonably considered independent and separate works in
118
- themselves, then this License, and its terms, do not apply to those
119
- sections when you distribute them as separate works. But when you
120
- distribute the same sections as part of a whole which is a work based
121
- on the Program, the distribution of the whole must be on the terms of
122
- this License, whose permissions for other licensees extend to the
123
- entire whole, and thus to each and every part regardless of who wrote it.
124
- Thus, it is not the intent of this section to claim rights or contest
125
- your rights to work written entirely by you; rather, the intent is to
126
- exercise the right to control the distribution of derivative or
127
- collective works based on the Program.
128
-
129
- In addition, mere aggregation of another work not based on the Program
130
- with the Program (or with a work based on the Program) on a volume of
131
- a storage or distribution medium does not bring the other work under
132
- the scope of this License.
133
-
134
- 3. You may copy and distribute the Program (or a work based on it,
135
- under Section 2) in object code or executable form under the terms of
136
- Sections 1 and 2 above provided that you also do one of the following:
137
-
138
- a) Accompany it with the complete corresponding machine-readable
139
- source code, which must be distributed under the terms of Sections
140
- 1 and 2 above on a medium customarily used for software interchange; or,
141
-
142
- b) Accompany it with a written offer, valid for at least three
143
- years, to give any third party, for a charge no more than your
144
- cost of physically performing source distribution, a complete
145
- machine-readable copy of the corresponding source code, to be
146
- distributed under the terms of Sections 1 and 2 above on a medium
147
- customarily used for software interchange; or,
148
-
149
- c) Accompany it with the information you received as to the offer
150
- to distribute corresponding source code. (This alternative is
151
- allowed only for noncommercial distribution and only if you
152
- received the program in object code or executable form with such
153
- an offer, in accord with Subsection b above.)
154
-
155
- The source code for a work means the preferred form of the work for
156
- making modifications to it. For an executable work, complete source
157
- code means all the source code for all modules it contains, plus any
158
- associated interface definition files, plus the scripts used to
159
- control compilation and installation of the executable. However, as a
160
- special exception, the source code distributed need not include
161
- anything that is normally distributed (in either source or binary
162
- form) with the major components (compiler, kernel, and so on) of the
163
- operating system on which the executable runs, unless that component
164
- itself accompanies the executable.
165
-
166
- If distribution of executable or object code is made by offering
167
- access to copy from a designated place, then offering equivalent
168
- access to copy the source code from the same place counts as
169
- distribution of the source code, even though third parties are not
170
- compelled to copy the source along with the object code.
171
-
172
- 4. You may not copy, modify, sublicense, or distribute the Program
173
- except as expressly provided under this License. Any attempt
174
- otherwise to copy, modify, sublicense or distribute the Program is
175
- void, and will automatically terminate your rights under this License.
176
- However, parties who have received copies, or rights, from you under
177
- this License will not have their licenses terminated so long as such
178
- parties remain in full compliance.
179
-
180
- 5. You are not required to accept this License, since you have not
181
- signed it. However, nothing else grants you permission to modify or
182
- distribute the Program or its derivative works. These actions are
183
- prohibited by law if you do not accept this License. Therefore, by
184
- modifying or distributing the Program (or any work based on the
185
- Program), you indicate your acceptance of this License to do so, and
186
- all its terms and conditions for copying, distributing or modifying
187
- the Program or works based on it.
188
-
189
- 6. Each time you redistribute the Program (or any work based on the
190
- Program), the recipient automatically receives a license from the
191
- original licensor to copy, distribute or modify the Program subject to
192
- these terms and conditions. You may not impose any further
193
- restrictions on the recipients' exercise of the rights granted herein.
194
- You are not responsible for enforcing compliance by third parties to
195
- this License.
196
-
197
- 7. If, as a consequence of a court judgment or allegation of patent
198
- infringement or for any other reason (not limited to patent issues),
199
- conditions are imposed on you (whether by court order, agreement or
200
- otherwise) that contradict the conditions of this License, they do not
201
- excuse you from the conditions of this License. If you cannot
202
- distribute so as to satisfy simultaneously your obligations under this
203
- License and any other pertinent obligations, then as a consequence you
204
- may not distribute the Program at all. For example, if a patent
205
- license would not permit royalty-free redistribution of the Program by
206
- all those who receive copies directly or indirectly through you, then
207
- the only way you could satisfy both it and this License would be to
208
- refrain entirely from distribution of the Program.
209
-
210
- If any portion of this section is held invalid or unenforceable under
211
- any particular circumstance, the balance of the section is intended to
212
- apply and the section as a whole is intended to apply in other
213
- circumstances.
214
-
215
- It is not the purpose of this section to induce you to infringe any
216
- patents or other property right claims or to contest validity of any
217
- such claims; this section has the sole purpose of protecting the
218
- integrity of the free software distribution system, which is
219
- implemented by public license practices. Many people have made
220
- generous contributions to the wide range of software distributed
221
- through that system in reliance on consistent application of that
222
- system; it is up to the author/donor to decide if he or she is willing
223
- to distribute software through any other system and a licensee cannot
224
- impose that choice.
225
-
226
- This section is intended to make thoroughly clear what is believed to
227
- be a consequence of the rest of this License.
228
-
229
- 8. If the distribution and/or use of the Program is restricted in
230
- certain countries either by patents or by copyrighted interfaces, the
231
- original copyright holder who places the Program under this License
232
- may add an explicit geographical distribution limitation excluding
233
- those countries, so that distribution is permitted only in or among
234
- countries not thus excluded. In such case, this License incorporates
235
- the limitation as if written in the body of this License.
236
-
237
- 9. The Free Software Foundation may publish revised and/or new versions
238
- of the General Public License from time to time. Such new versions will
239
- be similar in spirit to the present version, but may differ in detail to
240
- address new problems or concerns.
241
-
242
- Each version is given a distinguishing version number. If the Program
243
- specifies a version number of this License which applies to it and "any
244
- later version", you have the option of following the terms and conditions
245
- either of that version or of any later version published by the Free
246
- Software Foundation. If the Program does not specify a version number of
247
- this License, you may choose any version ever published by the Free Software
248
- Foundation.
249
-
250
- 10. If you wish to incorporate parts of the Program into other free
251
- programs whose distribution conditions are different, write to the author
252
- to ask for permission. For software which is copyrighted by the Free
253
- Software Foundation, write to the Free Software Foundation; we sometimes
254
- make exceptions for this. Our decision will be guided by the two goals
255
- of preserving the free status of all derivatives of our free software and
256
- of promoting the sharing and reuse of software generally.
257
-
258
- NO WARRANTY
259
-
260
- 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261
- FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262
- OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263
- PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264
- OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265
- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266
- TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267
- PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268
- REPAIR OR CORRECTION.
269
-
270
- 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271
- WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272
- REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273
- INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274
- OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275
- TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276
- YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277
- PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278
- POSSIBILITY OF SUCH DAMAGES.
279
-
280
- END OF TERMS AND CONDITIONS
281
-
1
+ GNU GENERAL PUBLIC LICENSE
2
+ Version 2, June 1991
3
+
4
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
5
+ 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
6
+
7
+ Everyone is permitted to copy and distribute verbatim copies
8
+ of this license document, but changing it is not allowed.
9
+
10
+ Preamble
11
+
12
+ The licenses for most software are designed to take away your
13
+ freedom to share and change it. By contrast, the GNU General Public
14
+ License is intended to guarantee your freedom to share and change free
15
+ software--to make sure the software is free for all its users. This
16
+ General Public License applies to most of the Free Software
17
+ Foundation's software and to any other program whose authors commit to
18
+ using it. (Some other Free Software Foundation software is covered by
19
+ the GNU Library General Public License instead.) You can apply it to
20
+ your programs, too.
21
+
22
+ When we speak of free software, we are referring to freedom, not
23
+ price. Our General Public Licenses are designed to make sure that you
24
+ have the freedom to distribute copies of free software (and charge for
25
+ this service if you wish), that you receive source code or can get it
26
+ if you want it, that you can change the software or use pieces of it
27
+ in new free programs; and that you know you can do these things.
28
+
29
+ To protect your rights, we need to make restrictions that forbid
30
+ anyone to deny you these rights or to ask you to surrender the rights.
31
+ These restrictions translate to certain responsibilities for you if you
32
+ distribute copies of the software, or if you modify it.
33
+
34
+ For example, if you distribute copies of such a program, whether
35
+ gratis or for a fee, you must give the recipients all the rights that
36
+ you have. You must make sure that they, too, receive or can get the
37
+ source code. And you must show them these terms so they know their
38
+ rights.
39
+
40
+ We protect your rights with two steps: (1) copyright the software, and
41
+ (2) offer you this license which gives you legal permission to copy,
42
+ distribute and/or modify the software.
43
+
44
+ Also, for each author's protection and ours, we want to make certain
45
+ that everyone understands that there is no warranty for this free
46
+ software. If the software is modified by someone else and passed on, we
47
+ want its recipients to know that what they have is not the original, so
48
+ that any problems introduced by others will not reflect on the original
49
+ authors' reputations.
50
+
51
+ Finally, any free program is threatened constantly by software
52
+ patents. We wish to avoid the danger that redistributors of a free
53
+ program will individually obtain patent licenses, in effect making the
54
+ program proprietary. To prevent this, we have made it clear that any
55
+ patent must be licensed for everyone's free use or not licensed at all.
56
+
57
+ The precise terms and conditions for copying, distribution and
58
+ modification follow.
59
+
60
+ GNU GENERAL PUBLIC LICENSE
61
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
62
+
63
+ 0. This License applies to any program or other work which contains
64
+ a notice placed by the copyright holder saying it may be distributed
65
+ under the terms of this General Public License. The "Program", below,
66
+ refers to any such program or work, and a "work based on the Program"
67
+ means either the Program or any derivative work under copyright law:
68
+ that is to say, a work containing the Program or a portion of it,
69
+ either verbatim or with modifications and/or translated into another
70
+ language. (Hereinafter, translation is included without limitation in
71
+ the term "modification".) Each licensee is addressed as "you".
72
+
73
+ Activities other than copying, distribution and modification are not
74
+ covered by this License; they are outside its scope. The act of
75
+ running the Program is not restricted, and the output from the Program
76
+ is covered only if its contents constitute a work based on the
77
+ Program (independent of having been made by running the Program).
78
+ Whether that is true depends on what the Program does.
79
+
80
+ 1. You may copy and distribute verbatim copies of the Program's
81
+ source code as you receive it, in any medium, provided that you
82
+ conspicuously and appropriately publish on each copy an appropriate
83
+ copyright notice and disclaimer of warranty; keep intact all the
84
+ notices that refer to this License and to the absence of any warranty;
85
+ and give any other recipients of the Program a copy of this License
86
+ along with the Program.
87
+
88
+ You may charge a fee for the physical act of transferring a copy, and
89
+ you may at your option offer warranty protection in exchange for a fee.
90
+
91
+ 2. You may modify your copy or copies of the Program or any portion
92
+ of it, thus forming a work based on the Program, and copy and
93
+ distribute such modifications or work under the terms of Section 1
94
+ above, provided that you also meet all of these conditions:
95
+
96
+ a) You must cause the modified files to carry prominent notices
97
+ stating that you changed the files and the date of any change.
98
+
99
+ b) You must cause any work that you distribute or publish, that in
100
+ whole or in part contains or is derived from the Program or any
101
+ part thereof, to be licensed as a whole at no charge to all third
102
+ parties under the terms of this License.
103
+
104
+ c) If the modified program normally reads commands interactively
105
+ when run, you must cause it, when started running for such
106
+ interactive use in the most ordinary way, to print or display an
107
+ announcement including an appropriate copyright notice and a
108
+ notice that there is no warranty (or else, saying that you provide
109
+ a warranty) and that users may redistribute the program under
110
+ these conditions, and telling the user how to view a copy of this
111
+ License. (Exception: if the Program itself is interactive but
112
+ does not normally print such an announcement, your work based on
113
+ the Program is not required to print an announcement.)
114
+
115
+ These requirements apply to the modified work as a whole. If
116
+ identifiable sections of that work are not derived from the Program,
117
+ and can be reasonably considered independent and separate works in
118
+ themselves, then this License, and its terms, do not apply to those
119
+ sections when you distribute them as separate works. But when you
120
+ distribute the same sections as part of a whole which is a work based
121
+ on the Program, the distribution of the whole must be on the terms of
122
+ this License, whose permissions for other licensees extend to the
123
+ entire whole, and thus to each and every part regardless of who wrote it.
124
+ Thus, it is not the intent of this section to claim rights or contest
125
+ your rights to work written entirely by you; rather, the intent is to
126
+ exercise the right to control the distribution of derivative or
127
+ collective works based on the Program.
128
+
129
+ In addition, mere aggregation of another work not based on the Program
130
+ with the Program (or with a work based on the Program) on a volume of
131
+ a storage or distribution medium does not bring the other work under
132
+ the scope of this License.
133
+
134
+ 3. You may copy and distribute the Program (or a work based on it,
135
+ under Section 2) in object code or executable form under the terms of
136
+ Sections 1 and 2 above provided that you also do one of the following:
137
+
138
+ a) Accompany it with the complete corresponding machine-readable
139
+ source code, which must be distributed under the terms of Sections
140
+ 1 and 2 above on a medium customarily used for software interchange; or,
141
+
142
+ b) Accompany it with a written offer, valid for at least three
143
+ years, to give any third party, for a charge no more than your
144
+ cost of physically performing source distribution, a complete
145
+ machine-readable copy of the corresponding source code, to be
146
+ distributed under the terms of Sections 1 and 2 above on a medium
147
+ customarily used for software interchange; or,
148
+
149
+ c) Accompany it with the information you received as to the offer
150
+ to distribute corresponding source code. (This alternative is
151
+ allowed only for noncommercial distribution and only if you
152
+ received the program in object code or executable form with such
153
+ an offer, in accord with Subsection b above.)
154
+
155
+ The source code for a work means the preferred form of the work for
156
+ making modifications to it. For an executable work, complete source
157
+ code means all the source code for all modules it contains, plus any
158
+ associated interface definition files, plus the scripts used to
159
+ control compilation and installation of the executable. However, as a
160
+ special exception, the source code distributed need not include
161
+ anything that is normally distributed (in either source or binary
162
+ form) with the major components (compiler, kernel, and so on) of the
163
+ operating system on which the executable runs, unless that component
164
+ itself accompanies the executable.
165
+
166
+ If distribution of executable or object code is made by offering
167
+ access to copy from a designated place, then offering equivalent
168
+ access to copy the source code from the same place counts as
169
+ distribution of the source code, even though third parties are not
170
+ compelled to copy the source along with the object code.
171
+
172
+ 4. You may not copy, modify, sublicense, or distribute the Program
173
+ except as expressly provided under this License. Any attempt
174
+ otherwise to copy, modify, sublicense or distribute the Program is
175
+ void, and will automatically terminate your rights under this License.
176
+ However, parties who have received copies, or rights, from you under
177
+ this License will not have their licenses terminated so long as such
178
+ parties remain in full compliance.
179
+
180
+ 5. You are not required to accept this License, since you have not
181
+ signed it. However, nothing else grants you permission to modify or
182
+ distribute the Program or its derivative works. These actions are
183
+ prohibited by law if you do not accept this License. Therefore, by
184
+ modifying or distributing the Program (or any work based on the
185
+ Program), you indicate your acceptance of this License to do so, and
186
+ all its terms and conditions for copying, distributing or modifying
187
+ the Program or works based on it.
188
+
189
+ 6. Each time you redistribute the Program (or any work based on the
190
+ Program), the recipient automatically receives a license from the
191
+ original licensor to copy, distribute or modify the Program subject to
192
+ these terms and conditions. You may not impose any further
193
+ restrictions on the recipients' exercise of the rights granted herein.
194
+ You are not responsible for enforcing compliance by third parties to
195
+ this License.
196
+
197
+ 7. If, as a consequence of a court judgment or allegation of patent
198
+ infringement or for any other reason (not limited to patent issues),
199
+ conditions are imposed on you (whether by court order, agreement or
200
+ otherwise) that contradict the conditions of this License, they do not
201
+ excuse you from the conditions of this License. If you cannot
202
+ distribute so as to satisfy simultaneously your obligations under this
203
+ License and any other pertinent obligations, then as a consequence you
204
+ may not distribute the Program at all. For example, if a patent
205
+ license would not permit royalty-free redistribution of the Program by
206
+ all those who receive copies directly or indirectly through you, then
207
+ the only way you could satisfy both it and this License would be to
208
+ refrain entirely from distribution of the Program.
209
+
210
+ If any portion of this section is held invalid or unenforceable under
211
+ any particular circumstance, the balance of the section is intended to
212
+ apply and the section as a whole is intended to apply in other
213
+ circumstances.
214
+
215
+ It is not the purpose of this section to induce you to infringe any
216
+ patents or other property right claims or to contest validity of any
217
+ such claims; this section has the sole purpose of protecting the
218
+ integrity of the free software distribution system, which is
219
+ implemented by public license practices. Many people have made
220
+ generous contributions to the wide range of software distributed
221
+ through that system in reliance on consistent application of that
222
+ system; it is up to the author/donor to decide if he or she is willing
223
+ to distribute software through any other system and a licensee cannot
224
+ impose that choice.
225
+
226
+ This section is intended to make thoroughly clear what is believed to
227
+ be a consequence of the rest of this License.
228
+
229
+ 8. If the distribution and/or use of the Program is restricted in
230
+ certain countries either by patents or by copyrighted interfaces, the
231
+ original copyright holder who places the Program under this License
232
+ may add an explicit geographical distribution limitation excluding
233
+ those countries, so that distribution is permitted only in or among
234
+ countries not thus excluded. In such case, this License incorporates
235
+ the limitation as if written in the body of this License.
236
+
237
+ 9. The Free Software Foundation may publish revised and/or new versions
238
+ of the General Public License from time to time. Such new versions will
239
+ be similar in spirit to the present version, but may differ in detail to
240
+ address new problems or concerns.
241
+
242
+ Each version is given a distinguishing version number. If the Program
243
+ specifies a version number of this License which applies to it and "any
244
+ later version", you have the option of following the terms and conditions
245
+ either of that version or of any later version published by the Free
246
+ Software Foundation. If the Program does not specify a version number of
247
+ this License, you may choose any version ever published by the Free Software
248
+ Foundation.
249
+
250
+ 10. If you wish to incorporate parts of the Program into other free
251
+ programs whose distribution conditions are different, write to the author
252
+ to ask for permission. For software which is copyrighted by the Free
253
+ Software Foundation, write to the Free Software Foundation; we sometimes
254
+ make exceptions for this. Our decision will be guided by the two goals
255
+ of preserving the free status of all derivatives of our free software and
256
+ of promoting the sharing and reuse of software generally.
257
+
258
+ NO WARRANTY
259
+
260
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261
+ FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262
+ OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263
+ PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264
+ OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266
+ TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267
+ PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268
+ REPAIR OR CORRECTION.
269
+
270
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271
+ WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272
+ REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273
+ INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274
+ OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275
+ TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276
+ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277
+ PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278
+ POSSIBILITY OF SUCH DAMAGES.
279
+
280
+ END OF TERMS AND CONDITIONS
281
+
readme.txt CHANGED
@@ -1,48 +1,58 @@
1
- === Tumblr Importer ===
2
- Contributors: Otto42, wordpressdotorg, dd32, westi
3
- Tags: tumblr, import
4
- Requires at least: 3.2
5
- Tested up to: 3.4
6
- Stable tag: trunk
7
-
8
- == Description ==
9
-
10
- Imports a Tumblr blog into a WordPress blog.
11
-
12
- * Correctly handles post formats
13
- * WP-Cron based background importing: start it up, then come back later to see how far it's gotten
14
- * Duplicate checking, will not create duplicate imported posts
15
- * Imports posts, drafts, and pages
16
- * Media Sideloading (for audio, video, and image posts)
17
-
18
- == Installation ==
19
-
20
- 1. Upload the files to the `/wp-content/plugins/tumblr-importer/` directory.
21
- 1. Activate the plugin through the 'Plugins' menu in WordPress.
22
- 1. Go to Tools->Import and use the new importer.
23
-
24
- == Upgrade Notice ==
25
-
26
- == Changelog ==
27
- = 0.5 =
28
- * Fix edge cases for tumblr photos where tumblr isn't returning expected headers for filenames
29
-
30
- = 0.4 =
31
- * Map multi-image posts to Gallery post format
32
- * Import Tags
33
- * Import Media to server (Images, Audio, Custom uploaded Video's)
34
- * Set the date on Media imports for easier management
35
-
36
- = 0.3 =
37
- * Handle multi-image posts
38
- * Handle question/answer posts
39
- * Handle video posts somewhat better
40
- * Speedup (reduce importer delay from 3 minutes to 1 minute)
41
-
42
- = 0.2 =
43
- * The audio, video, and image formats no longer use the caption for the titles. Tumblr seems to facilitate putting all sorts of crazy stuff into the caption fields as part of their reblogging system. So instead, these types of posts will have no titles at all. Sorry, but Tumblr simply doesn't have any sort of title fields here to work with, and no data that can be used to "create" a title for them.
44
- * Minor debug error cleanup.
45
- * Sideloading now done on drafts and pages as well.
46
-
47
- = 0.1 =
48
- * First version, not meant to be used except for testing.
 
 
 
 
 
 
 
 
 
 
1
+ === Tumblr Importer ===
2
+ 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
+
10
+ == Description ==
11
+
12
+ Imports a Tumblr blog into a WordPress blog.
13
+
14
+ * Correctly handles post formats
15
+ * Background importing: start it up, then come back later to see how far it's gotten
16
+ * Duplicate checking, will not create duplicate imported posts
17
+ * Imports posts, drafts, and pages
18
+ * Media Side loading (for audio, video, and image posts)
19
+
20
+ == Installation ==
21
+
22
+ 1. Upload the files to the `/wp-content/plugins/tumblr-importer/` directory.
23
+ 1. Activate the plugin through the 'Plugins' menu in WordPress.
24
+ 1. Go to Tools->Import and use the new importer.
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
32
+ * Improved author selection logic on single author blogs
33
+ * Auto refreshing to show import progress and give clearer feedback
34
+ * Improves import videos from Tumble - enable auto-embedding for for content.
35
+ * Block imports from Tumblr sites with mapped domains enabled because they don't work well - you have to temporarily disable the mapping.
36
+
37
+ = 0.5 =
38
+ * Fix edge cases for tumblr photos where tumblr isn't returning expected headers for filenames
39
+
40
+ = 0.4 =
41
+ * Map multi-image posts to Gallery post format
42
+ * Import Tags
43
+ * Import Media to server (Images, Audio, Custom uploaded Video's)
44
+ * Set the date on Media imports for easier management
45
+
46
+ = 0.3 =
47
+ * Handle multi-image posts
48
+ * Handle question/answer posts
49
+ * Handle video posts somewhat better
50
+ * Speedup (reduce importer delay from 3 minutes to 1 minute)
51
+
52
+ = 0.2 =
53
+ * The audio, video, and image formats no longer use the caption for the titles. Tumblr seems to facilitate putting all sorts of crazy stuff into the caption fields as part of their reblogging system. So instead, these types of posts will have no titles at all. Sorry, but Tumblr simply doesn't have any sort of title fields here to work with, and no data that can be used to "create" a title for them.
54
+ * Minor debug error cleanup.
55
+ * Sideloading now done on drafts and pages as well.
56
+
57
+ = 0.1 =
58
+ * First version, not meant to be used except for testing.
tumblr-importer.php CHANGED
@@ -1,787 +1,887 @@
1
- <?php
2
- /*
3
- Plugin Name: Tumblr Importer
4
- 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.5
9
- License: GPL v2 - http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
10
- */
11
-
12
- if ( !defined('WP_LOAD_IMPORTERS') && !defined('DOING_CRON') )
13
- return;
14
-
15
- require_once ABSPATH . 'wp-admin/includes/import.php';
16
- require_once ABSPATH . 'wp-admin/includes/admin.php';
17
-
18
- require_once 'class-wp-importer-cron.php';
19
-
20
- /**
21
- * Tumblr Importer Initialisation routines
22
- *
23
- * @package WordPress
24
- * @subpackage Importer
25
- */
26
- function tumblr_importer_init() {
27
- global $tumblr_import;
28
- load_plugin_textdomain( 'tumblr-importer', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' );
29
-
30
- $tumblr_import = new Tumblr_Import();
31
- register_importer('tumblr', __('Tumblr', 'tumblr-importer'), __('Import posts from a Tumblr blog.', 'tumblr-importer'), array ($tumblr_import, 'start'));
32
- if ( !defined('TUMBLR_MAX_IMPORT') )
33
- define ('TUMBLR_MAX_IMPORT', 20);
34
- }
35
- add_action( 'init', 'tumblr_importer_init' );
36
-
37
- /**
38
- * Tumblr Importer
39
- *
40
- * @package WordPress
41
- * @subpackage Importer
42
- */
43
- if ( class_exists( 'WP_Importer_Cron' ) ) {
44
- class Tumblr_Import extends WP_Importer_Cron {
45
-
46
- /**
47
- * Constructor
48
- */
49
- function __construct() {
50
- parent::__construct();
51
- }
52
-
53
- // Figures out what to do, then does it.
54
- function start() {
55
- if ( isset($_POST['restart']) )
56
- $this->restart();
57
-
58
- if ( !isset($this->error) ) $this->error = null;
59
-
60
- if ( isset( $_POST['email'] ) && isset( $_POST['password'] ) ) {
61
- $this->check_credentials();
62
- }
63
-
64
- if ( isset( $_POST['blogurl'] ) ) {
65
- $this->start_blog_import();
66
- }
67
-
68
- if ( isset( $this->blogs ) ) {
69
- $this->show_blogs($this->error);
70
- } else {
71
- $this->greet($this->error);
72
- }
73
-
74
- unset ($this->error);
75
-
76
- if ( !isset($_POST['restart']) ) $saved = $this->save_vars();
77
-
78
- if ( $saved && !isset($_GET['noheader']) ) {
79
- ?>
80
- <div class='wrap'>
81
- <h2><?php _e('Restart', 'tumblr-importer'); ?></h2>
82
- <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>
83
- <p><?php _e('Note: This will stop any import currently in progress.', 'tumblr-importer'); ?></p>
84
- <form method='post' action='?import=tumblr&amp;noheader=true'>
85
- <p class='submit' style='text-align:left;'>
86
- <input type='submit' class='button' value='<?php esc_attr_e('Clear account information', 'tumblr-importer'); ?>' name='restart' />
87
- </p>
88
- </form>
89
- </div>
90
- <?php
91
- }
92
- }
93
-
94
- function greet($error=null) {
95
-
96
- if ( !empty( $error ) ) echo "<div class='error'>{$error}</div>";
97
- ?>
98
-
99
- <div class='wrap'><?php echo screen_icon(); ?>
100
- <h2><?php _e('Import Tumblr', 'tumblr-importer'); ?></h2>
101
- <p><?php _e('Howdy! This importer allows you to import posts from your Tumblr account into your WordPress site.', 'tumblr-importer'); ?></p>
102
- <p><?php _e('First, you need to do is provide your email and password for Tumblr, so that WordPress can access your account.', 'tumblr-importer'); ?></p>
103
- <form action='?import=tumblr' method='post'>
104
- <?php wp_nonce_field( 'tumblr-import' ) ?>
105
- <table class="form-table">
106
- <tr>
107
- <th scope="row"><label for='email'><?php _e('Email:','tumblr-importer'); ?></label></label></th>
108
- <td><input type='text' class="regular-text" name='email' value='<?php if (isset($this->email)) echo esc_attr($this->email); ?>' /></td>
109
- </tr>
110
- <tr>
111
- <th scope="row"><label for='email'><?php _e('Password:','tumblr-importer'); ?></label></label></th>
112
- <td><input type='password' class="regular-text" name='password' value='<?php if (isset($this->password)) echo esc_attr($this->password); ?>' /></td>
113
- </tr>
114
- </table>
115
- <p class='submit'>
116
- <input type='submit' class='button' value="<?php _e('Connect to Tumblr','tumblr-importer'); ?>" />
117
- </p>
118
- </form>
119
- </div>
120
- <?php
121
- }
122
-
123
- function check_credentials() {
124
- check_admin_referer( 'tumblr-import' );
125
-
126
- $this->email = $_POST['email'];
127
- $this->password = $_POST['password'];
128
-
129
- if ( !is_email( $_POST['email'] ) ) {
130
- $error = __("This doesn't appear to be a valid email address. Please check it and try again.",'tumblr-importer');
131
- $this->error = $error;
132
- }
133
-
134
- $blogs = $this->get_blogs($this->email, $this->password);
135
- if ( is_wp_error ($blogs) ) {
136
- $this->error = $blogs->get_error_message();
137
- } else {
138
- $this->blogs = $blogs;
139
- }
140
- }
141
-
142
- function show_blogs($error=null) {
143
-
144
- if ( !empty( $error ) ) echo "<div class='error'>{$error}</div>";
145
- ?>
146
- <div class='wrap'><?php echo screen_icon(); ?>
147
- <h2><?php _e('Import Tumblr', 'tumblr-importer'); ?></h2>
148
- <p><?php _e('Tumblr does not have such a concept as "author", even on multi-author blogs. Therefore you will need to select which WordPress user will be listed as the author of the imported posts.','tumblr-importer'); ?></p>
149
- <p><a href="?import=tumblr"><?php _e('Refresh view','tumblr-importer'); ?></a></p>
150
- <table class="widefat" cellspacing="0"><thead>
151
- <tr>
152
- <th><?php _e('Tumblr Blog','tumblr-importer'); ?></th>
153
- <th><?php _e('URL','tumblr-importer'); ?></th>
154
- <th><?php _e('Posts Imported','tumblr-importer'); ?></th>
155
- <th><?php _e('Drafts Imported','tumblr-importer'); ?></th>
156
- <!--<th><?php _e('Queued Imported','tumblr-importer'); ?></th>-->
157
- <th><?php _e('Pages Imported','tumblr-importer'); ?></th>
158
- <th><?php _e('Author Selection','tumblr-importer'); ?></th>
159
- <th><?php _e('Action','tumblr-importer'); ?></th>
160
- </tr></thead>
161
- <tbody>
162
- <?php
163
- $style = '';
164
- foreach ($this->blogs as $blog) {
165
- $url = $blog['url'];
166
- $style = ( 'alternate' == $style ) ? '' : 'alternate';
167
- if ( !isset( $this->blog[$url] ) ) {
168
- $this->blog[$url]['posts_complete'] = 0;
169
- $this->blog[$url]['drafts_complete'] = 0;
170
- $this->blog[$url]['queued_complete'] = 0;
171
- $this->blog[$url]['pages_complete'] = 0;
172
- $this->blog[$url]['total_posts'] = $blog['posts'];
173
- $this->blog[$url]['total_drafts'] = $blog['drafts'];
174
- $this->blog[$url]['total_queued'] = $blog['queued'];
175
- $this->blog[$url]['name'] = $blog['name'];
176
- }
177
-
178
- if ( empty( $this->blog[$url]['progress'] ) ) {
179
- $submit = "<input type='submit' value='". __('Import this blog','tumblr-importer') ."' />";
180
- } else if ( $this->blog[$url]['progress'] == 'finish' ) {
181
- $submit = "<input type='button' disabled='disabled' value='". __('Finished!','tumblr-importer') ."' />";
182
- } else {
183
- $submit = "<input type='button' disabled='disabled' value='". __('In Progress','tumblr-importer') ."' />";
184
- }
185
- ?>
186
- <tr class="<?php echo $style; ?>">
187
- <form action='?import=tumblr' method='post'>
188
- <?php wp_nonce_field( 'tumblr-import' ); ?>
189
- <input type='hidden' name='blogurl' value='<?php echo esc_attr($blog['url']); ?>' />
190
-
191
- <td><?php echo esc_html($blog['title']); ?></td>
192
- <td><?php echo esc_html($blog['url']); ?></td>
193
- <td><?php echo $this->blog[$url]['posts_complete']; ?></td>
194
- <td><?php echo $this->blog[$url]['drafts_complete']; ?></td>
195
- <!--<td><?php echo $this->blog[$url]['queued_complete']; ?></td>-->
196
- <td><?php echo $this->blog[$url]['pages_complete']; ?></td>
197
- <td><?php wp_dropdown_users( array('who' => 'authors', 'name' => 'post_author' ) ); ?></td>
198
- <td><?php echo $submit; ?></td>
199
- </form>
200
- </tr>
201
- <?php
202
- }
203
- ?>
204
- </tbody>
205
- </table>
206
- <p><?php _e("Because Tumblr's servers are often overloaded, the importing process happens in the background. Thus, you will not see immediate results here. Come back to this page later to check on the importer's progress.",'tumblr-importer'); ?></p>
207
- </div>
208
- <?php
209
- }
210
-
211
- function start_blog_import() {
212
- check_admin_referer( 'tumblr-import' );
213
-
214
- $url = $_POST['blogurl'];
215
-
216
- if ( !isset( $this->blog[$url] ) ) {
217
- $this->error = __('The specified blog cannot be found.', 'tumblr-importer');
218
- return;
219
- }
220
-
221
- if ( !empty($this->blog[$url]['progress']) ) {
222
- $this->error = __('This blog is currently being imported.', 'tumblr-importer');
223
- return;
224
- }
225
-
226
- $this->blog[$url]['progress'] = 'start';
227
- $this->blog[$url]['post_author'] = (int) $_POST['post_author'];
228
-
229
- $this->schedule_import_job( 'do_blog_import', array($url) );
230
- }
231
-
232
- function restart() {
233
- delete_option(get_class($this));
234
- wp_redirect('?import=tumblr');
235
- }
236
-
237
- function do_blog_import($url) {
238
-
239
- // default to the done state
240
- $done = true;
241
-
242
- $this->error=null;
243
-
244
- if ( !empty( $this->blog[$url]['progress'] ) ) {
245
- $done = false;
246
- do {
247
- switch ($this->blog[$url]['progress']) {
248
- case 'start':
249
- case 'posts':
250
- $this->do_posts_import($url);
251
- break;
252
- case 'drafts':
253
- $this->do_drafts_import($url);
254
- break;
255
- case 'queued':
256
- // TODO Tumblr's API is broken for queued posts
257
- $this->blog[$url]['progress'] = 'pages';
258
- //$this->do_queued_import($url);
259
- break;
260
- case 'pages':
261
- $this->do_pages_import($url);
262
- break;
263
- case 'finish':
264
- default:
265
- $done = true;
266
- break;
267
- }
268
- $this->save_vars();
269
- } while ( empty($this->error) && !$done && $this->have_time() );
270
- }
271
-
272
- return $done;
273
- }
274
-
275
- function do_posts_import($url) {
276
- $start = $this->blog[$url]['posts_complete'];
277
- $total = $this->blog[$url]['total_posts'];
278
-
279
- // check for posts completion
280
- if ( $start == $total ) {
281
- $this->blog[$url]['progress'] = 'drafts';
282
- return;
283
- }
284
-
285
- // get the already imported posts to prevent dupes
286
- $dupes = $this->get_imported_posts( 'tumblr', $this->blog[$url]['name'] );
287
-
288
- if ($this->blog[$url]['posts_complete'] + TUMBLR_MAX_IMPORT > $total) $count = $total - $start;
289
- else $count = TUMBLR_MAX_IMPORT;
290
-
291
- $imported_posts = $this->fetch_posts($url, $start, $count, $this->email, $this->password );
292
-
293
- if ( empty($imported_posts) ) {
294
- $this->error = __('Problem communicating with Tumblr, retrying later','tumblr-importer');
295
- return;
296
- }
297
-
298
- if ( is_array($imported_posts) && !empty($imported_posts) ) {
299
- reset($imported_posts);
300
- $post = current($imported_posts);
301
- do {
302
- // skip dupes
303
- if ( !empty( $dupes[$post['tumblr_url']] ) ) {
304
- $this->blog[$url]['posts_complete']++;
305
- $this->save_vars();
306
- continue;
307
- }
308
-
309
- if ( isset( $post['private'] ) ) $post['post_status'] = 'private';
310
- else $post['post_status']='publish';
311
-
312
- $post['post_author'] = $this->blog[$url]['post_author'];
313
-
314
- if ( empty($post['post_title']) ) {
315
- // for empty titles, Attempt to use 100char of the content
316
- $content_excerpt = wp_html_excerpt($post['post_content'], 100);
317
- if ( ! empty($content_excerpt) ) {
318
- $post['post_title'] = $content_excerpt;
319
- // And failing the content, use the slug.
320
- } elseif ( ! empty($post['post_name']) ) {
321
- $post['post_title'] = $post['post_name'];
322
- }
323
- }
324
-
325
- $id = wp_insert_post( $post );
326
-
327
- if ( !is_wp_error( $id ) ) {
328
- $post['ID'] = $id; // Allows for the media importing to wp_update_post()
329
- if ( isset( $post['format'] ) ) set_post_format($id, $post['format']);
330
-
331
- // @todo: Add basename of the permalink as a 404 redirect handler for when a custom domain has been brought accross
332
- add_post_meta( $id, 'tumblr_'.$this->blog[$url]['name'].'_permalink', $post['tumblr_url'] );
333
- add_post_meta( $id, 'tumblr_'.$this->blog[$url]['name'].'_id', $post['tumblr_id'] );
334
- $import_result = $this->handle_sideload($post);
335
-
336
- // Handle failed imports.. If empty content and failed to import media..
337
- if ( is_wp_error($import_result) ) {
338
- if ( empty($post['post_content']) ) {
339
- wp_delete_post($id, true);
340
- }
341
- }
342
- }
343
-
344
- $this->blog[$url]['posts_complete']++;
345
- $this->save_vars();
346
-
347
- } while ( false != ($post = next($imported_posts) ) && $this->have_time() );
348
- }
349
- }
350
-
351
- function do_drafts_import($url) {
352
- $start = $this->blog[$url]['drafts_complete'];
353
- $total = $this->blog[$url]['total_drafts'];
354
-
355
- // check for posts completion
356
- if ( $start == $total ) {
357
- $this->blog[$url]['progress'] = 'queued';
358
- return;
359
- }
360
-
361
- // get the already imported posts to prevent dupes
362
- $dupes = $this->get_imported_posts( 'tumblr', $this->blog[$url]['name'] );
363
-
364
- if ($this->blog[$url]['posts_complete'] + TUMBLR_MAX_IMPORT > $total) $count = $total - $start;
365
- else $count = TUMBLR_MAX_IMPORT;
366
-
367
- $imported_posts = $this->fetch_posts($url, $start, $count, $this->email, $this->password, 'draft' );
368
-
369
- if ( empty($imported_posts) ) {
370
- $this->error = __('Problem communicating with Tumblr, retrying later','tumblr-importer');
371
- return;
372
- }
373
-
374
- if ( is_array($imported_posts) && !empty($imported_posts) ) {
375
- reset($imported_posts);
376
- $post = current($imported_posts);
377
- do {
378
- // skip dupes
379
- if ( !empty( $dupes[$post['tumblr_url']] ) ) {
380
- $this->blog[$url]['drafts_complete']++;
381
- $this->save_vars();
382
- continue;
383
- }
384
-
385
- $post['post_status'] = 'draft';
386
- $post['post_author'] = $this->blog[$url]['post_author'];
387
-
388
- $id = wp_insert_post( $post );
389
- if ( !is_wp_error( $id ) ) {
390
- $post['ID'] = $id;
391
- if ( isset( $post['format'] ) ) set_post_format($id, $post['format']);
392
-
393
- add_post_meta( $id, 'tumblr_'.$this->blog[$url]['name'].'_permalink', $post['tumblr_url'] );
394
- add_post_meta( $id, 'tumblr_'.$this->blog[$url]['name'].'_id', $post['tumblr_id'] );
395
-
396
- $this->handle_sideload($post);
397
- }
398
-
399
- $this->blog[$url]['drafts_complete']++;
400
- $this->save_vars();
401
- } while ( false != ($post = next($imported_posts) ) && $this->have_time() );
402
- }
403
- }
404
-
405
- function do_pages_import($url) {
406
- $start = $this->blog[$url]['pages_complete'];
407
-
408
- // get the already imported posts to prevent dupes
409
- $dupes = $this->get_imported_posts( 'tumblr', $this->blog[$url]['name'] );
410
-
411
- $imported_pages = $this->fetch_pages($url, $this->email, $this->password );
412
-
413
- if ( empty($imported_pages) ) {
414
- $this->error = __('Problem communicating with Tumblr, retrying later','tumblr-importer');
415
- return;
416
- }
417
-
418
- if ( is_array($imported_pages) && !empty($imported_pages) ) {
419
- reset($imported_pages);
420
- $post = current($imported_pages);
421
- do {
422
- // skip dupes
423
- if ( !empty( $dupes[$post['tumblr_url']] ) ) {
424
- continue;
425
- }
426
-
427
- $post['post_type'] = 'page';
428
- $post['post_status'] = 'publish';
429
- $post['post_author'] = $this->blog[$url]['post_author'];
430
-
431
- $id = wp_insert_post( $post );
432
- if ( !is_wp_error( $id ) ) {
433
- add_post_meta( $id, 'tumblr_'.$this->blog[$url]['name'].'_permalink', $post['tumblr_url'] );
434
- $post['ID'] = $id;
435
- $this->handle_sideload($post);
436
- }
437
-
438
- $this->blog[$url]['pages_complete']++;
439
- $this->save_vars();
440
- } while ( false != ($post = next($imported_pages) ) );
441
- }
442
- $this->blog[$url]['progress'] = 'finish';
443
- }
444
-
445
- function handle_sideload_import($post, $source, $description = '', $filename = false) {
446
- // Make a HEAD request to get the filename:
447
- if ( empty($filename) ) {
448
- $head = wp_remote_request( $source, array('method' => 'HEAD') );
449
- if ( !empty($head['headers']['location']) ) {
450
- $source = $head['headers']['location'];
451
- $filename = preg_replace('!\?.*!', '', basename($source) ); // Strip off the Query vars
452
- }
453
- }
454
-
455
- // still empty? Darned inconsistent tumblr...
456
- if ( empty($filename) ) {
457
- $path = parse_url($source,PHP_URL_PATH);
458
- $filename = basename($path);
459
- }
460
-
461
- // Download file to temp location
462
- $tmp = download_url( $source );
463
- if ( is_wp_error($tmp) )
464
- return $tmp;
465
-
466
- $file_array['name'] = !empty($filename) ? $filename : basename($tmp);
467
- $file_array['tmp_name'] = $tmp;
468
- // do the validation and storage stuff
469
- $id = media_handle_sideload( $file_array, $post['ID'], $description, array( 'post_excerpt' => $description ) );
470
-
471
- if ( $id && ! is_wp_error($id) ) {
472
- // Update the date/time on the attachment to that of the Tumblr post.
473
- $attachment = get_post($id, ARRAY_A);
474
- foreach ( array('post_date', 'post_date_gmt', 'post_modified', 'post_modified_gmt') as $field ) {
475
- if ( isset($post[ $field]) )
476
- $attachment[ $field ] = $post[ $field ];
477
- }
478
- wp_update_post($attachment);
479
- }
480
-
481
- // If error storing permanently, unlink
482
- if ( is_wp_error($id) )
483
- @unlink($file_array['tmp_name']);
484
- return $id;
485
- }
486
-
487
- function handle_sideload($post) {
488
-
489
- if ( empty( $post['format'] ) )
490
- return; // Nothing to import.
491
-
492
- switch ( $post['format'] ) {
493
- case 'gallery':
494
- if ( !empty( $post['gallery'] ) ) {
495
- foreach ( $post['gallery'] as $i => $photo ) {
496
- $id = $this->handle_sideload_import( $post, (string)$photo['src'], (string)$photo['caption']);
497
- if ( is_wp_error($id) )
498
- return $id;
499
- }
500
- $post['post_content'] = "[gallery]\n" . $post['post_content'];
501
- wp_update_post($post);
502
- break; // If we processed a gallery, break, otherwise let it fall through to the Image handler
503
- }
504
-
505
- case 'image':
506
- if ( isset( $post['media']['src'] ) ) {
507
- $id = $this->handle_sideload_import( $post, (string)$post['media']['src'], (string)$post['post_title']);
508
- if ( is_wp_error($id) )
509
- return $id;
510
-
511
- $link = !empty($post['media']['link']) ? $post['media']['link'] : null;
512
- // image_send_to_editor has a filter to wrap in a shortcode.
513
- $post['post_content'] = get_image_send_to_editor($id, (string)$post['post_title'], (string)$post['post_title'], 'none', $link, true, 'large' );
514
- //$post['post_content'] .= "\n" . $post['post_content']; // the [caption] shortcode doesn't allow HTML, but this might have some extra markup
515
- wp_update_post($post);
516
- }
517
-
518
- break;
519
-
520
- case 'audio':
521
- // Handle Tumblr Hosted Audio
522
- if ( isset( $post['media']['audio'] ) ) {
523
- $id = $this->handle_sideload_import( $post, (string)$post['media']['audio'], $post['post_title'], (string)$post['media']['filename'] );
524
- if ( is_wp_error($id) )
525
- return $id;
526
- $post['post_content'] = wp_get_attachment_link($id) . "\n" . $post['post_content'];
527
- wp_update_post($post);
528
- }
529
- break;
530
-
531
- case 'video':
532
- // Handle Tumblr hosted video
533
- if ( isset( $post['media']['video'] ) ) {
534
- $id = $this->handle_sideload_import( $post, (string)$post['media']['video'], $post['post_title'], (string)$post['media']['filename'] );
535
- if ( is_wp_error($id) )
536
- return $id;
537
-
538
- // @TODO: Check/change this to embed the imported video.
539
- $post['post_content'] = wp_get_attachment_link($id) . "\n" . $post['post_content'];
540
- wp_update_post($post);
541
- }
542
- // Else, Check to see if the url embedded is handled by oEmbed (or not)
543
- break;
544
- }
545
-
546
- return true; // all processed
547
- }
548
-
549
- /**
550
- * Fetch a list of blogs for a user
551
- *
552
- * @param $email
553
- * @param $password
554
- * @returns array of blog info or a WP_Error
555
- */
556
- function get_blogs($email, $password) {
557
- $url = 'http://www.tumblr.com/api/authenticate';
558
-
559
- $params = array(
560
- 'email'=>$email,
561
- 'password'=>$password,
562
- );
563
- $options = array( 'body' => $params );
564
-
565
- // fetch the list
566
- $out = wp_remote_post($url,$options);
567
- if (wp_remote_retrieve_response_code($out) != 200) {
568
- return new WP_Error('tumblr_error', __('Tumblr replied with an error: ', 'tumblr-importer' ) . wp_remote_retrieve_body($out));
569
- }
570
- $body = wp_remote_retrieve_body($out);
571
-
572
- // parse the XML into something useful
573
- $xml = simplexml_load_string($body);
574
-
575
- $blogs = array();
576
-
577
- if (!isset($xml->tumblelog)) new WP_Error('tumblr_error', __('No blog information found for this account. ', 'tumblr-importer' ));
578
-
579
- $tblogs = $xml->tumblelog;
580
- foreach ($tblogs as $tblog) {
581
- $blog = array();
582
-
583
- if ((string) $tblog['is-admin'] != '1') continue; // we'll only allow admins to import their blogs
584
-
585
- $blog['title'] = (string) $tblog['title'];
586
- $blog['posts'] = (int) $tblog['posts'];
587
- $blog['drafts'] = (int) $tblog['draft-count'];
588
- $blog['queued'] = (int) $tblog['queue-count'];
589
- $blog['avatar'] = (string) $tblog['avatar-url'];
590
- $blog['url'] = (string) $tblog['url'];
591
- $blog['name'] = (string) $tblog['name'];
592
-
593
- $blogs[] = $blog;
594
- }
595
-
596
- return $blogs;
597
- }
598
-
599
- /**
600
- * Fetch a subset of posts from a tumblr blog
601
- *
602
- * @param $start index to start at
603
- * @param $count how many posts to get (max 50)
604
- * @param $state can be empty for normal posts, or "draft", "queue", or "submission" to get those posts
605
- * @returns false on error, array of posts on success
606
- */
607
- function fetch_posts($url, $start=0, $count = 50, $email = null, $password = null, $state = null) {
608
- $url = trailingslashit($url).'api/read';
609
- $params = array(
610
- 'start'=>$start,
611
- 'num'=>$count,
612
- );
613
- if ( !empty($email) && !empty($password) ) {
614
- $params['email'] = $email;
615
- $params['password'] = $password;
616
- }
617
-
618
- if ( !empty($state) ) $params['state'] = $state;
619
-
620
- $options = array( 'body' => $params );
621
-
622
- // fetch the posts
623
- $out = wp_remote_post($url,$options);
624
- if (wp_remote_retrieve_response_code($out) != 200) return false;
625
- $body = wp_remote_retrieve_body($out);
626
-
627
- // parse the XML into something useful
628
- $xml = simplexml_load_string($body);
629
-
630
- if (!isset($xml->posts->post)) return false;
631
-
632
- $tposts = $xml->posts;
633
- $posts = array();
634
- foreach($tposts->post as $tpost) {
635
- $post = array();
636
- $post['tumblr_id'] = (string) $tpost['id'];
637
- $post['tumblr_url'] = (string) $tpost['url-with-slug'];
638
- $post['post_date'] = date( 'Y-m-d H:i:s', strtotime ( (string) $tpost['date'] ) );
639
- $post['post_date_gmt'] = date( 'Y-m-d H:i:s', strtotime ( (string) $tpost['date-gmt'] ) );
640
- $post['post_name'] = (string) $tpost['slug'];
641
- if ( isset($tpost['private']) ) $post['private'] = (string) $tpost['private'];
642
- if ( isset($tpost->{'tag'}) ) {
643
- $post['tags_input'] = array();
644
- foreach ( $tpost->{'tag'} as $tag )
645
- $post['tags_input'][] = rtrim( (string) $tag, ','); // Strip trailing Commas off it too.
646
- }
647
-
648
- // set the various post info for each special format tumblr offers
649
- // TODO reorg this as needed
650
- switch ((string) $tpost['type']) {
651
- case 'photo':
652
- $post['format'] = 'image';
653
- $post['media']['src'] = (string) $tpost->{'photo-url'}[0];
654
- $post['media']['link'] =(string) $tpost->{'photo-link-url'};
655
- $post['media']['width'] = (string) $tpost['width'];
656
- $post['media']['height'] = (string) $tpost['height'];
657
- $post['post_content'] = (string) $tpost->{'photo-caption'};
658
- if ( !empty( $tpost->{'photoset'} ) ) {
659
- $post['format'] = 'gallery';
660
- foreach ( $tpost->{'photoset'}->{'photo'} as $photo ) {
661
- $post['gallery'][] = array (
662
- 'src'=>$photo->{'photo-url'}[0],
663
- 'width'=>$photo['width'],
664
- 'height'=>$photo['height'],
665
- 'caption'=>$photo['caption'],
666
- );
667
- }
668
- }
669
- break;
670
- case 'quote':
671
- $post['format'] = 'quote';
672
- $post['post_content'] = (string) $tpost->{'quote-text'};
673
- $post['post_title'] = (string) $tpost->{'quote-source'};
674
- break;
675
- case 'link':
676
- $post['format'] = 'link';
677
- $linkurl = (string) $tpost->{'link-url'};
678
- $linktext = (string) $tpost->{'link-text'};
679
- $post['post_content'] = "<a href='{$linkurl}'>{$linktext}</a>";
680
- $post['post_title'] = (string) $tpost->{'link-description'};
681
- break;
682
- case 'conversation':
683
- $post['format'] = 'chat';
684
- $post['post_title'] = (string) $tpost->{'conversation-title'};
685
- $post['post_content'] = (string) $tpost->{'conversation-text'};
686
- break;
687
- case 'audio':
688
- $post['format'] = 'audio';
689
- $post['media']['filename'] = basename( (string) $tpost->{'authorized-download-url'} ) . '.mp3';
690
- $post['media']['audio'] = (string) $tpost->{'authorized-download-url'} .'?plead=please-dont-download-this-or-our-lawyers-wont-let-us-host-audio';
691
- $post['post_content'] = (string) $tpost->{'audio-player'} . "\n" . (string) $tpost->{'audio-caption'};
692
- if ( !empty($tpost->{'id3-artist'}) )
693
- $post['post_title'] = $tpost->{'id3-artist'} . ' - ' . $tpost->{'id3-title'};
694
- break;
695
- case 'video':
696
- $post['format'] = 'video';
697
- $post['post_content'] = '';
698
- if ( is_serialized( (string) $tpost->{'video-source'} ) ) {
699
- if ( preg_match('|\'(http://.*video_file.*)\'|U', $tpost->{'video-player'}[0], $matches) ) {
700
- $post['media']['video'] = $matches[1];
701
- $val = unserialize( (string) $tpost->{'video-source'} );
702
- $vidmeta = $val['o1'];
703
- $post['media']['filename'] = basename($post['media']['video']) . '.' . $vidmeta['extension'];
704
- $post['media']['width'] = $vidmeta['width'];
705
- $post['media']['height'] = $vidmeta['height'];
706
- }
707
- } else if ( false !== strpos( (string) $tpost->{'video-source'}, 'embed' ) ) {
708
- if ( preg_match_all('/<embed (.+?)>/', (string) $tpost->{'video-source'}, $matches) ) {
709
- foreach ($matches[1] as $match) {
710
- foreach ( wp_kses_hair($match, array('http')) as $attr)
711
- $embed[$attr['name']] = $attr['value'];
712
- }
713
-
714
- // special case for weird youtube vids
715
- $embed['src'] = preg_replace('|http://www.youtube.com/v/([a-zA-Z0-9_]+).*|i', 'http://www.youtube.com/watch?v=$1', $embed['src']);
716
-
717
- // TODO find other special cases, since tumblr is full of them
718
-
719
- $post['post_content'] = $embed['src'];
720
- }
721
-
722
- } else {
723
- // @todo: See if the video-source is going to be oEmbed'able before adding the flash player
724
- // 1 Seems to be "original" size, with 0 being set otherwise.
725
- $post['post_content'] .= isset($tpost->{'video-player'}[1]) ? $tpost->{'video-player'}[1] : (string) $tpost->{'video-player'}[0];
726
- $post['post_content'] .= (string) $tpost->{'video-source'};
727
- }
728
- $post['post_content'] .= "\n" . (string) $tpost->{'video-caption'};
729
- break;
730
- case 'answer':
731
- $post['post_title'] = (string) $tpost->{'question'};
732
- $post['post_content'] = (string) $tpost->{'answer'};
733
- break;
734
- case 'regular':
735
- default:
736
- $post['post_title'] = (string) $tpost->{'regular-title'};
737
- $post['post_content'] = (string) $tpost->{'regular-body'};
738
- break;
739
- }
740
- $posts[] = $post;
741
- }
742
-
743
- return $posts;
744
- }
745
-
746
- /**
747
- * Fetch the Pages from a tumblr blog
748
- *
749
- * @returns false on error, array of page contents on success
750
- */
751
- function fetch_pages($url, $email = null, $password = null) {
752
- $tumblrurl = trailingslashit($url).'api/pages';
753
- $params = array(
754
- 'email'=>$email,
755
- 'password'=>$password,
756
- );
757
- $options = array( 'body' => $params );
758
-
759
- // fetch the pages
760
- $out = wp_remote_post($tumblrurl,$options);
761
- if (wp_remote_retrieve_response_code($out) != 200) return false;
762
- $body = wp_remote_retrieve_body($out);
763
-
764
- // parse the XML into something useful
765
- $xml = simplexml_load_string($body);
766
-
767
- if (!isset($xml->pages)) return false;
768
-
769
- $tpages = $xml->pages;
770
- $pages = array();
771
- foreach($tpages->page as $tpage) {
772
- if ( !empty($tpage['title']) )
773
- $page['post_title'] = (string) $tpage['title'];
774
- else if (!empty($tpage['link-title']) )
775
- $page['post_title'] = (string) $tpage['link-title'];
776
- else
777
- $page['post_title'] = '';
778
- $page['post_name'] = str_replace( $url, '', (string) $tpage['url'] );
779
- $page['post_content'] = (string) $tpage;
780
- $page['tumblr_url'] = (string) $tpage['url'];
781
- $pages[] = $page;
782
- }
783
-
784
- return $pages;
785
- }
786
- }
787
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Plugin Name: Tumblr Importer
4
+ 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
+
12
+ if ( !defined('WP_LOAD_IMPORTERS') && !defined('DOING_CRON') )
13
+ return;
14
+
15
+ require_once ABSPATH . 'wp-admin/includes/import.php';
16
+ require_once ABSPATH . 'wp-admin/includes/admin.php';
17
+
18
+ require_once 'class-wp-importer-cron.php';
19
+
20
+ /**
21
+ * Tumblr Importer Initialisation routines
22
+ *
23
+ * @package WordPress
24
+ * @subpackage Importer
25
+ */
26
+ function tumblr_importer_init() {
27
+ global $tumblr_import;
28
+ load_plugin_textdomain( 'tumblr-importer', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' );
29
+
30
+ $tumblr_import = new Tumblr_Import();
31
+ register_importer('tumblr', __('Tumblr', 'tumblr-importer'), __('Import posts from a Tumblr blog.', 'tumblr-importer'), array ($tumblr_import, 'start'));
32
+ if ( !defined('TUMBLR_MAX_IMPORT') )
33
+ define ('TUMBLR_MAX_IMPORT', 20);
34
+ }
35
+ add_action( 'init', 'tumblr_importer_init' );
36
+
37
+ /**
38
+ * Tumblr Importer
39
+ *
40
+ * @package WordPress
41
+ * @subpackage Importer
42
+ */
43
+ if ( class_exists( 'WP_Importer_Cron' ) ) {
44
+ class Tumblr_Import extends WP_Importer_Cron {
45
+
46
+ /**
47
+ * Constructor
48
+ */
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
+ }
55
+
56
+ // Figures out what to do, then does it.
57
+ function start() {
58
+ if ( isset($_POST['restart']) )
59
+ $this->restart();
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
+ }
69
+ if ( isset( $this->blogs ) ) {
70
+ $this->show_blogs($this->error);
71
+ } else {
72
+ $this->greet($this->error);
73
+ }
74
+
75
+ unset ($this->error);
76
+
77
+ if ( !isset($_POST['restart']) ) $saved = $this->save_vars();
78
+
79
+ if ( $saved && !isset($_GET['noheader']) ) {
80
+ ?>
81
+ <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>
82
+ <p><?php _e('Note: This will stop any import currently in progress.', 'tumblr-importer'); ?></p>
83
+ <form method='post' action='?import=tumblr&amp;noheader=true'>
84
+ <p class='submit' style='text-align:left;'>
85
+ <input type='submit' class='button' value='<?php esc_attr_e('Clear account information', 'tumblr-importer'); ?>' name='restart' />
86
+ </p>
87
+ </form>
88
+ <?php
89
+ }
90
+ }
91
+
92
+ function greet($error=null) {
93
+
94
+ if ( !empty( $error ) )
95
+ echo "<div class='error'><p>{$error}</p></div>";
96
+ ?>
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'>
115
+ <input type='submit' class='button' value="<?php _e('Connect to Tumblr','tumblr-importer'); ?>" />
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) {
142
+
143
+ if ( !empty( $error ) )
144
+ echo "<div class='error'><p>{$error}</p></div>";
145
+
146
+ $authors = get_users( array('who' => 'authors') );
147
+ ?>
148
+ <div class='wrap'><?php echo screen_icon(); ?>
149
+ <h2><?php _e('Import Tumblr', 'tumblr-importer'); ?></h2>
150
+ <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>
151
+ <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>
152
+ <?php if ( 1 < count( $authors ) ) : ?>
153
+ <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>
154
+ <?php endif; ?>
155
+ <table class="widefat" cellspacing="0"><thead>
156
+ <tr>
157
+ <th><?php _e('Tumblr Blog','tumblr-importer'); ?></th>
158
+ <th><?php _e('URL','tumblr-importer'); ?></th>
159
+ <th><?php _e('Posts Imported','tumblr-importer'); ?></th>
160
+ <th><?php _e('Drafts Imported','tumblr-importer'); ?></th>
161
+ <!--<th><?php _e('Queued Imported','tumblr-importer'); ?></th>-->
162
+ <th><?php _e('Pages Imported','tumblr-importer'); ?></th>
163
+ <th><?php _e('Author','tumblr-importer'); ?></th>
164
+ <th><?php _e('Action/Status','tumblr-importer'); ?></th>
165
+ </tr></thead>
166
+ <tbody>
167
+ <?php
168
+ $style = '';
169
+ $custom_domains = false;
170
+ foreach ($this->blogs as $blog) {
171
+ $url = $blog['url'];
172
+ $style = ( 'alternate' == $style ) ? '' : 'alternate';
173
+ if ( !isset( $this->blog[$url] ) ) {
174
+ $this->blog[$url]['posts_complete'] = 0;
175
+ $this->blog[$url]['drafts_complete'] = 0;
176
+ $this->blog[$url]['queued_complete'] = 0;
177
+ $this->blog[$url]['pages_complete'] = 0;
178
+ $this->blog[$url]['total_posts'] = $blog['posts'];
179
+ $this->blog[$url]['total_drafts'] = $blog['drafts'];
180
+ $this->blog[$url]['total_queued'] = $blog['queued'];
181
+ $this->blog[$url]['name'] = $blog['name'];
182
+ }
183
+
184
+ if ( empty( $this->blog[$url]['progress'] ) ) {
185
+ $submit = "<input type='submit' value='". __('Import this blog','tumblr-importer') ."' />";
186
+ } else if ( $this->blog[$url]['progress'] == 'finish' ) {
187
+ $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>';
188
+ } else {
189
+ $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>';
190
+ // Just a little js page reload to show progress if we're in the in-progress phase of the import.
191
+ $submit .= "<script type='text/javascript'>setTimeout( 'window.location.href = window.location.href', 15000);</script>";
192
+ }
193
+
194
+ // Check to see if this url is a custom domain. The API doesn't play nicely with these
195
+ // (intermittently returns 408 status), so make the user disable the custom domain
196
+ // before importing.
197
+ if ( !preg_match( '|tumblr.com/$|', $url ) ) {
198
+ $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>';
199
+ $custom_domains = true;
200
+ }
201
+
202
+ // Build an author selector / static name depending on number
203
+ if ( 1 == count( $authors ) ) {
204
+ $author_selection = "<input type='hidden' value='{$authors[0]->ID}' name='post_author' />{$authors[0]->display_name}";
205
+ } else {
206
+ $args = array('who' => 'authors', 'name' => 'post_author', 'echo' => false );
207
+ if ( isset( $this->blog[$url]['post_author'] ) )
208
+ $args['selected'] = $this->blog[$url]['post_author'];
209
+ $author_selection = wp_dropdown_users( $args );
210
+ }
211
+ ?>
212
+ <tr class="<?php echo $style; ?>">
213
+ <form action='?import=tumblr' method='post'>
214
+ <?php wp_nonce_field( 'tumblr-import' ); ?>
215
+ <input type='hidden' name='blogurl' value='<?php echo esc_attr($blog['url']); ?>' />
216
+
217
+ <td><?php echo esc_html($blog['title']); ?></td>
218
+ <td><?php echo esc_html($blog['url']); ?></td>
219
+ <td><?php echo $this->blog[$url]['posts_complete'] . ' / ' . $this->blog[$url]['total_posts']; ?></td>
220
+ <td><?php echo $this->blog[$url]['drafts_complete'] . ' / ' . $this->blog[$url]['total_drafts']; ?></td>
221
+ <!--<td><?php echo $this->blog[$url]['queued_complete']; ?></td>-->
222
+ <td><?php echo $this->blog[$url]['pages_complete']; ?></td>
223
+ <td><?php echo $author_selection ?></td>
224
+ <td><?php echo $submit; ?></td>
225
+ </form>
226
+ </tr>
227
+ <?php
228
+ }
229
+ ?>
230
+ </tbody>
231
+ </table>
232
+ <?php if ( $custom_domains ) : ?>
233
+ <p><strong>
234
+ <?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.' ); ?>
235
+ </strong></p>
236
+ <?php endif; ?>
237
+ <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>
238
+ </div>
239
+ <?php
240
+ }
241
+
242
+ function start_blog_import() {
243
+ check_admin_referer( 'tumblr-import' );
244
+ $url = $_POST['blogurl'];
245
+
246
+ if ( !isset( $this->blog[$url] ) ) {
247
+ $this->error = __('The specified blog cannot be found.', 'tumblr-importer');
248
+ return;
249
+ }
250
+
251
+ if ( !empty($this->blog[$url]['progress']) ) {
252
+ $this->error = __('This blog is currently being imported.', 'tumblr-importer');
253
+ return;
254
+ }
255
+
256
+ $this->blog[$url]['progress'] = 'start';
257
+ $this->blog[$url]['post_author'] = (int) $_POST['post_author'];
258
+
259
+ $this->schedule_import_job( 'do_blog_import', array($url) );
260
+ }
261
+
262
+ function restart() {
263
+ delete_option(get_class($this));
264
+ wp_redirect('?import=tumblr');
265
+ }
266
+
267
+ function do_blog_import($url) {
268
+
269
+ // default to the done state
270
+ $done = true;
271
+
272
+ $this->error=null;
273
+
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
+ $this->do_pages_import($url);
292
+ break;
293
+ case 'finish':
294
+ default:
295
+ $done = true;
296
+ break;
297
+ }
298
+ $this->save_vars();
299
+ } while ( empty($this->error) && !$done && $this->have_time() );
300
+ }
301
+
302
+ return $done;
303
+ }
304
+
305
+ function do_posts_import($url) {
306
+ $start = $this->blog[$url]['posts_complete'];
307
+ $total = $this->blog[$url]['total_posts'];
308
+
309
+ // check for posts completion
310
+ if ( $start >= $total ) {
311
+ $this->blog[$url]['progress'] = 'drafts';
312
+ return;
313
+ }
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
+
328
+ if ( is_array($imported_posts) && !empty($imported_posts) ) {
329
+ reset($imported_posts);
330
+ $post = current($imported_posts);
331
+ do {
332
+ // skip dupes
333
+ if ( !empty( $dupes[$post['tumblr_url']] ) ) {
334
+ $this->blog[$url]['posts_complete']++;
335
+ $this->save_vars();
336
+ continue;
337
+ }
338
+
339
+ if ( isset( $post['private'] ) ) $post['post_status'] = 'private';
340
+ else $post['post_status']='publish';
341
+
342
+ $post['post_author'] = $this->blog[$url]['post_author'];
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']);
350
+
351
+ // @todo: Add basename of the permalink as a 404 redirect handler for when a custom domain has been brought accross
352
+ add_post_meta( $id, 'tumblr_'.$this->blog[$url]['name'].'_permalink', $post['tumblr_url'] );
353
+ add_post_meta( $id, 'tumblr_'.$this->blog[$url]['name'].'_id', $post['tumblr_id'] );
354
+
355
+ $import_result = $this->handle_sideload($post);
356
+
357
+ // Handle failed imports.. If empty content and failed to import media..
358
+ if ( is_wp_error($import_result) ) {
359
+ if ( empty($post['post_content']) ) {
360
+ wp_delete_post($id, true);
361
+ }
362
+ }
363
+ }
364
+
365
+ $this->blog[$url]['posts_complete']++;
366
+ $this->save_vars();
367
+
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'];
375
+
376
+ // check for posts completion
377
+ if ( $start >= $total ) {
378
+ $this->blog[$url]['progress'] = 'queued';
379
+ return;
380
+ }
381
+
382
+ // get the already imported posts to prevent dupes
383
+ $dupes = $this->get_imported_posts( 'tumblr', $this->blog[$url]['name'] );
384
+
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) ) {
391
+ $this->error = __('Problem communicating with Tumblr, retrying later','tumblr-importer');
392
+ return;
393
+ }
394
+
395
+ if ( is_array($imported_posts) && !empty($imported_posts) ) {
396
+ reset($imported_posts);
397
+ $post = current($imported_posts);
398
+ do {
399
+ // skip dupes
400
+ if ( !empty( $dupes[$post['tumblr_url']] ) ) {
401
+ $this->blog[$url]['drafts_complete']++;
402
+ $this->save_vars();
403
+ continue;
404
+ }
405
+
406
+ $post['post_status'] = 'draft';
407
+ $post['post_author'] = $this->blog[$url]['post_author'];
408
+
409
+ do_action( 'tumblr_importing_post', $post );
410
+ $id = wp_insert_post( $post );
411
+ if ( !is_wp_error( $id ) ) {
412
+ $post['ID'] = $id;
413
+ if ( isset( $post['format'] ) ) set_post_format($id, $post['format']);
414
+
415
+ add_post_meta( $id, 'tumblr_'.$this->blog[$url]['name'].'_permalink', $post['tumblr_url'] );
416
+ add_post_meta( $id, 'tumblr_'.$this->blog[$url]['name'].'_id', $post['tumblr_id'] );
417
+
418
+ $this->handle_sideload($post);
419
+ }
420
+
421
+ $this->blog[$url]['drafts_complete']++;
422
+ $this->save_vars();
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
+
430
+ // get the already imported posts to prevent dupes
431
+ $dupes = $this->get_imported_posts( 'tumblr', $this->blog[$url]['name'] );
432
+
433
+ $imported_pages = $this->fetch_pages($url, $this->email, $this->password );
434
+
435
+ if ( false === $imported_pages ) {
436
+ $this->error = __('Problem communicating with Tumblr, retrying later','tumblr-importer');
437
+ return;
438
+ }
439
+
440
+ if ( is_array($imported_pages) && !empty($imported_pages) ) {
441
+ reset($imported_pages);
442
+ $post = current($imported_pages);
443
+ do {
444
+ // skip dupes
445
+ if ( !empty( $dupes[$post['tumblr_url']] ) ) {
446
+ continue;
447
+ }
448
+
449
+ $post['post_type'] = 'page';
450
+ $post['post_status'] = 'publish';
451
+ $post['post_author'] = $this->blog[$url]['post_author'];
452
+
453
+ $id = wp_insert_post( $post );
454
+ if ( !is_wp_error( $id ) ) {
455
+ add_post_meta( $id, 'tumblr_'.$this->blog[$url]['name'].'_permalink', $post['tumblr_url'] );
456
+ $post['ID'] = $id;
457
+ $this->handle_sideload($post);
458
+ }
459
+
460
+ $this->blog[$url]['pages_complete']++;
461
+ $this->save_vars();
462
+ } while ( false != ($post = next($imported_pages) ) );
463
+ }
464
+ $this->blog[$url]['progress'] = 'finish';
465
+ }
466
+
467
+ function handle_sideload_import($post, $source, $description = '', $filename = false) {
468
+ // Make a HEAD request to get the filename:
469
+ if ( empty($filename) ) {
470
+ $head = wp_remote_request( $source, array('method' => 'HEAD') );
471
+ if ( !empty($head['headers']['location']) ) {
472
+ $source = $head['headers']['location'];
473
+ $filename = preg_replace('!\?.*!', '', basename($source) ); // Strip off the Query vars
474
+ }
475
+ }
476
+
477
+ // still empty? Darned inconsistent tumblr...
478
+ if ( empty($filename) ) {
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) )
486
+ return $tmp;
487
+
488
+ $file_array['name'] = !empty($filename) ? $filename : basename($tmp);
489
+ $file_array['tmp_name'] = $tmp;
490
+ // do the validation and storage stuff
491
+ $id = media_handle_sideload( $file_array, $post['ID'], $description, array( 'post_excerpt' => $description ) );
492
+
493
+ if ( $id && ! is_wp_error($id) ) {
494
+ // Update the date/time on the attachment to that of the Tumblr post.
495
+ $attachment = get_post($id, ARRAY_A);
496
+ foreach ( array('post_date', 'post_date_gmt', 'post_modified', 'post_modified_gmt') as $field ) {
497
+ if ( isset($post[ $field]) )
498
+ $attachment[ $field ] = $post[ $field ];
499
+ }
500
+ wp_update_post($attachment);
501
+ }
502
+
503
+ // If error storing permanently, unlink
504
+ if ( is_wp_error($id) )
505
+ @unlink($file_array['tmp_name']);
506
+ return $id;
507
+ }
508
+
509
+ function handle_sideload($post) {
510
+
511
+ if ( empty( $post['format'] ) )
512
+ return; // Nothing to import.
513
+
514
+ switch ( $post['format'] ) {
515
+ case 'gallery':
516
+ if ( !empty( $post['gallery'] ) ) {
517
+ foreach ( $post['gallery'] as $i => $photo ) {
518
+ $id = $this->handle_sideload_import( $post, (string)$photo['src'], (string)$photo['caption']);
519
+ if ( is_wp_error($id) )
520
+ return $id;
521
+ }
522
+ $post['post_content'] = "[gallery]\n" . $post['post_content'];
523
+ $post = apply_filters( 'tumblr_importer_format_post', $post );
524
+ do_action( 'tumblr_importer_metadata', $post );
525
+ wp_update_post($post);
526
+ break; // If we processed a gallery, break, otherwise let it fall through to the Image handler
527
+ }
528
+
529
+ case 'image':
530
+ if ( isset( $post['media']['src'] ) ) {
531
+ $id = $this->handle_sideload_import( $post, (string)$post['media']['src'], (string)$post['post_title']);
532
+ if ( is_wp_error($id) )
533
+ return $id;
534
+
535
+ $link = !empty($post['media']['link']) ? $post['media']['link'] : null;
536
+ // image_send_to_editor has a filter to wrap in a shortcode.
537
+ $post_content = $post['post_content'];
538
+ $post['post_content'] = get_image_send_to_editor($id, (string)$post['post_title'], (string)$post['post_title'], 'none', $link, true, 'full' );
539
+ $post['post_content'] .= $post_content;
540
+ $post['meta']['attribution'] = $link;
541
+ $post = apply_filters( 'tumblr_importer_format_post', $post );
542
+ do_action( 'tumblr_importer_metadata', $post );
543
+ //$post['post_content'] .= "\n" . $post['post_content']; // the [caption] shortcode doesn't allow HTML, but this might have some extra markup
544
+ wp_update_post($post);
545
+ }
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'] );
553
+ if ( is_wp_error($id) )
554
+ return $id;
555
+ $post['post_content'] = wp_get_attachment_link($id) . "\n" . $post['post_content'];
556
+ } else {
557
+ // Try to work out a "source" link to display Tumblr-style.
558
+ preg_match( '/(http[^ "<>\']+)/', $post['post_content'], $matches );
559
+ if ( isset( $matches[1] ) ) {
560
+ $url_parts = parse_url( $matches[1] );
561
+ $post['meta']['attribution'] = $url_parts['scheme'] . "://" . $url_parts['host'] . "/";
562
+ }
563
+ }
564
+ $post = apply_filters( 'tumblr_importer_format_post', $post );
565
+ do_action( 'tumblr_importer_metadata', $post );
566
+ wp_update_post($post);
567
+ break;
568
+
569
+ case 'video':
570
+ // Handle Tumblr hosted video
571
+ if ( isset( $post['media']['video'] ) ) {
572
+ $id = $this->handle_sideload_import( $post, (string)$post['media']['video'], $post['post_title'], (string)$post['media']['filename'] );
573
+ if ( is_wp_error($id) )
574
+ return $id;
575
+
576
+ // @TODO: Check/change this to embed the imported video.
577
+ $link = wp_get_attachment_link($id) . "\n" . $post['post_content'];
578
+ $post['post_content'] = $link;
579
+ $post['meta']['attribution'] = $link;
580
+ } else {
581
+ // Try to work out a "source" link to mimic Tumblr's post formatting.
582
+ preg_match( '/(http[^ "<>\']+)/', $post['post_content'], $matches );
583
+ if ( isset( $matches[1] ) ) {
584
+ $url_parts = parse_url( $matches[1] );
585
+ $post['meta']['attribution'] = $url_parts['scheme'] . "://" . $url_parts['host'] . "/";
586
+ }
587
+ }
588
+ $post = apply_filters( 'tumblr_importer_format_post', $post );
589
+ do_action( 'tumblr_importer_metadata', $post );
590
+ wp_update_post($post);
591
+
592
+ // Else, Check to see if the url embedded is handled by oEmbed (or not)
593
+ break;
594
+ }
595
+
596
+ return true; // all processed
597
+ }
598
+
599
+ /**
600
+ * Fetch a list of blogs for a user
601
+ *
602
+ * @param $email
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
+ /**
664
+ * Fetch a subset of posts from a tumblr blog
665
+ *
666
+ * @param $start index to start at
667
+ * @param $count how many posts to get (max 50)
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;
809
+ }
810
+
811
+ return $posts;
812
+ }
813
+
814
+ /**
815
+ * Fetch the Pages from a tumblr blog
816
+ *
817
+ * @returns false on error, array of page contents on success
818
+ */
819
+ function fetch_pages($url, $email = null, $password = null) {
820
+ $tumblrurl = trailingslashit($url).'api/pages';
821
+ $params = array(
822
+ 'email'=>$email,
823
+ 'password'=>$password,
824
+ );
825
+ $options = array( 'body' => $params );
826
+
827
+ // fetch the pages
828
+ $out = wp_remote_post($tumblrurl,$options);
829
+ if (wp_remote_retrieve_response_code($out) != 200) return false;
830
+ $body = wp_remote_retrieve_body($out);
831
+
832
+ // parse the XML into something useful
833
+ $xml = simplexml_load_string($body);
834
+
835
+ if (!isset($xml->pages)) return false;
836
+
837
+ $tpages = $xml->pages;
838
+ $pages = array();
839
+ foreach($tpages->page as $tpage) {
840
+ if ( !empty($tpage['title']) )
841
+ $page['post_title'] = (string) $tpage['title'];
842
+ else if (!empty($tpage['link-title']) )
843
+ $page['post_title'] = (string) $tpage['link-title'];
844
+ else
845
+ $page['post_title'] = '';
846
+ $page['post_name'] = str_replace( $url, '', (string) $tpage['url'] );
847
+ $page['post_content'] = (string) $tpage;
848
+ $page['tumblr_url'] = (string) $tpage['url'];
849
+ $pages[] = $page;
850
+ }
851
+
852
+ return $pages;
853
+ }
854
+
855
+ function filter_format_post( $_post ) {
856
+ if ( isset( $_post['meta']['attribution'] ) ) {
857
+ $attribution = $_post['meta']['attribution'];
858
+ if ( preg_match( '/^http[^ ]+$/', $_post['meta']['attribution'] ) )
859
+ $attribution = sprintf( '<a href="%s">%s</a>', $_post['meta']['attribution'], $_post['meta']['attribution'] );
860
+ $_post['post_content'] .= sprintf( '<div class="attribution">(<span>' . __( 'Source:', 'tumblr-importer' ) . '</span> %s)</div>', $attribution );
861
+ }
862
+
863
+ return $_post;
864
+ }
865
+
866
+ function tumblr_importer_metadata( $_post ) {
867
+ if ( isset( $_post['meta'] ) ) {
868
+ foreach ( $_post['meta'] as $key => $val ) {
869
+ add_post_meta( $_post['ID'], 'tumblr_' . $key, $val );
870
+ }
871
+ }
872
+ }
873
+
874
+ /*
875
+ * When galleries have no caption, the post_content field is empty, which
876
+ * along with empty title and excerpt causes the post not to insert.
877
+ * Here we override the default behavior.
878
+ */
879
+ function filter_allow_empty_content( $maybe_empty, $_post ) {
880
+ if ( 'gallery' == $_post['format'] )
881
+ return false;
882
+
883
+ return $maybe_empty;
884
+ }
885
+
886
+ }
887
+ }