The problem
Imagine you have huge spreadsheet that requires some custom processing and on top of that you also need to upload the data to WordPress.
In my case i was given a spreadsheet of almost 1500 entries that was set of data containing name, email, ip address and some other data. The request was to import those as WordPress users, then convert the ip address to country, write it in their meta data and finally send welcome email.
The solution
While the importing is simple and there are a lot of plugins that will handle the import without problems, the custom processing requires manual work (eg. converting the ip to location or sending welcome email). So for that purpose i created WP Batch Processing. This plugin allows you to programmaticaly define your batch and the processing operation.
I will go in details how can you setup such procedure that will import CSV with users and do some custom logic.
Step 1 – Installing the batch processing plugin
To install the plugin download the latest version from the github repository, upload and activate it on your site.
Step 2 – Defining your batch
The first step is to extend the base WP_Batch
class with your own. This class can be placed in your theme or plugin. It depends of your choice.
We will assume that the csv file is named users.csv
and it is located in the theme directory.
First we need to define theid
and the title
of the batch and then also the setup
and the process
methods. This is the complete batch class with all the required methods. Feel free to check and test it yourself.
/** * Class Users_Import_Batch * * Import users from CSV with the following structure: * first_name, last_name, email, ip */ class Users_Import_Batch extends WP_Batch { /** * Unique identifier of each batch * @var string */ public $id = 'users_import_4'; /** * Describe the batch * @var string */ public $title = 'Users Import'; /** * Define a way to obtain the data from the csv. * You need to populate the $items array. * * @return void */ public function setup() { // Define the CSV Path $csv_path = get_template_directory() . '/users.csv'; // Add the CSV data in the processing queue $rows = array_map( 'str_getcsv', file( $csv_path ) ); // Loop over the data and add every row to the queue foreach ( $rows as $row ) { $row_data = array( 'first_name' => $row[0], // First name 'last_name' => $row[1], // Last name 'email' => $row[2], // Email 'ip' => $row[3] // Ip ); $unique_id = md5( $row[2] ); $this->push( new WP_Batch_Item( $unique_id, $row_data ) ); } } /*** * Define the import procedure for single item * * Return * - TRUE - If the item was processed successfully. * - WP_Error instance - If there was an error. * * @param WP_Batch_Item $item * * @return bool|\WP_Error */ public function process( $item ) { // Retrieve the custom data $user_firstname = $item->get_value( 'first_name' ); $user_lastname = $item->get_value( 'last_name' ); $user_email = $item->get_value( 'email' ); $user_ipaddress = $item->get_value( 'ip' ); // Bail if invalid data provided. if ( ! filter_var( $user_email, FILTER_VALIDATE_EMAIL ) ) { return new WP_Error( 302, "Invalid email provided" ); } // Bail if no name is provided. if ( empty( $user_firstname ) || empty( $user_lastname ) ) { return new WP_Error( 302, "No name provided" ); } // No ip address provided. if ( empty( $user_ipaddress ) ) { return new WP_Error( 302, "No ip address provided" ); } // Bail if the email is used already if ( email_exists( $user_email ) ) { return new WP_Error( 302, 'Email ' . $user_email . ' already exist.' ); } // Generate username $user_login = $this->generate_username( $user_email ); // Setup the basic data $data = array( 'user_login' => $user_login, 'user_email' => $user_email, 'first_name' => $user_firstname, 'last_name' => $user_lastname, 'user_pass' => wp_generate_password(), ); // Try to inser the user $imported_user_id = wp_insert_user( $data ); if ( is_wp_error( $imported_user_id ) ) { return $imported_user_id; // Bail if WP_Error is returned. } // 1.) Determine the country based on the ip. // Note: Just for demonstration purposes, we are using ip-api, they limit the requests to 250 per minute. So be careful. $ip_data = simplexml_load_file( "http://ip-api.com/xml/" . $user_ipaddress ); $country = isset( $ip_data->country ) ? (string) $ip_data->country : ''; // If country found add the country data if ( ! empty( $country ) ) { update_user_meta( $imported_user_id, 'country', $country ); } // 2.) Send welcome email wp_mail( $user_email, 'Welcome!', 'Howdy ' . $user_firstname . ', Welcome to the client portal.' ); return true; } /** * Generates unused username * * @param $email * * @return string|string[]|null */ private function generate_username( $email ) { // Generate unused username $tries = 0; $user_login = ''; while ( true ) { $user_login = preg_replace( '/@.*?$/', '', $email ); if ( $tries > 0 ) { $user_login .= $tries; } if ( ! username_exists( $user_login ) ) { break; } elseif ( $tries > 100 ) { // Stop if no free username. break; } else { $tries ++; } } // Generate random username if the above procedure didn't succeeded. if ( empty( $user_login ) ) { $user_login = 'user_' . time(); } return $user_login; } } /** * Initialize the Batch. */ add_action( 'wp_batch_processing_init', function () { $batch = new Users_Import_Batch(); WP_Batch_Processor::get_instance()->register( $batch ); } );
Step 3 – Include the class in your theme or plugin
require 'class-user-import-batch.php'
Navigate to the admin Dashboard > Batches and the batch will show up here.
If you are sure about your procedure you can run it. Always test it with smaller dataset to ensure it is working properly.
That’s it for now.
Cheers!
6 comments
Ivan
Great ! , is it possible to call batch import by a cron , not from WordPress CMS ?
Amirition
Thanks, Works like a charm.
But I think it’s too slow, My rows have about 42 columns and they upload several pictures and insert a post so I think it’s normal that it runs slow.
Giang
I got an error after installing the plugin (from Github)
Warning: The magic method WP_BP_Singleton::__wakeup() must have public visibility in E:\XAMPP_Rev1\htdocs\serial-checker\wp-content\plugins\wp-batch-processing\includes\class-bp-singleton.php on line 51
Giang
Hi,
I want to make a form to upload CSV file , after that as user click SUBMIT to upload, the batch will run imediatly to handle with uploaded CSV.
How could I do thank, may I ask?
Many thanks!
Eric Fox
I’m testing out your plugin for the batch import of some data from a large CSV file into LearnDash (a WordPress learning management system plugin), and so far it’s working perfectly! You did an awesome job with it. Thanks so much for making the plugin available and for this helpful blog post describing how to use it.
Darko Gjorgjijoski
Glad it worked for you! 🙂