WordPress.org

Make WordPress Core

Ticket #22981: wp-twitter-importer.3.php

File wp-twitter-importer.3.php, 13.2 KB (added by Otto42, 4 years ago)
Line 
1<?php
2/*
3Plugin Name: WP Twitter Importer
4Plugin URI: http://wordpress.org/extend/plugins/wp-twitter-importer/
5Description:
6Author: wordpressdotorg
7Author URI: http://wordpress.org/
8Version: 0.1
9Text Domain: wp-twitter-importer
10License: 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
14defined('TWITTER_IMPORTER_AUTOCOMMIT_OFF') or define('TWITTER_IMPORTER_AUTOCOMMIT_OFF', true);
15
16if ( ! defined( 'WP_LOAD_IMPORTERS' ) )
17        return;
18
19/** Display verbose errors */
20define( 'IMPORT_DEBUG', false );
21
22// Load Importer API
23require_once ABSPATH . 'wp-admin/includes/import.php';
24
25if ( ! 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
31if ( 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&#8217;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&amp;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&amp;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&#8217;s role will be set as %s. Manually changing the new user&#8217;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 .= '&hellip;';
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
371function 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}
381add_action( 'admin_init', 'wp_twitter_importer_init' );