Bulk csv import in WordPress programmatically

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!

Related posts

5 comments

  • 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.

  • 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

  • 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.


This site uses Akismet to reduce spam. Learn how your comment data is processed.

Secured By miniOrange