PluginProbe
Import Users from CSV / trunk
Import Users from CSV vtrunk
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 trunk, at import-users-from-csv.php

510 lines 15.1 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: https://wordpress.org/plugins/import-users-from-csv/
5 Description: Import Users data and metadata from a csv file.
6 Version: 1.3.1
7 Author: WP All Import
8 Author URI: https://www.wpallimport.com/
9 License: GPL2
10 Text Domain: import-users-from-csv
11 */
12
13 /**
14 * @package Import_Users_from_CSV
15 */
16
17 load_plugin_textdomain( 'import-users-from-csv', false, basename( dirname( __FILE__ ) ) . '/languages' );
18
19 if ( ! defined( 'IS_IU_CSV_DELIMITER' ) ){
20 define ( 'IS_IU_CSV_DELIMITER', ',' );
21 }
22
23 /**
24 * Main plugin class
25 *
26 * @since 0.1
27 **/
28 class IS_IU_Import_Users {
29 private static $log_dir_path = '';
30 private static $log_dir_url = '';
31
32 /**
33 * Initialization
34 *
35 * @since 0.1
36 **/
37
38 public static function init() {
39 add_action( 'admin_menu', array( __CLASS__, 'add_admin_pages' ) );
40 add_action( 'init', array( __CLASS__, 'process_csv' ) );
41 add_action( 'admin_enqueue_scripts', array( __CLASS__, 'enqueue_assets' ) );
42
43 $upload_dir = wp_upload_dir();
44 self::$log_dir_path = trailingslashit( $upload_dir['basedir'] );
45 self::$log_dir_url = trailingslashit( $upload_dir['baseurl'] );
46
47 if ( defined( 'WP_CLI' ) && WP_CLI ) {
48 require_once __DIR__ . '/includes/import-users-from-csv.wpcli.php';
49 }
50
51 do_action('is_iu_after_init');
52 }
53
54 public static function enqueue_assets($hook) {
55 if( 'users_page_import-users-from-csv' !== $hook ) {
56 return;
57 }
58 wp_enqueue_style( 'import-users-from-csv-css', plugin_dir_url( __FILE__ ) . 'includes/assets/notice.css' );
59 }
60
61 /**
62 * Add administration menus
63 *
64 * @since 0.1
65 **/
66 public static function add_admin_pages() {
67 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' ) );
68 }
69
70 /**
71 * Process content of CSV file
72 *
73 * @since 0.1
74 **/
75 public static function process_csv() {
76 if ( isset( $_POST['_wpnonce-is-iu-import-users-users-page_import'] ) ) {
77 check_admin_referer( 'is-iu-import-users-users-page_import', '_wpnonce-is-iu-import-users-users-page_import' );
78
79 if(!current_user_can( 'create_users' )) {
80 die();
81 }
82 if ( !empty( $_FILES['users_csv']['tmp_name'] ) ) {
83 /* Setup settings variables */
84 $filename = sanitize_text_field( $_FILES['users_csv']['tmp_name'] );
85 $users_update = isset( $_POST['users_update'] ) ? sanitize_text_field( $_POST['users_update'] ) : false;
86 $new_user_notification = isset( $_POST['new_user_notification'] ) ? sanitize_text_field( $_POST['new_user_notification'] ) : false;
87
88 $results = self::import_csv( $filename, array(
89 'new_user_notification' => intval( $new_user_notification ),
90 'users_update' => intval( $users_update )
91 ) );
92
93 if ( ! $results['user_ids'] ){
94 /* No users imported? */
95 wp_redirect( add_query_arg( 'import', 'fail', wp_get_referer() ) );
96 } else if ( $results['errors'] ){
97 /* Some users imported? */
98 wp_redirect( add_query_arg( 'import', 'errors', wp_get_referer() ) );
99 } else {
100 /* All users imported? :D */
101 wp_redirect( add_query_arg( 'import', 'success', wp_get_referer() ) );
102 }
103 exit;
104 }
105
106 wp_redirect( add_query_arg( 'import', 'file', wp_get_referer() ) );
107 exit;
108 }
109 }
110
111 /**
112 * Content of the settings page
113 *
114 * @since 0.1
115 **/
116 public static function users_page() {
117 if ( ! current_user_can( 'create_users' ) ){
118 wp_die( __( 'You do not have sufficient permissions to access this page.' , 'import-users-from-csv') );
119 }
120
121 ?>
122
123 <div class="wrap">
124 <h2><?php _e( 'Import Users from CSV' , 'import-users-from-csv'); ?></h2>
125 <?php
126 $error_log_file = self::$log_dir_path . 'is_iu_errors.log';
127 $error_log_url = self::$log_dir_url . 'is_iu_errors.log';
128
129 if ( ! file_exists( $error_log_file ) ) {
130 if ( ! @fopen( $error_log_file, 'x' ) ){
131 $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 );
132 self::render_notice('updated', $message);
133 }
134 }
135
136 $import = isset( $_GET['import'] ) ? sanitize_text_field( $_GET['import'] ) : false;
137
138 if ( $import ) {
139 $error_log_msg = '';
140 if ( file_exists( $error_log_file ) ){
141 $error_log_msg = sprintf( __( ", please <a href='%s' target='_blank'>check the error log</a>", 'import-users-from-csv'), esc_url( $error_log_url ) );
142 }
143
144 switch ( $import ) {
145 case 'file':
146 $message = __( 'Error during file upload.' , 'import-users-from-csv');
147 self::render_notice('error', $message);
148 break;
149 case 'data':
150 $message = __( 'Cannot extract data from uploaded file or no file was uploaded.' , 'import-users-from-csv');
151 self::render_notice('error', $message);
152 break;
153 case 'fail':
154 $message = sprintf( __( 'No user was successfully imported%s.' , 'import-users-from-csv'), $error_log_msg );
155 self::render_notice('error', $message);
156 break;
157 case 'errors':
158 $message = sprintf( __( 'Some users were successfully imported but some were not%s.' , 'import-users-from-csv'), $error_log_msg );
159 self::render_notice('update-nag', $message);
160 break;
161 case 'success':
162 $message = __( 'Users import was successful.' , 'import-users-from-csv');
163 self::render_notice('updated', $message);
164 break;
165 default:
166 break;
167 }
168 }
169 ?>
170
171 <form method="post" action="" enctype="multipart/form-data">
172 <?php wp_nonce_field( 'is-iu-import-users-users-page_import', '_wpnonce-is-iu-import-users-users-page_import' ); ?>
173
174 <?php do_action('is_iu_import_page_before_table'); ?>
175
176 <table class="form-table widefat wp-list-table">
177 <?php do_action('is_iu_import_page_inside_table_top'); ?>
178 <tr valign="top">
179 <td scope="row">
180 <strong>
181 <label for="users_csv"><?php _e( 'CSV file' , 'import-users-from-csv'); ?></label>
182 </strong>
183 </td>
184 <td>
185 <input type="file" id="users_csv" name="users_csv" value="" class="all-options" /><br />
186 <span class="description">
187 <?php
188 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' ) );
189 ?>
190 </span>
191 </td>
192 </tr>
193 <tr valign="top">
194 <td scope="row">
195 <strong>
196 <?php _e( 'Notification' , 'import-users-from-csv'); ?>
197 </strong>
198 </td>
199 <td>
200 <fieldset>
201 <legend class="screen-reader-text"><span><?php _e( 'Notification' , 'import-users-from-csv'); ?></span></legend>
202
203 <label for="new_user_notification">
204 <input id="new_user_notification" name="new_user_notification" type="checkbox" value="1" />
205 <?php _e('Send to new users', 'import-users-from-csv'); ?>
206 </label>
207 </fieldset>
208 </td>
209 </tr>
210 <tr valign="top">
211 <td scope="row"><strong><?php _e( 'Users update' , 'import-users-from-csv'); ?></strong></td>
212 <td>
213 <fieldset>
214 <legend class="screen-reader-text"><span><?php _e( 'Users update' , 'import-users-from-csv' ); ?></span></legend>
215
216 <label for="users_update">
217 <input id="users_update" name="users_update" type="checkbox" value="1" />
218 <?php _e( 'Update user when a username or email exists', 'import-users-from-csv' ) ;?>
219 </label>
220 </fieldset>
221 </td>
222 </tr>
223 <tr valign="top">
224 <td scope="row">
225 <p class="submit">
226 <input type="submit" class="button-primary" value="<?php _e( 'Import' , 'import-users-from-csv'); ?>" />
227 </p>
228 </td>
229 </tr>
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 </form>
236 </div>
237 <?php
238
239 include 'includes/notice.php';
240
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 ) || empty( array_filter( $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 if(is_serialized($metavalue)){
426 $metavalue = unserialize(trim($metavalue), ['allowed_classes' => false]);
427 }
428 update_user_meta( $user_id, $metakey, $metavalue );
429 }
430 }
431
432 /* Let's update the user roles! */
433 foreach( $user_roles as $user_role ){
434 $user = new WP_User( $user_id );
435 $user->add_role( $user_role );
436 }
437
438 /* If we created a new user, maybe send new notification */
439 if ( ! $update ) {
440 if ( $new_user_notification ) {
441 wp_new_user_notification( $user_id, null, 'user' );
442 }
443 }
444
445 /* Hook to allow other plugins to run functionality post import */
446 do_action( 'is_iu_post_user_import', $user_id, $userdata, $usermeta );
447
448 $user_ids[] = $user_id;
449 }
450
451 $rkey++;
452 }
453 fclose( $file_handle );
454 } else {
455 $errors[] = new WP_Error('file_read', 'Unable to open CSV file.');
456 }
457
458 /* One more thing to do after all imports? */
459 do_action( 'is_iu_post_users_import', $user_ids, $errors );
460
461 $errors = apply_filters( 'is_iu_errors_filter', $errors, $user_ids );
462
463 /* Let's log the errors */
464 self::log_errors( $errors );
465
466 return apply_filters( 'is_iu_return_import_results', array(
467 'user_ids' => $user_ids,
468 'errors' => $errors
469 ) );
470 }
471
472 /**
473 * Log errors to a file
474 *
475 * @since 0.2
476 **/
477 private static function log_errors( $errors ) {
478 if ( empty( $errors ) ){
479 return;
480 }
481
482 $log = @fopen( self::$log_dir_path . 'is_iu_errors.log', 'a' );
483 @fwrite( $log, sprintf( __( 'BEGIN %s' , 'import-users-from-csv'), date_i18n( 'Y-m-d H:i:s', time() ) ) . "\n" );
484
485 foreach ( $errors as $key => $error ) {
486 $line = $key + 1;
487 $message = $error->get_error_message();
488 @fwrite( $log, sprintf( __( '[Line %1$s] %2$s' , 'import-users-from-csv'), $line, $message ) . "\n" );
489 }
490
491 @fclose( $log );
492 }
493
494 /**
495 * Echo out a notice withs specific class.
496 *
497 * @param $class - class to add to div
498 * @param $message - The content of the notice. This should be escaped before being passed in to ensure proper escaping is done.
499 *
500 *
501 * @since 1.0.1
502 */
503 private static function render_notice($class, $message){
504 $class = esc_attr($class);
505 echo "<div class='$class'><p><strong>$message</strong></p></div>";
506 }
507 }
508
509 IS_IU_Import_Users::init();
510