1 | <?php |
---|
2 | /* |
---|
3 | Plugin Name: WP Twitter Importer |
---|
4 | Plugin URI: http://wordpress.org/extend/plugins/wp-twitter-importer/ |
---|
5 | Description: |
---|
6 | Author: wordpressdotorg |
---|
7 | Author URI: http://wordpress.org/ |
---|
8 | Version: 0.1 |
---|
9 | Text Domain: wp-twitter-importer |
---|
10 | License: GPL version 2 or later - http://www.gnu.org/licenses/old-licenses/gpl-2.0.html |
---|
11 | */ |
---|
12 | |
---|
13 | // not sure whether this should be on by default or not |
---|
14 | defined('TWITTER_IMPORTER_AUTOCOMMIT_OFF') or define('TWITTER_IMPORTER_AUTOCOMMIT_OFF', true); |
---|
15 | |
---|
16 | if ( ! defined( 'WP_LOAD_IMPORTERS' ) ) |
---|
17 | return; |
---|
18 | |
---|
19 | /** Display verbose errors */ |
---|
20 | define( 'IMPORT_DEBUG', false ); |
---|
21 | |
---|
22 | // Load Importer API |
---|
23 | require_once ABSPATH . 'wp-admin/includes/import.php'; |
---|
24 | |
---|
25 | if ( ! class_exists( 'WP_Importer' ) ) { |
---|
26 | $class_wp_importer = ABSPATH . 'wp-admin/includes/class-wp-importer.php'; |
---|
27 | if ( file_exists( $class_wp_importer ) ) |
---|
28 | require $class_wp_importer; |
---|
29 | } |
---|
30 | |
---|
31 | if ( class_exists( 'WP_Importer' ) ) { |
---|
32 | class WP_Twitter_Import extends WP_Importer { |
---|
33 | |
---|
34 | /** |
---|
35 | * Display import page title |
---|
36 | */ |
---|
37 | function header() { |
---|
38 | echo '<div class="wrap">'; |
---|
39 | screen_icon(); |
---|
40 | echo '<h2>' . __( 'Import Twitter', 'wp-twitter-importer' ) . '</h2>'; |
---|
41 | |
---|
42 | $updates = get_plugin_updates(); |
---|
43 | $basename = plugin_basename( __FILE__ ); |
---|
44 | if ( isset( $updates[$basename] ) ) { |
---|
45 | $update = $updates[$basename]; |
---|
46 | echo '<div class="error"><p><strong>'; |
---|
47 | printf( __( 'A new version of this importer is available. Please update to version %s to ensure compatibility with newer export files.', 'wp-twitter-importer' ), $update->update->new_version ); |
---|
48 | echo '</strong></p></div>'; |
---|
49 | } |
---|
50 | } |
---|
51 | |
---|
52 | /** |
---|
53 | * Close div.wrap |
---|
54 | */ |
---|
55 | function footer() { |
---|
56 | echo '</div>'; |
---|
57 | } |
---|
58 | |
---|
59 | /** |
---|
60 | * Display introductory text and file upload form |
---|
61 | */ |
---|
62 | function greet() { |
---|
63 | echo '<div class="narrow">'; |
---|
64 | echo '<p>'.__( 'Howdy! Upload your Twitter archive data file and we’ll import the status updates into this site.', 'wp-twitter-importer' ).'</p>'; |
---|
65 | echo '<p>'.__( 'Choose a Twitter archive data (.zip) file to upload, then click Upload file and import.', 'wp-twitter-importer' ).'</p>'; |
---|
66 | wp_import_upload_form( 'admin.php?import=twitter&step=1' ); |
---|
67 | echo '</div>'; |
---|
68 | } |
---|
69 | |
---|
70 | /** |
---|
71 | * Registered callback function for the WordPress Importer |
---|
72 | * |
---|
73 | * Manages the three separate stages of the WXR import process |
---|
74 | */ |
---|
75 | function dispatch() { |
---|
76 | $this->header(); |
---|
77 | |
---|
78 | $step = empty( $_GET['step'] ) ? 0 : (int) $_GET['step']; |
---|
79 | switch ( $step ) { |
---|
80 | case 0: |
---|
81 | $this->greet(); |
---|
82 | break; |
---|
83 | case 1: |
---|
84 | check_admin_referer( 'import-upload' ); |
---|
85 | if ( $working_dir = $this->handle_upload() ) |
---|
86 | $this->import_options( $working_dir ); |
---|
87 | break; |
---|
88 | case 2: |
---|
89 | check_admin_referer( 'import-twitter' ); |
---|
90 | if ( ! empty( $_POST['user'] ) ) { |
---|
91 | $user_id = absint( $_POST['user'] ); |
---|
92 | } elseif ( $this->allow_create_users() ) { |
---|
93 | if ( ! empty($_POST['user_new']) ) { |
---|
94 | $user_id = wp_create_user( $_POST['user_new'], wp_generate_password() ); |
---|
95 | } else { |
---|
96 | $user_json = file_get_contents( $_POST['working_dir'] . '/data/js/user_details.js' ); |
---|
97 | $user_json = preg_replace( '/^[^{]*/', '', $user_json ); |
---|
98 | $user_json = json_decode( $user_json ); |
---|
99 | |
---|
100 | $user_data = array( |
---|
101 | 'user_login' => $user_json->screen_name, |
---|
102 | 'user_pass' => wp_generate_password(), |
---|
103 | 'display_name' => $user_json->full_name, |
---|
104 | ); |
---|
105 | $user_id = wp_insert_user( $user_data ); |
---|
106 | } |
---|
107 | if ( is_wp_error( $user_id ) ) { |
---|
108 | _e( 'Failed to create new user. Their posts will be attributed to the current user.', 'wp-twitter-importer' ); |
---|
109 | if ( defined('IMPORT_DEBUG') && IMPORT_DEBUG ) |
---|
110 | echo ' ' . $user_id->get_error_message(); |
---|
111 | echo '<br />'; |
---|
112 | } |
---|
113 | } |
---|
114 | set_time_limit(0); |
---|
115 | |
---|
116 | $this->import_start(); |
---|
117 | |
---|
118 | $this->parse_files( $_POST['working_dir'], $user_id ); |
---|
119 | |
---|
120 | $this->import_end( $_POST['working_dir'] ); |
---|
121 | break; |
---|
122 | } |
---|
123 | |
---|
124 | $this->footer(); |
---|
125 | } |
---|
126 | |
---|
127 | public function import_start( ) { |
---|
128 | global $wpdb; |
---|
129 | |
---|
130 | wp_suspend_cache_invalidation( true ); |
---|
131 | wp_defer_term_counting( true ); |
---|
132 | wp_defer_comment_counting( true ); |
---|
133 | |
---|
134 | do_action( 'import_start' ); |
---|
135 | |
---|
136 | // force off autocommit for speed |
---|
137 | if ( TWITTER_IMPORTER_AUTOCOMMIT_OFF ) { |
---|
138 | $wpdb->query('SET autocommit = 0'); |
---|
139 | } |
---|
140 | } |
---|
141 | |
---|
142 | /** |
---|
143 | * Performs post-import cleanup of files and the cache |
---|
144 | */ |
---|
145 | public function import_end( $working_dir ) { |
---|
146 | global $wp_filesystem, $wpdb; |
---|
147 | |
---|
148 | if ( TWITTER_IMPORTER_AUTOCOMMIT_OFF ) { |
---|
149 | $wpdb->query('COMMIT'); |
---|
150 | $wpdb->query('SET autocommit = 1'); |
---|
151 | } |
---|
152 | |
---|
153 | WP_Filesystem(); |
---|
154 | $wp_filesystem->delete( $working_dir, true ); |
---|
155 | |
---|
156 | wp_suspend_cache_invalidation( false ); |
---|
157 | |
---|
158 | wp_cache_flush(); |
---|
159 | foreach ( get_taxonomies() as $tax ) { |
---|
160 | delete_option( "{$tax}_children" ); |
---|
161 | _get_term_hierarchy( $tax ); |
---|
162 | } |
---|
163 | |
---|
164 | wp_defer_term_counting( false ); |
---|
165 | wp_defer_comment_counting( false ); |
---|
166 | |
---|
167 | |
---|
168 | echo '<p>' . __( 'All done.', 'wp-twitter-importer' ) . ' <a href="' . admin_url() . '">' . __( 'Have fun!', 'wp-twitter-importer' ) . '</a>' . '</p>'; |
---|
169 | |
---|
170 | do_action( 'import_end' ); |
---|
171 | } |
---|
172 | |
---|
173 | /** |
---|
174 | * Handles the zip upload and initial parsing of the file |
---|
175 | * |
---|
176 | * @return bool False if error uploading or invalid file, true otherwise |
---|
177 | */ |
---|
178 | function handle_upload() { |
---|
179 | global $wp_filesystem; |
---|
180 | |
---|
181 | if ( ! isset( $_FILES['import'] ) ) { |
---|
182 | $file['error'] = __( 'File is empty. Please upload something more substantial. This error could also be caused by uploads being disabled in your php.ini or by post_max_size being defined as smaller than upload_max_filesize in php.ini.' ); |
---|
183 | return $file; |
---|
184 | } |
---|
185 | |
---|
186 | $url = 'admin.php?import=twitter'; |
---|
187 | |
---|
188 | if ( false === ($credentials = request_filesystem_credentials($url, '', false, ABSPATH)) ) |
---|
189 | return false; |
---|
190 | |
---|
191 | if ( ! WP_Filesystem($credentials, ABSPATH) ) { |
---|
192 | request_filesystem_credentials($url, '', true, ABSPATH); //Failed to connect, Error and request again |
---|
193 | return false; |
---|
194 | } |
---|
195 | |
---|
196 | $import_folder = $wp_filesystem->wp_content_dir() . 'import/'; |
---|
197 | |
---|
198 | //Clean up contents of upgrade directory beforehand. |
---|
199 | $import_files = $wp_filesystem->dirlist( $import_folder ); |
---|
200 | if ( ! empty( $import_files ) ) { |
---|
201 | foreach ( $import_files as $file ) |
---|
202 | $wp_filesystem->delete( $import_folder . $file['name'], true ); |
---|
203 | } |
---|
204 | |
---|
205 | //We need a working directory |
---|
206 | $working_dir = $import_folder . basename( $_FILES['import']['name'], '.zip' ); |
---|
207 | |
---|
208 | // Clean up working directory |
---|
209 | if ( $wp_filesystem->is_dir( $working_dir ) ) |
---|
210 | $wp_filesystem->delete( $working_dir, true ); |
---|
211 | |
---|
212 | // Unzip package to working directory |
---|
213 | $result = unzip_file( $_FILES['import']['tmp_name'], $working_dir ); //TODO optimizations, Copy when Move/Rename would suffice? |
---|
214 | |
---|
215 | // Once extracted, delete the import file. |
---|
216 | unlink( $_FILES['import']['tmp_name'] ); |
---|
217 | |
---|
218 | if ( is_wp_error($result) ) { |
---|
219 | $wp_filesystem->delete($working_dir, true); |
---|
220 | if ( 'incompatible_archive' == $result->get_error_code() ) { |
---|
221 | return new WP_Error( 'incompatible_archive', $this->strings['incompatible_archive'], $result->get_error_data() ); |
---|
222 | } |
---|
223 | return $result; |
---|
224 | } |
---|
225 | |
---|
226 | return $working_dir; |
---|
227 | |
---|
228 | } |
---|
229 | |
---|
230 | /** |
---|
231 | * Display pre-import options, author importing/mapping and option to |
---|
232 | * fetch attachments |
---|
233 | */ |
---|
234 | function import_options( $working_dir ) { |
---|
235 | $j = 0; |
---|
236 | ?> |
---|
237 | <form action="<?php echo admin_url( 'admin.php?import=twitter&step=2' ); ?>" method="post"> |
---|
238 | <?php wp_nonce_field( 'import-twitter' ); ?> |
---|
239 | <input type="hidden" name="working_dir" value="<?php echo esc_attr( $working_dir ) ?>" /> |
---|
240 | |
---|
241 | <h3><?php _e( 'Assign Author', 'wp-twitter-importer' ); ?></h3> |
---|
242 | <p><?php _e( 'To make it easier for you to edit and save the imported content, you may want to reassign the author of the imported item to an existing user of this site. For example, you may want to import all the entries as <code>admin</code>s entries.', 'wp-twitter-importer' ); ?></p> |
---|
243 | <?php if ( $this->allow_create_users() ) : ?> |
---|
244 | <p><?php printf( __( 'If a new user is created by WordPress, a new password will be randomly generated and the new user’s role will be set as %s. Manually changing the new user’s details will be necessary.', 'wp-twitter-importer' ), esc_html( get_option('default_role') ) ); ?></p> |
---|
245 | <?php endif; ?> |
---|
246 | <?php $this->author_select(); ?> |
---|
247 | |
---|
248 | <p class="submit"><input type="submit" class="button" value="<?php esc_attr_e( 'Submit', 'wp-twitter-importer' ); ?>" /></p> |
---|
249 | </form> |
---|
250 | <?php |
---|
251 | } |
---|
252 | |
---|
253 | /** |
---|
254 | * Display import options for an individual author. That is, either create |
---|
255 | * a new user based on import info or map to an existing user |
---|
256 | */ |
---|
257 | function author_select() { |
---|
258 | echo '<div class="author">'; |
---|
259 | |
---|
260 | _e( 'Assign posts to an existing user:', 'wp-twitter-importer' ); |
---|
261 | wp_dropdown_users( array( 'show_option_all' => __( '- Select -', 'wp-twitter-importer' ) ) ); |
---|
262 | echo '<br />'; |
---|
263 | |
---|
264 | $create_users = $this->allow_create_users(); |
---|
265 | if ( $create_users ) { |
---|
266 | _e( 'or create new user with login name:', 'wp-twitter-importer' ); |
---|
267 | |
---|
268 | echo ' <input type="text" name="user_new" />'; |
---|
269 | } |
---|
270 | |
---|
271 | echo '</div>'; |
---|
272 | } |
---|
273 | |
---|
274 | /** |
---|
275 | * Decide whether or not the importer is allowed to create users. |
---|
276 | * Default is true, can be filtered via import_allow_create_users |
---|
277 | * |
---|
278 | * @return bool True if creating users is allowed |
---|
279 | */ |
---|
280 | function allow_create_users() { |
---|
281 | return apply_filters( 'import_allow_create_users', true ); |
---|
282 | } |
---|
283 | |
---|
284 | public function parse_files( $working_dir, $post_author ) { |
---|
285 | global $wp_filesystem, $wpdb; |
---|
286 | WP_Filesystem(); |
---|
287 | $tweets_dir = $working_dir . '/data/js/tweets/'; |
---|
288 | |
---|
289 | $tweet_files = $wp_filesystem->dirlist( $tweets_dir ); |
---|
290 | $tweets = array(); |
---|
291 | $import_count = 0; |
---|
292 | if ( ! empty( $tweet_files ) ) { |
---|
293 | foreach ( $tweet_files as $file ) { |
---|
294 | $tweet_json = file_get_contents( $tweets_dir . $file['name'] ); |
---|
295 | $tweet_json = preg_replace( '/^[^\[]*/', '', $tweet_json ); |
---|
296 | $tweets = json_decode( $tweet_json ); |
---|
297 | if ( is_array( $tweets ) ) { |
---|
298 | foreach ( $tweets as $tweet ) { |
---|
299 | // Post title can be empty for Statuses, but it makes them easier to manage if they have *something* |
---|
300 | $title_words = explode( ' ', strip_tags( $tweet->text ) ); |
---|
301 | $post_title = implode( ' ', array_slice( $title_words, 0, 5 ) ); // Use the first 5 words |
---|
302 | if ( count( $title_words ) > 5 ) |
---|
303 | $post_title .= '…'; |
---|
304 | |
---|
305 | // Parse/adjust dates |
---|
306 | $post_date_gmt = strtotime( $tweet->created_at ); |
---|
307 | $post_date_gmt = gmdate( 'Y-m-d H:i:s', $post_date_gmt ); |
---|
308 | $post_date = get_date_from_gmt( $post_date_gmt ); |
---|
309 | |
---|
310 | // Clean up content a bit |
---|
311 | $post_content = $tweet->text; |
---|
312 | $post_content = $wpdb->escape( html_entity_decode( trim( $post_content ) ) ); |
---|
313 | |
---|
314 | // Handle entities supplied by Twitter |
---|
315 | if ( count( $tweet->entities->urls ) ) { |
---|
316 | foreach ( $tweet->entities->urls as $url ) |
---|
317 | $post_content = str_replace( $url->url, $url->expanded_url, $post_content ); |
---|
318 | } |
---|
319 | |
---|
320 | // Any hashtags used in a tweet will be applied to the Post as tags in WP |
---|
321 | $tags = array(); |
---|
322 | if ( preg_match_all( '/(^|[(\[\s])#(\w+)/', $post_content, $tag ) ) |
---|
323 | $tags = $tag[2]; |
---|
324 | |
---|
325 | // Add HTML links to URLs, usernames and hashtags |
---|
326 | $post_content = make_clickable( esc_html( $post_content ) ); |
---|
327 | |
---|
328 | $twitter_permalink = "https://twitter.com/{$tweet->user->screen_name}/status/{$tweet->id_str}"; |
---|
329 | $in_reply_to_user_id = !empty( $tweet->in_reply_to_user_id_str ) ? $tweet->in_reply_to_user_id_str : ''; |
---|
330 | $in_reply_to_screen_name = !empty( $tweet->in_reply_to_screen_name ) ? $tweet->in_reply_to_screen_name : ''; |
---|
331 | $in_reply_to_status_id = !empty( $tweet->in_reply_to_status_id_str ) ? $tweet->in_reply_to_status_id_str : ''; |
---|
332 | $post_status = apply_filters( 'tweet_import_status', 'publish' ); |
---|
333 | $post_type = apply_filters( 'tweet_import_post_type', 'post' ); |
---|
334 | |
---|
335 | // Build the post array, and hang onto it along with the others |
---|
336 | $post = apply_filters( 'twitter-import-post-data', compact( |
---|
337 | 'post_author', |
---|
338 | 'post_date', |
---|
339 | 'post_date_gmt', |
---|
340 | 'post_content', |
---|
341 | 'post_title', |
---|
342 | 'post_status', |
---|
343 | 'post_type', |
---|
344 | ), $tweet ); |
---|
345 | $post_id = wp_insert_post( $post ); |
---|
346 | $post_format = apply_filters( 'twitter-import-post-format', 'status', $tweet ); |
---|
347 | if ( ! empty( $post_format ) ) |
---|
348 | set_post_format( $post_id, $post_format ); |
---|
349 | $tags = apply_filters( 'twitter-import-tags', $tags, $tweet ); |
---|
350 | if ( count( $tags ) ) |
---|
351 | wp_set_post_terms( $post_id, implode( ',', $tags ) ); |
---|
352 | |
---|
353 | update_post_meta( $post_id, 'twitter_permalink', $twitter_permalink ); |
---|
354 | update_post_meta( $post_id, 'raw_tweet_data', $tweet ); |
---|
355 | update_post_meta( $post_id, 'tweet_id', $tweet->id_str ); |
---|
356 | |
---|
357 | $import_count++; |
---|
358 | if ( TWITTER_IMPORTER_AUTOCOMMIT_OFF && $import_count % 1000 == 0 ) { |
---|
359 | $wpdb->query('COMMIT'); |
---|
360 | } |
---|
361 | |
---|
362 | do_action( 'twitter-import-post-inserted', $tweet, $post_id ); |
---|
363 | } |
---|
364 | } |
---|
365 | } |
---|
366 | } |
---|
367 | } |
---|
368 | } |
---|
369 | } |
---|
370 | |
---|
371 | function wp_twitter_importer_init() { |
---|
372 | load_plugin_textdomain( 'wp-twitter-importer', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' ); |
---|
373 | |
---|
374 | /** |
---|
375 | * WordPress Importer object for registering the import callback |
---|
376 | * @global WP_Twitter_Import $wp_twitter_import |
---|
377 | */ |
---|
378 | $GLOBALS['wp_twitter_import'] = new WP_Twitter_Import(); |
---|
379 | register_importer( 'twitter', 'Twitter', __( 'Import your twitter status udpates.', 'wp-twitter-importer' ), array( $GLOBALS['wp_twitter_import'], 'dispatch' ) ); |
---|
380 | } |
---|
381 | add_action( 'admin_init', 'wp_twitter_importer_init' ); |
---|