PluginProbe
Import Users from CSV / 1.1
Import Users from CSV v1.1
trunk 0.5.1 1.0.0 1.0.1 1.1 1.2 1.3 1.3.1
import-users-from-csv / import-users-from-csv.php

import-users-from-csv.php in Import Users from CSV 1.1, at import-users-from-csv.php

508 lines 15.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 Plugin Name: Import Users from CSV
4 Plugin URI: http://wordpress.org/extend/plugins/import-users-from-csv/
5 Description: Import Users data and metadata from a csv file.
6 Version: 1.1
7 Author: Andrew Lima
8 Author URI: https://andrewlima.co.za
9 License: GPL2
10 Text Domain: import-users-from-csv
11 */
12
13 /*
14 * Copyright 2011 Ulrich Sossou (https://github.com/sorich87)
15 * Copyright 2018 Andrew Lima (https://github.com/andrewlimaza/import-users-from-csv)
16 *
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License, version 2, as
19 * published by the Free Software Foundation.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
29 */
30
31 /**
32 * @package Import_Users_from_CSV
33 */
34
35 load_plugin_textdomain( 'import-users-from-csv', false, basename( dirname( __FILE__ ) ) . '/languages' );
36
37 if ( ! defined( 'IS_IU_CSV_DELIMITER' ) ){
38 define ( 'IS_IU_CSV_DELIMITER', ',' );
39 }
40
41 /**
42 * Main plugin class
43 *
44 * @since 0.1
45 **/
46 class IS_IU_Import_Users {
47 private static $log_dir_path = '';
48 private static $log_dir_url = '';
49
50 /**
51 * Initialization
52 *
53 * @since 0.1
54 **/
55 public static function init() {
56 add_action( 'admin_menu', array( __CLASS__, 'add_admin_pages' ) );
57 add_action( 'init', array( __CLASS__, 'process_csv' ) );
58
59 $upload_dir = wp_upload_dir();
60 self::$log_dir_path = trailingslashit( $upload_dir['basedir'] );
61 self::$log_dir_url = trailingslashit( $upload_dir['baseurl'] );
62
63 if ( defined( 'WP_CLI' ) && WP_CLI ) {
64 require_once __DIR__ . '/includes/import-users-from-csv.wpcli.php';
65 }
66
67 do_action('is_iu_after_init');
68 }
69
70 /**
71 * Add administration menus
72 *
73 * @since 0.1
74 **/
75 public static function add_admin_pages() {
76 add_users_page( __( 'Import From CSV' , 'import-users-from-csv'), __( 'Import From CSV' , 'import-users-from-csv'), 'create_users', 'import-users-from-csv', array( __CLASS__, 'users_page' ) );
77 }
78
79 /**
80 * Process content of CSV file
81 *
82 * @since 0.1
83 **/
84 public static function process_csv() {
85 if ( isset( $_POST['_wpnonce-is-iu-import-users-users-page_import'] ) ) {
86 check_admin_referer( 'is-iu-import-users-users-page_import', '_wpnonce-is-iu-import-users-users-page_import' );
87
88 if ( !empty( $_FILES['users_csv']['tmp_name'] ) ) {
89 /* Setup settings variables */
90 $filename = sanitize_text_field( $_FILES['users_csv']['tmp_name'] );
91 $users_update = isset( $_POST['users_update'] ) ? sanitize_text_field( $_POST['users_update'] ) : false;
92 $new_user_notification = isset( $_POST['new_user_notification'] ) ? sanitize_text_field( $_POST['new_user_notification'] ) : false;
93
94 $results = self::import_csv( $filename, array(
95 'new_user_notification' => intval( $new_user_notification ),
96 'users_update' => intval( $users_update )
97 ) );
98
99 if ( ! $results['user_ids'] ){
100 /* No users imported? */
101 wp_redirect( add_query_arg( 'import', 'fail', wp_get_referer() ) );
102 } else if ( $results['errors'] ){
103 /* Some users imported? */
104 wp_redirect( add_query_arg( 'import', 'errors', wp_get_referer() ) );
105 } else {
106 /* All users imported? :D */
107 wp_redirect( add_query_arg( 'import', 'success', wp_get_referer() ) );
108 }
109 exit;
110 }
111
112 wp_redirect( add_query_arg( 'import', 'file', wp_get_referer() ) );
113 exit;
114 }
115 }
116
117 /**
118 * Content of the settings page
119 *
120 * @since 0.1
121 **/
122 public static function users_page() {
123 if ( ! current_user_can( 'create_users' ) ){
124 wp_die( __( 'You do not have sufficient permissions to access this page.' , 'import-users-from-csv') );
125 }
126
127 ?>
128
129 <div class="wrap">
130 <h2><?php _e( 'Import users from a CSV file' , 'import-users-from-csv'); ?></h2>
131 <?php
132 $error_log_file = self::$log_dir_path . 'is_iu_errors.log';
133 $error_log_url = self::$log_dir_url . 'is_iu_errors.log';
134
135 if ( ! file_exists( $error_log_file ) ) {
136 if ( ! @fopen( $error_log_file, 'x' ) ){
137 $message = sprintf( __( 'Notice: please make the directory %s writable so that you can see the error log.' , 'import-users-from-csv'), self::$log_dir_path );
138 self::render_notice('updated', $message);
139 }
140 }
141
142 $import = isset( $_GET['import'] ) ? sanitize_text_field( $_GET['import'] ) : false;
143
144 if ( $import ) {
145 $error_log_msg = '';
146 if ( file_exists( $error_log_file ) ){
147 $error_log_msg = sprintf( __( ", please <a href='%s' target='_blank'>check the error log</a>", 'import-users-from-csv'), esc_url( $error_log_url ) );
148 }
149
150 switch ( $import ) {
151 case 'file':
152 $message = __( 'Error during file upload.' , 'import-users-from-csv');
153 self::render_notice('error', $message);
154 break;
155 case 'data':
156 $message = __( 'Cannot extract data from uploaded file or no file was uploaded.' , 'import-users-from-csv');
157 self::render_notice('error', $message);
158 break;
159 case 'fail':
160 $message = sprintf( __( 'No user was successfully imported%s.' , 'import-users-from-csv'), $error_log_msg );
161 self::render_notice('error', $message);
162 break;
163 case 'errors':
164 $message = sprintf( __( 'Some users were successfully imported but some were not%s.' , 'import-users-from-csv'), $error_log_msg );
165 self::render_notice('update-nag', $message);
166 break;
167 case 'success':
168 $message = __( 'Users import was successful.' , 'import-users-from-csv');
169 self::render_notice('updated', $message);
170 break;
171 default:
172 break;
173 }
174 }
175 ?>
176
177 <form method="post" action="" enctype="multipart/form-data">
178 <?php wp_nonce_field( 'is-iu-import-users-users-page_import', '_wpnonce-is-iu-import-users-users-page_import' ); ?>
179
180 <?php do_action('is_iu_import_page_before_table'); ?>
181
182 <table class="form-table widefat wp-list-table" style='padding: 5px;'>
183 <?php do_action('is_iu_import_page_inside_table_top'); ?>
184 <tr valign="top">
185 <td scope="row">
186 <strong>
187 <label for="users_csv"><?php _e( 'CSV file' , 'import-users-from-csv'); ?></label>
188 </strong>
189 </td>
190 <td>
191 <input type="file" id="users_csv" name="users_csv" value="" class="all-options" /><br />
192 <span class="description">
193 <?php
194 echo sprintf( __( 'You may want to see <a href="%s">the example of the CSV file</a>.' , 'import-users-from-csv'), esc_url( plugin_dir_url(__FILE__).'examples/import.csv' ) );
195 ?>
196 </span>
197 </td>
198 </tr>
199 <tr valign="top">
200 <td scope="row">
201 <strong>
202 <?php _e( 'Notification' , 'import-users-from-csv'); ?>
203 </strong>
204 </td>
205 <td>
206 <fieldset>
207 <legend class="screen-reader-text"><span><?php _e( 'Notification' , 'import-users-from-csv'); ?></span></legend>
208
209 <label for="new_user_notification">
210 <input id="new_user_notification" name="new_user_notification" type="checkbox" value="1" />
211 <?php _e('Send to new users', 'import-users-from-csv'); ?>
212 </label>
213 </fieldset>
214 </td>
215 </tr>
216 <tr valign="top">
217 <td scope="row"><strong><?php _e( 'Users update' , 'import-users-from-csv'); ?></strong></td>
218 <td>
219 <fieldset>
220 <legend class="screen-reader-text"><span><?php _e( 'Users update' , 'import-users-from-csv' ); ?></span></legend>
221
222 <label for="users_update">
223 <input id="users_update" name="users_update" type="checkbox" value="1" />
224 <?php _e( 'Update user when a username or email exists', 'import-users-from-csv' ) ;?>
225 </label>
226 </fieldset>
227 </td>
228 </tr>
229
230 <?php do_action('is_iu_import_page_inside_table_bottom'); ?>
231
232 </table>
233
234 <?php do_action('is_iu_import_page_after_table'); ?>
235
236 <p class="submit">
237 <input type="submit" class="button-primary" value="<?php _e( 'Import' , 'import-users-from-csv'); ?>" />
238 </p>
239 </form>
240 <?php
241 }
242
243 /**
244 * Import a csv file
245 *
246 * @since 0.5
247 */
248 public static function import_csv( $filename, $args ) {
249 /* Stop timeouts */
250 @set_time_limit(0);
251
252 if ( ! class_exists( 'ReadCSV' ) ) {
253 include( plugin_dir_path( __FILE__ ) . 'class-readcsv.php' );
254 }
255
256 $errors = $user_ids = array();
257
258 $defaults = array(
259 'new_user_notification' => false,
260 'users_update' => false
261 );
262
263 extract( wp_parse_args( $args, $defaults ) );
264
265 /*
266 * User data field map, used to match datasets
267 */
268 $userdata_fields = array(
269 'ID',
270 'user_login',
271 'user_pass',
272 'user_email',
273 'user_url',
274 'user_nicename',
275 'display_name',
276 'user_registered',
277 'first_name',
278 'last_name',
279 'nickname',
280 'description',
281 'rich_editing',
282 'comment_shortcuts',
283 'admin_color',
284 'use_ssl',
285 'show_admin_bar_front',
286 'show_admin_bar_admin',
287 'role'
288 );
289
290 /* Filter for the user field map */
291 apply_filters('is_iu_userdata_fields', $userdata_fields);
292
293 /* Loop through the file lines */
294 $file_handle = @fopen( $filename, 'r' );
295 if($file_handle) {
296 $csv_reader = new ReadCSV( $file_handle, IS_IU_CSV_DELIMITER, "\xEF\xBB\xBF" ); // Skip any UTF-8 byte order mark.
297
298 $first = true;
299 $rkey = 0;
300 while ( ( $line = $csv_reader->get_row() ) !== NULL ) {
301 if ( empty( $line ) ) {
302 if ( $first ){
303 /* If the first line is empty, abort */
304 break;
305 } else{
306 /* If another line is empty, just skip it */
307 continue;
308 }
309 }
310
311 if ( $first ) {
312 /* If we are on the first line, the columns are the headers */
313 $headers = $line;
314 $first = false;
315 continue;
316 }
317
318 /* Prepare an array for multiple user roles */
319 $user_roles = array();
320
321 /* Separate user data from meta */
322 $userdata = $usermeta = array();
323 foreach ( $line as $ckey => $column ) {
324 $column_name = $headers[$ckey];
325 $column = trim( $column );
326
327 if ( in_array( $column_name, $userdata_fields ) ) {
328 $userdata[$column_name] = $column;
329 } else {
330 /**
331 * Data cleanup:
332 *
333 * Let's do a loose match on the column name
334 * This is to allow for small typos like 'UsEr PaSS' to be converted to 'user_pass'
335 *
336 * Todo: Add support for all uppercase as well
337 */
338 $formatted_column_name = strtolower($column_name);
339 $formatted_column_name = str_replace(' ', '_', $formatted_column_name);
340 $formatted_column_name = str_replace('-', '_', $formatted_column_name);
341 if( in_array( $formatted_column_name, $userdata_fields) ){
342 /**
343 * We have a formatted match
344 */
345 $userdata[$formatted_column_name] = $column;
346 } else {
347 /*
348 * We still have no match
349 * let's assume this is a meta value
350 */
351 $usermeta[$column_name] = $column;
352 }
353 }
354 }
355
356 /*
357 * Hooks to allow other plugins from filtering this data
358 */
359 $userdata = apply_filters( 'is_iu_import_userdata', $userdata, $usermeta );
360 $usermeta = apply_filters( 'is_iu_import_usermeta', $usermeta, $userdata );
361
362 if ( empty( $userdata ) ){
363 /* If no user data, bailout! */
364 continue;
365 }
366
367 /* Hook to allow other plugins to execute additional code pre-import */
368 do_action( 'is_iu_pre_user_import', $userdata, $usermeta );
369
370 $user = $user_id = false;
371 if ( isset( $userdata['ID'] ) ){
372 $user = get_user_by( 'ID', $userdata['ID'] );
373 }
374
375 /**
376 * Find the user by some alternative fields
377 *
378 * Fields checked: user_login, user_email
379 */
380 if ( ! $user && $users_update ) {
381 if ( isset( $userdata['user_login'] ) ){
382 $user = get_user_by( 'login', $userdata['user_login'] );
383 }
384
385 if ( ! $user && isset( $userdata['user_email'] ) ){
386 $user = get_user_by( 'email', $userdata['user_email'] );
387 }
388 }
389
390 $update = false;
391 if ( $user ) {
392 $userdata['ID'] = $user->ID;
393 $update = true;
394 }
395
396 if ( ! $update && empty( $userdata['user_pass'] ) ){
397 /* No password set for this user, let's generate one automatically */
398 $userdata['user_pass'] = wp_generate_password( 12, false );
399 }
400
401 if ( ! empty( $userdata['role'] ) ) {
402 $userdata['role'] = strtolower( $userdata['role'] );
403
404 $user_roles = explode( ',', $userdata['role'] );
405 $user_roles = array_map( 'trim', $user_roles );
406
407 if( count( $user_roles ) > 1 ) {
408 $userdata['role'] = reset( $user_roles );
409 }
410 }
411
412 if ( $update ){
413 $user_id = wp_update_user( $userdata );
414 } else {
415 $user_id = wp_insert_user( $userdata );
416 }
417
418 /* Is there an error o_O? */
419 if ( is_wp_error( $user_id ) ) {
420 $errors[$rkey] = $user_id;
421 } else {
422 /* If no error, let's update the user meta too! */
423 if ( $usermeta ) {
424 foreach ( $usermeta as $metakey => $metavalue ) {
425 $metavalue = maybe_unserialize( $metavalue );
426 update_user_meta( $user_id, $metakey, $metavalue );
427 }
428 }
429
430 /* Let's update the user roles! */
431 foreach( $user_roles as $user_role ){
432 $user = new WP_User( $user_id );
433 $user->add_role( $user_role );
434 }
435
436 /* If we created a new user, maybe send new notification */
437 if ( ! $update ) {
438 if ( $new_user_notification ) {
439 wp_new_user_notification( $user_id, null, 'user' );
440 }
441 }
442
443 /* Hook to allow other plugins to run functionality post import */
444 do_action( 'is_iu_post_user_import', $user_id, $userdata, $usermeta );
445
446 $user_ids[] = $user_id;
447 }
448
449 $rkey++;
450 }
451 fclose( $file_handle );
452 } else {
453 $errors[] = new WP_Error('file_read', 'Unable to open CSV file.');
454 }
455
456 /* One more thing to do after all imports? */
457 do_action( 'is_iu_post_users_import', $user_ids, $errors );
458
459 $errors = apply_filters( 'is_iu_errors_filter', $errors, $user_ids );
460
461 /* Let's log the errors */
462 self::log_errors( $errors );
463
464 return apply_filters( 'is_iu_return_import_results', array(
465 'user_ids' => $user_ids,
466 'errors' => $errors
467 ) );
468 }
469
470 /**
471 * Log errors to a file
472 *
473 * @since 0.2
474 **/
475 private static function log_errors( $errors ) {
476 if ( empty( $errors ) ){
477 return;
478 }
479
480 $log = @fopen( self::$log_dir_path . 'is_iu_errors.log', 'a' );
481 @fwrite( $log, sprintf( __( 'BEGIN %s' , 'import-users-from-csv'), date_i18n( 'Y-m-d H:i:s', time() ) ) . "\n" );
482
483 foreach ( $errors as $key => $error ) {
484 $line = $key + 1;
485 $message = $error->get_error_message();
486 @fwrite( $log, sprintf( __( '[Line %1$s] %2$s' , 'import-users-from-csv'), $line, $message ) . "\n" );
487 }
488
489 @fclose( $log );
490 }
491
492 /**
493 * Echo out a notice withs specific class.
494 *
495 * @param $class - class to add to div
496 * @param $message - The content of the notice. This should be escaped before being passed in to ensure proper escaping is done.
497 *
498 *
499 * @since 1.0.1
500 */
501 private static function render_notice($class, $message){
502 $class = esc_attr($class);
503 echo "<div class='$class'><p><strong>$message</strong></p></div>";
504 }
505 }
506
507 IS_IU_Import_Users::init();
508