Community Documentation

Import new users and their Profile2 fields from one CSV file

Last updated May 17, 2013. Created by wusel on September 20, 2011.
Edited by jp.stacey, joachim, drewish, mikeryan. Log in to edit this page.

This Cookbook shows, how you import one CSV file into a Drupal 7 site, creating new users, each with Profile2 fields.

The trick is to create two separate migrations from one source. The first creates the users; the second creates the profiles.

The second migration connects up the profiles it creates with the users that now exist by mapping the source unique key, MID, to the user uid. This is achieved by applying the line '$this->addFieldMapping('uid', 'MID')' to the mapping.

Cookbook:

Step 1: Before we start

  1. If not enabled, (download, install to your modules-path like sites/all/modules and) enable these modules:
  2. Add one 'profile type' in 'http://example.com/admin/structure/profiles':
    Label ='Memberlist'
  3. Add some fields in 'http://example.com/admin/structure/profiles/manage/memberlist/fields':
    • 'Text'-field: Label ='Member-ID', Field name = 'field_mnr', length = 6
    • 'Text'-field: Label ='Username', Field name = 'field_username'
    • 'Text'-field: Label ='Complete Name', Field name = 'field_name'
    • 'Date'-field[5]: Label ='Birthday', Field name = 'field_birthday', Date attributes to collect: Year = yes, Month = yes, Day = yes, Hour = no, Minute = no, Second = no
    • 'Text'-field: Label ='Tel. 1', Field name = 'field_tel_1'
  4. Check the permissions for 'Memberlist' on 'http://example.com/admin/people/permissions#module-profile2'

Note:
At the moment (April 30, 2013) you have to patch the date module. Please take a look at #1832544-2: Class registration for Migrate 2.5 or later / please commit patch for details.

Step 2: Build the import-module

Containing directory

Create a containing directory for your module. For example, all later steps in this section assume that you're in the directory sites/all/modules/a_wusel_migration.

.info file

In your module directory, create the file a_wusel_migration.info containing the following:

name = "A Wusel Migration"
description = "Importing a CSV file as new users, each with Profile2 fields"
package = Development

dependencies[] = migrate (2.5)
dependencies[] = migrate_extras
dependencies[] = profile2

; only for the 'Date'-field 'Birthday':
dependencies[] = date
dependencies[] = date_api
dependencies[] = date_migrate

; include the Classes file
files[] = a_wusel_migration.migrate.inc

; TIP: to show the migrate user interface delete the ";" at the beginning of the next line (or use drush)
;dependencies[] = migrate_ui

version = "7.x-1.1b"
core = 7.x

Hint:
The line "dependencies[] = migrate (2.5)" enforces to have the module-version 7.x-2.5.
I switch back to module-version 2.5 in this cookbook, because the user interface (migrate UI) is currently in heavy editing (in dev-version like 7.x-2.5+xx-dev).

.module file

In your module directory, create the file a_wusel_migration.module.

This file only needs to contain a call to hook_migrate_api, to tell Migrate that your module supports its APIs. For the 7.x-2.x branch of Migrate, you must return an API level of 2 as follows:[1]

<?php
/**
* @file
* Implements hook_migrate_api()
*
* Returns 'api' => 2 for the 7.x-2.x branch of Migrate
* Registers the migration classes for the 7.x-2.5 branch of Migrate (7.x-2.5-rc1+6-dev) as reported in: drupal.org/node/1824884 on 10/29/2012
*/
function a_wusel_migration_migrate_api() {
  return array(
   
'api' => 2,
   
'migrations' => array(
     
'Wusel_Step1_User' => array('class_name' => 'Wusel_Step1_UserMigration'),
     
'Wusel_Step2_Memberlist' => array('class_name' => 'Wusel_Step2_MemberlistMigration'),
    ),
  );
}
?>

This is all you require in your .module file.

Classes file

This file can be called anything, as long as it's named in the files[] array of your .info file above and it's in your module directory.

In a_wusel_migration.migrate.inc, start the following file[1]:

<?php
/**
* @file
* Migration classes for migrating users and profiles
*
* based on: drupal.org/node/1269066#comment-4988994
* and:      drupal.org/node/1190958#comment-4616032
*/

/**
* Abstract class as a base for all our migration classes
*/
abstract class Wusel_Basic_Migration extends Migration {
  public function
__construct() {
   
// Always call the parent constructor first for basic setup
   
parent::__construct(MigrateGroup::getInstance('WuselMigrate'));
   
// Avoid known line ending issue: drupal.org/node/1705850
   
ini_set('auto_detect_line_endings', TRUE);
  }
}
// Note that as always you do not have to close this ? > tag below
?>

You might find you don't need this abstract class, but it helps avoid a problem with line ending encodings that some people have reported. Basically, rather than using Migration as our base class below, we always use Wusel_Basic_Migration.

Continuing with this same file, we then add a class to migrate our users[1]:

<?php
/**
* User-only migration - not profile fields
*
* Data files are assumed to be in
*   sites/all/modules/a_wusel_migration/data_sources/
*/
class Wusel_Step1_UserMigration extends Wusel_Basic_Migration {
  public function
__construct() {
   
parent::__construct();
   
$this->description = t('Import an CSV-file (only "Account"-fields)');
   
$columns = array(
     
// "Source": ('Fieldname', 'Description')
     
0 => array('MID', t('Member-ID (must be unique)')),
     
1 => array('mail', t('Email (Account)')),
     
2 => array('name', t('Name (Account)')),
     
3 => array('password', t('Password (Account)'))
    );
   
// TIP: delete ", array('header_rows' => 1)" in the next line, if the CSV-file has NO header-line
   
$this->source = new MigrateSourceCSV(DRUPAL_ROOT . '/' . drupal_get_path('module', 'a_wusel_migration') . '/data_sources/drupaluser_import.csv', $columns, array('header_rows' => 1));
   
$this->destination = new MigrateDestinationUser();
   
$this->map = new MigrateSQLMap($this->machineName,
        array(
'MID' => array( // this field is used to connect user und profile2
               
'type' => 'varchar',
               
'length' => 6,
               
'not null' => TRUE,
               
'description' => t('User\'s Member-ID') // description never used
             
)
             ),
       
MigrateDestinationUser::getKeySchema()
    );

   
// Mapped fields
   
$this->addSimpleMappings(array('name'));
   
$this->addFieldMapping('mail', 'mail')
      ->
defaultValue('')
      ->
description(t('Email address'));
   
$this->addFieldMapping('init')
      ->
defaultValue('')
      ->
description(t('Email address used for initial account creation'));
   
$this->addFieldMapping('pass', 'password')
      ->
defaultValue('asdf')
      ->
description(t("User's password (plain text)"));
   
$this->addFieldMapping('is_new')
      ->
defaultValue(TRUE)
      ->
description(t('Build the new user (0|1)'));
   
$this->addFieldMapping('roles')
      ->
defaultValue(DRUPAL_AUTHENTICATED_RID)
      ->
description(DRUPAL_AUTHENTICATED_RID . t(' = "authenticated user"'));
   
$this->addFieldMapping('theme')
      ->
defaultValue('')
      ->
description(t("User's default theme"));
   
$this->addFieldMapping('signature')
      ->
defaultValue('')
      ->
description(t("User's signature"));
   
$this->addFieldMapping('signature_format')
      ->
defaultValue('filtered_html')
      ->
description(t('Which filter applies to this signature'));
   
$this->addFieldMapping('created')
      ->
defaultValue(time())
      ->
description(t('UNIX timestamp of user creation date'));
   
$this->addFieldMapping('access')
      ->
defaultValue(0)
      ->
description(t('UNIX timestamp for previous time user accessed the site'));
   
$this->addFieldMapping('login')
      ->
defaultValue(0)
      ->
description(t('UNIX timestamp for user\'s last login'));
   
$this->addFieldMapping('status')
      ->
defaultValue(1)
      ->
description(t('Whether the user is active(1) or blocked(0)'));
   
$this->addFieldMapping('timezone')
      ->
defaultValue(t('Europe/London')) // 'America/Los_Angeles', 'Europe/Berlin', 'UTC', ... from drupal.org/node/714214
     
->description(t("User's time zone"));
   
$this->addFieldMapping('language')
      ->
defaultValue(t('en')) // e.g.: 'en', 'fr', 'de', ...
     
->description(t("User's default language"));
   
$this->addFieldMapping('picture')
      ->
defaultValue(0
      ->
description(t('Avatar of the user'));
 
   
// Other handlers
   
if (module_exists('path')) {
     
$this->addFieldMapping('path')
           ->
defaultValue(NULL)
           ->
description(t('Path alias'));
    }
    if (
module_exists('pathauto')) {
     
$this->addFieldMapping('pathauto')
        ->
defaultValue(1)
        ->
description(t('Perform aliasing (set to 0 to prevent alias generation during migration)'));
    }
   
// Unmapped destination fields
   
$this->addUnmigratedDestinations(array('role_names', 'data'));
  }
}
// Note that as always you do not have to close this ? > tag below
?>

In the same file, we also write a second class, to migrate the Profile2 fields[1]:

<?php
/**
* Profile2 field migration
*
* Data files are assumed to be in
*   sites/all/modules/a_wusel_migration/data_sources/
*/
class Wusel_Step2_MemberlistMigration extends Wusel_Basic_Migration {
  public function
__construct() {
   
parent::__construct();
    global
$user;
   
$this->description = t('Import an CSV-file with Profile2-fields ("memberlist"-fields)');
   
$columns = array(
     
// "Source": ('Fieldname', 'Description')
     
0 => array('MID', t('Member-ID (must be unique)')),
     
1 => array('mail', t('Email (Account)')),
     
2 => array('name', t('Name (Account)')),
     
3 => array('password', t('Password (Account)')),
     
4 => array('complete_name', t('Complete Name (for Memberlist)')),
     
5 => array('birthday', t('Birthday (for Memberlist)')),
     
6 => array('tel_1', t('Tel.#1 (for Memberlist)'))
    );
   
// TIP: delete ", array('header_rows' => 1)" in the next line, if the CSV-file has NO header-line
   
$this->source = new MigrateSourceCSV(DRUPAL_ROOT . '/' . drupal_get_path('module', 'a_wusel_migration') . '/data_sources/drupaluser_import.csv', $columns, array('header_rows' => 1));
   
// Declare migration 'Wusel_Step1_User' a dependency in migration 'Wusel_Step2_Memberlist' to have them run in the right order, if needed:
   
$this->dependencies = array('Wusel_Step1_User');
   
$this->destination = new MigrateDestinationProfile2('memberlist');  // 'memberlist' is the "Machine name" of the profile2-"Profile type"
   
$this->map = new MigrateSQLMap($this->machineName,
        array(
'MID' => array( // this field is used to connect user und profile2
               
'type' => 'varchar',
               
'length' => 6,
               
'not null' => TRUE,
               
'description' => t('User\'s Member-ID') // description never used
             
)
             ),
       
MigrateDestinationProfile2::getKeySchema()
    );
   
// Connecting the profile2 to the user:
   
$this->addFieldMapping('uid', 'MID')
         ->
sourceMigration('Wusel_Step1_User'// If your user migration class was named 'MyUserMigration', the string is 'MyUser'
        
->description(t('The assignment of profile2-items to the respective user'));

   
// Mapped fields
   
$this->addFieldMapping('field_mnr', 'MID')
      ->
defaultValue(0)
      ->
description(t('The Member-ID (must be unique)'));
   
/* Delete this line, if you need the following:
    $this->addFieldMapping('field_mnr:format')
      ->defaultValue('plain_text')
      ->description(t('The Text-Format of the Member-ID'));
    /* */
   
$this->addFieldMapping('field_mnr:language')
      ->
defaultValue('und')
      ->
description(t('The language of the Member-ID<br />("und" = no language)'));
   
$this->addFieldMapping('field_username', 'name')
      ->
defaultValue('')
      ->
description(t('The login name'));
   
/* Delete this line, if you need the following:
    $this->addFieldMapping('field_username:format')
      ->defaultValue('plain_text')
      ->description(t('The Text-Format of the login name'));
    /* */
   
$this->addFieldMapping('field_username:language')
      ->
defaultValue(t('en'))
      ->
description(t('The language of the login name'));
   
$this->addFieldMapping('field_name', 'complete_name')
      ->
defaultValue('')
      ->
description(t('The complete name (for Memberlist)'));
   
/* Delete this line, if you need the following:
    $this->addFieldMapping('field_name:format')
      ->defaultValue('plain_text')
      ->description(t('The Text-Format of the complete name'));
    /* */
   
$this->addFieldMapping('field_name:language')
      ->
defaultValue(t('en'))
      ->
description(t('The language of the complete name'));
   
$this->addFieldMapping('field_birthday', 'birthday')
      ->
defaultValue('') // empty = unknown
     
->callbacks(array($this, 'fixTimestamp'))
      ->
description(t('The birthday (for Memberlist)') . '.<br />' . t('Format') . ': "YYYY-MM-DD" <br />' . t('or') . ' "MM/DD/YYYY" <br />' . t('or') . ' "DD.MM.YYYY"');
   
$this->addFieldMapping('field_tel_1', 'tel_1')
      ->
defaultValue('')
      ->
description(t('The main telephone-number (for Memberlist)'));
   
/* Delete this line, if you need the following:
    $this->addFieldMapping('field_tel_1:format')
      ->defaultValue('plain_text')
      ->description(t('The Text-Format of the main telephone-number'));
    /* */
   
$this->addFieldMapping('field_tel_1:language')
      ->
defaultValue('und')
      ->
description(t('The language of the main telephone-number<br />("und" = no language)'));
     
   
// Other handlers
    /* Delete this line, if you need the following:
    if (module_exists('path')) {
      $this->addFieldMapping('path')
           ->defaultValue(NULL)
           ->description(t('Path alias'));
    }
    /* */

    // some internal fields
   
$this->addFieldMapping('revision_uid')
      ->
defaultValue($user->uid)
      ->
description(t('The user ID of the user, who started the migration'));
   
$this->addFieldMapping('language')
      ->
defaultValue(t('en'))
      ->
description(t("The default language of the user (e.g. 'en', 'fr', 'de')"));

   
// Unmapped fields (this fields are in core and not needed as profile2-fields)
   
$this->addUnmigratedSources(array('mail', 'password'));
  }

  public function
fixTimestamp($date) {
   
// enable empty (= unknown) birthday-string:
   
if (strlen($date) > 0) {
     
$date = substr($date, 0, 10) . 'T12:00:00'; // we add 'twelve o'clock in the daytime' for automatic compensation of a website time zone difference to UTC
   
}
    return
$date;
  } 
}
?>

These two non-abstract objects are automatically detected by the Migrate module and appear in the admin interface for Migrate. Because you declare a dependency between them above, then Migrate knows it has to have run one before it runs the other.

.install file

Along with your other module files, create a_wusel_migration.install, containing the following[1]:

<?php
/**
* @file
* Implements hook_disable().
*
* the migration module should deregister its migrations
*/
function a_wusel_migration_disable() {
 
// based on: drupal.org/node/1418350#comment-5557772
 
Migration::deregisterMigration('Wusel_Step1_User');
 
Migration::deregisterMigration('Wusel_Step2_Memberlist');
}
?>


Create the directory for the data file

Create the directory "sites/all/modules/a_wusel_migration/data_sources/"[4].


Step 3: Enable your module and the Migrate modules

If not present, download and install to your modules-path like sites/all/modules these modules:

Then, enable your own module "A Wusel Migration"! Because of the dependencies[] in the .info file, it should also automatically enable:

  • Migrate
  • Migrate Extras
  • Date Migration (for the Date field "Birthday")


Step 4: Prepare the CSV file

Prepare the CSV file[2] and name it drupaluser_import.csv, e.g.:

"member_nr","email","username","password","complete_name","birthday","tel_1"
"1001","new.tester@example.com","new tester","test","New Tester","07/13/1999","00000 12345-213"
"1002","old.tester@example.com","old tester","test","Old Tester","12.07.1945","00000/54321-0"
"1003","another.tester@example.com","another tester","test","Another Tester","1985-07-11","00000 678901"
"1004","","incognito user","test","Incognito User","",""

This file shows the possible forms of the birthday field (ten or none signs!) for testing the import.
The allowed date formats in the CSV-file are:
"YYYY-MM-DD" or "MM/DD/YYYY" or "DD.MM.YYYY".
The delimiters are different for each format and have to be used properly!
This is only for the import!
Within e.g. a view, you can chose the format of the output.


The columns of this CSV file have to follow the order of both

$columns = array(
...
);
-code-parts in the file 'a_wusel_migration.migrate.inc'!

The first column has the "Source"-code of '0'.


Step 5: Import

Store the CSV-file drupaluser_import.csv from Step 4 in the place as specified (sites/all/modules/a_wusel_migration/data_sources/drupaluser_import.csv).

Clear your cache!

If you have enabled the module migrate_ui:
Go to Administration > Content > Migrate or http://example.com/admin/content/migrate.
Check the box for the first migration Wusel_Step1_User and click import (or use drush).
Check the box for the second migration Wusel_Step2_Memberlist and click import (or use drush).

Step 6: Show the import

Visit 'http://example.com/admin/people'.


Notes:

[1]: Don't include the "?>" at the end of the file! Here it is only visible to format this page-text.

[2]: Some sub-notes:

  1. The CSV-file must have the ","-separator. The ";"-separator is not allowed!
  2. The CSV-file must be in "UTF8 with BOM"-format, then the import of special characters (letters like €, £, ß, ö ,ä, ü, Ö, Ä and Ü or other non-ASCII-signs) is without problems.
  3. The needed/correct line-ending-char(s) of a Feeds-imported CSV-file depends on the type of the operating system of the www-server:
    If you are using a Linux-Server, use only LF at the line-end of the CSV-file.
    If you are using a Windows-Server, use CR+LF at the line-end of the CSV-file.
    If you are using a Mac-Server, use only CR at the line-end of the CSV-file.
    The changing of the line-end of the CSV-file before importing is important, if the source of the CSV-file (e.g. your computer or the database of the CSV-file) has a different operating system!
  4. You can use a good editor like 'notepad++' on windows or 'LibreOffice Calc' (when indicated: '... Portable') or 'MS Excel' to change this (Tip: use "Save as" and change the needed properties before/during saving).

[3]: You can translate this enabled module using the Locale module (in core). Or use 'Add a translation' (http://drupal.org/node/1524254).

[4]: It's convenient to have the sample data files (drupaluser_import.csv) in the module directory for the example module, but bad practice with real data. Don't try this at your real live server! Your source data should be outside of the webroot, and should not be anywhere where it may get committed into a revision control system.

[5]: To be able to store dates before "1901-12-14" (12/14/1901), never use the field type "Date (Unix timestamp)"!



Good luck!

Comments

Thank you

I have been struggling with this for a while now, and finally got it working this morning, just before this page went up. Thanks anyway!

edit: Oh, this is based on my forum post! *facepalm*

The other Andrew Morton

Module not working correctly?

Trying out this module approach but getting the following errors when I try to run the Wusel_Step_1 import:

Notice: Undefined variable: user in Wusel_Step2_MemberlistMigration->__construct() (line 129 of /Applications/MAMP/htdocs/www/sites/all/modules/custom/a_wusel_migration/a_wusel_migration.migrate.inc).
Notice: Trying to get property of non-object in Wusel_Step2_MemberlistMigration->__construct() (line 129 of /Applications/MAMP/htdocs/www/sites/all/modules/custom/a_wusel_migration/a_wusel_migration.migrate.inc).

Suggestions?

-Trevor

Processed message shows 0

I'm also getting this message when running the first import:

Processed 0 (0 created, 0 updated, 0 failed, 0 ignored) in 0 sec (0/min) - done with 'Wusel_Step1_User'

-Trevor

Thanks for your postings

@ambientdrup:

Your posting on December 1, 2011 at 10:53pm:
It was my error.
I add a new line 3 of "class Wusel_Step2_MemberlistMigration" as "global $user;", please look at the code above. Please add it in your code, too.

Your other posting on December 1, 2011 at 11:06pm:
Is your CSV-file at the correct path? On the tab/page "Source" of "http://example.com/admin/content/migrate/Wusel_Step1_User", you can find your path to the CSV-file.
And always clear your cache after putting this (e.g. new) CSV-file in the correct path.
If you are using a Linux-Server, please use only LF at the line-end of the CSV-file.
If you are using a Windows-Server, please use CR+LF at the line-end of the CSV-file.
The CSV-file must have the ","-separator. The ";"-separator is not allowed!

Wusel

How to check conditional statement

In case our csv file content have duplicate user (eg: by mistake to add same user details in mutiple times) how can i check to using conditional statement and where do write the code..

You can do it in a

You can do it in a prepareRow() public method:

<?php
public function prepareRow($row) {
  if (
this is a bad row) {
    return
FALSE// this row will be skipped in the migration
 
}
  return
TRUE;
}
?>

Look to the general migrate documentation to find out more about this method.

checking conditional

when i add user name and other details it shows 'it already exist' and that user name does not saved in database but other field values stored. i wish when user name is same other field values do not have to store in database and also that user account do not have to create. how to write code for this condition?

Finally got it working!

Thank you soooooo much!

Any chance you could put together an "Update Users and Profile2 Info" cookbook?

This has been a LIFE SAVER

This has been a LIFE SAVER for a client job - thank you!!

How to display results

I tried this example and it worked. At least I can see the Import worked like it should and imported 3 things as in the csv. But where are the results? How do I display those results after the import?

2+ Types of Profile2 Profile Types

This code looks like it only works for 1 profile type, can you please mod it so that it works with 2 or more? Thanks

freedom isn't free

Your Cookbook (main steps)

1.) Copy the whole "class Wusel_Step2_MemberlistMigration" as "class Wusel_Step3_SecondProfile2Migration" to the bottom of the file "sites/all/modules/a_wusel_migration/a_wusel_migration.migrate.inc".
2.) Edit this new class to fit your second Profile2.
Here you have to change "memberlist" in the line "MigrateDestinationProfile2('memberlist')" to your second Profile2-Name.
The "$columns" and the "AddFieldMapping"s depend on the fields of your second Profile2.
3.) Add the new fields to your CSV-file.

Good luck!

Wusel

Thanks for the tutorial and code.
For some reason my http://mysite.com/admin/content/migrate does not display the Wusel_Step1_User and Wusel_Step2_Memberlist options.
Only the MigrateExampleProfile2 and Date migration options are displayed.
I have the a_wusel_migration directory/file structure as follows:
modules (folder)
--a_wusel_migration (folder)
----a_wusel_migration.inc
----a_wusel_migration.info
----a_wusel_migration.module
----data_source (folder)
------drupaluser_import.csv
I removed the end ?> from .inc and .module files
Modules installed: migrate, migrate_extras, migrate ui, migrate extra profile2 example, a_wusel_migration, profiles2, entity api, date, date migration, date api, etc...
Added profiles to the user data. The profile fields mirror the ones on the Drupal 6 site.
Clear cache several times.
Basically, I am trying to convert a Drupal 6 to 7 website that has a membership list with profiles. The Drupal 7 site is fresh and I want to do the membership migration before adding content to the site. This new site is being developed on a local wampserver.
Is there a reason that the Wusel_Step1_User and Wusel_Step2_Memberlist options do not display?

TJM

My tip

@TJM:
First implement this Cookbook without any changes on a test-drupal-system (Drupal core 7 without any other module and without any other theme).

Only when there are no errors, then change part for part, but only one part in every step. "Part" may be a value of the description above or an additional module or another theme. If this runs you may change the next part.

Good luck!

Wusel

Hi Wusel, Thanks for your

Hi Wusel,
Thanks for your continued support.
I did a fresh install of Drupal 7 and when through the files again. Guess what? The problem was a file name. As seen above in my post, the module file name is not correct.
Wrong: ----a_wusel_migration.module
Correct: ----a_wusel_migration.migrate.module
After the correction, Step 1 and 2 show up correctly. Now I can proceed with your module.
Sorry about my mistake,
Ted

TJM

I'm getting this error:
SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'field_company_value' cannot be null: etc, etc, etc
I've triple checked everything and looked at migrate issues (where this error only seems to come up for some filefield... in my case it's a plain text field).
- Wondering if anyone has seen this error in relation to this cookbook and has any advice
- And Wusel, I'd be happy to talk about compensation for troubleshooting...

Whoops, I realize the field

Whoops, I realize the field throwing the error is in fact a computed field.
So now I have to figure how to migrate to a destination computed field... any advice, anyone?

My users are already in my database by upgrading from Drupal 6 to Drupal 7. However, this upgrading did not transfer the Profiles to the new Profile2. So, currently, I have a database with all the users and their passwords in my database. How should your code be modified to add the user's profiles?
Thanks,
Ted

TJM

_

I think your problem is explained on this section and this section provides information about importing user profiles from a CVS file to profile2 to use them in Drupal 7. Please read this section again and if it didn't work do you well, ask your question again with more details that members can help you better. However i am not sure if it helps you, you can enable profile module in Drupal 7 too by going to yoursite.com/admin/modules page.

Doubt is the father of invention..... Hubmesh

Please create an issue

The trick of this import is to create two separate migrations from one source. The first creates the users, the second creates the profiles.
I think you have to do both steps of this migration and not only step two.
Or you have to use another field to connect ("map") user und profile2. But I don't know the trick for you.

Please feel free to create an issue at http://drupal.org/node/add/project-issue/migrate or (look) at http://drupal.org/forum/37
This may help you!

Please report your solution with a new cookbook-page! Thanks from the other users, who have similar problems.

Wusel

I have moved on to other

I have moved on to other projects. I might let the users enter their own profiles again. Possibly, someone will come up with a simple solution for just transferring the profiles of Drupal 6 to profiles2 of Drupal 7.
I appreciate all of your contributions and assistance.
Thanks
Ted

TJM

Importing for existing users

I was able to import profile data for existing users by modifying these files only slightly:

  1. From the .module file, delete the line: Wusel_Step1_User' => array('class_name' => 'Wusel_Step1_UserMigration')
  2. From the .inc file:
  • Delete the entire class: class Wusel_Step1_UserMigration extends Wusel_Basic_Migration
  • Delete this line: $this->dependencies = array('Wusel_Step1_User')
  • Delete this line: ->sourceMigration('Wusel_Step1_User')
  • Keep this line; it tells migrate which user record your data goes with: $this->addFieldMapping('uid', 'MID'), but change the field names to match what's in your destination and source fields.
  • Create new field mappings $this->addFieldMapping to link the columns in your source table to the appropriate profile2 fields, and update the $this->addUnmigratedSources array to include all of the source columns you're not migrating.

To migrate data from the same CSV into multiple profile types, as mentioned elsewhere in the comments, just create new classes like Wusel_Step2_MemberlistMigration and add them to the .inc file, and to the migrations array in the .module file. Since Wusel_Step1_User and Wusel_Step1_UserMigration no longer exist, you might also want to renumber the remaining step(s), although it's probably not required.

how about a taxonomy field?

Thx a lot!

i have a problem about importing taxonomy term.

CSV:

name,sex,phone
cobenash,F,0000

My problem is the data of sex in CSV is "F". However,the taxonomy tid in my drupal site is 7.

How can i get the value of the CSV and then use if~else if to put the correct tid in the field?

hello Santa
Santa Hello

Adding roles

Thanks for the cookbook, its great
Can you help me with giving a role to the migrated user.

thanks
nitish

My tip

In the file a_wusel_migration.module change the line

      ->defaultValue(DRUPAL_AUTHENTICATED_RID)

to
      ->defaultValue(array(DRUPAL_AUTHENTICATED_RID,4))

if you want e.g. to add the role with RID = 4 to all users. This RID must exist!

You also can import the roles from the CSV file. Add a new column and assign it to the field 'roles'.

Note:
"DRUPAL_AUTHENTICATED_RID" has the RID = 2.
You can view this at 'http://example.com/admin/content/migrate/Wusel_Step1_User', click at the tab 'Mapping: Done'.

Good luck!

Wusel

Thanks wusel

You really helped,
Now i have got into another problem.
I have added the birthday field in the registration form only. I have added your timefix function there also, But i am getting:
DateTime::__construct(): Failed to parse time string (1T12:00:00) at position 0 (1): Unexpected character (/var/www/fodler1/sites/all/modules/migrate/includes/base.inc:1019)
error could you help with this.

Solved it..

I solved it by keeping the mapped field in the same order in CSV as in code.

Field Collection

Thanks, this is great :)

I was wondering if I can map Profile2 fields that are "Field Collection" type.

Step 3 - Add field collection items

Guess what? I've just added a Step3 with successfully field collection migration.

This is what i've done:

1. Add this patch to field_collection module
http://drupal.org/node/1175082#comment-6763310

2. Add new class to the .migrate.inc developed on the current post

3. Import one or more childs to profile2. Cool or what? :)

thanks Wusel!

<?php
class Wusel__Step3_ChildMigration extends Wusel_Basic_Migration {
  public function
__construct() {
   
parent::__construct();
    global
$user;
   
$this->description = t('Import an CSV-file with Field Collection-fields ("child"-fields)');
   
$columns = array(
     
// "Source": ('Fieldname', 'Description')
     
0 => array('MID', t('Member-ID (must be unique)')),
     
1 => array('mail', t('Email (Account)')),
     
2 => array('name', t('Name (Account)')),
     
3 => array('password', t('Password (Account)')),
     
4 => array('child_name', t('Name (for Child)')),
     
5 => array('child_birth', t('Birthday (for Child)'))
    );
   
// TIP: delete ", array('header_rows' => 1)" in the next line, if the CSV-file has NO header-line
   
$this->source = new MigrateSourceCSV(DRUPAL_ROOT . '/' . drupal_get_path('module', 'a_wusel_migration') . '/data_sources/drupaluser_import.csv', $columns, array('header_rows' => 1));
   
$this->dependencies = array('Wusel_Step2_Memberlist');
   
$this->destination = new MigrateDestinationFieldCollection('field_mychildcollection',array('host_entity_type' => 'profile2')); 
   
$this->map = new MigrateSQLMap($this->machineName,
        array(
'MID' => array( // this field is used to connect child und profile2
               
'type' => 'varchar',
               
'length' => 6,
               
'not null' => TRUE,
               
'description' => t('User\'s Member-ID') // description never used
             
)
             ),
       
MigrateDestinationFieldCollection::getKeySchema()
    );

   
// Connecting the field collection to the profile2:
   
$this->addFieldMapping('host_entity_id', 'MID')
         ->
sourceMigration('Wusel_Step2_Memberlist'// If your user migration class was named 'MyUserMigration', the string is 'MyUser'
        
->description(t('The assignment of collection-items to the respective profile'));

   
$this->addFieldMapping('field_child_first_name', 'child_name')
      ->
defaultValue('')
      ->
description(t('The first name (for Child)'));
   
/* Delete this line, if you need the following:
    $this->addFieldMapping('field_name:format')
      ->defaultValue('plain_text')
      ->description(t('The Text-Format of the complete name'));
    /* */
   
$this->addFieldMapping('field_child_first_name:language')
      ->
defaultValue(t('pt-pt'))
      ->
description(t('The language of the complete name'));
   
$this->addFieldMapping('field_child_birthday', 'child_birth')
      ->
defaultValue('') // empty = unknown
     
->callbacks(array($this, 'fixTimestamp'))
      ->
description(t('The birthday (for Child)') . '.<br />' . t('Format') . ': "YYYY-MM-DD" <br />' . t('or') . ' "MM/DD/YYYY" <br />' . t('or') . ' "DD.MM.YYYY"');
  }

  public function
fixTimestamp($date) {
   
// enable empty (= unknown) birthday-string:
   
if (strlen($date) > 0) {
     
$date = substr($date, 0, 10) . 'T12:00:00'; // we add 'twelve o'clock in the daytime' for automatic compensation of a website time zone difference to UTC
   
}
    return
$date;
  }
}
?>

Showing CSV content

I did all the things said above. Data in csv file doesn't store in database but table is created, and I can't view the data in my site. How can i show data stored in csv file on drupal site?

I done this. I forget to

I done this. I forget to execute the import.
Thanks for your post.

Date format

i did to create user profile from import data from csv file. The date format is storied in MM.DD.YYYY but i want to store this format DD.MM.YYYY. how can i write the condition code in this format

Hint

The allowed date formats in the CSV-file are:
"YYYY-MM-DD" or "MM/DD/YYYY" or "DD.MM.YYYY".
The delimiters are different for each format and have to be used properly!

You have to change "MM.DD.YYYY" to "MM/DD/YYYY".

This is only for the import!
Within e.g. a view, you can chose the format of the output.

You can read this in the "class Wusel_Step2_MemberlistMigration" in the third part of the file "a_wusel_migration.migrate.inc" for the field 'field_birthday'
or after enabling the module "A Wusel Migration" in the UI.

Good luck!

Wusel

Thank u

thank your for your replay

Error 500

I seem to be getting an error when clicking on the "Execute" button. I've checked every line, twice! I've even stripped out my code to just have Step 1, with no solution in sight.

An AJAX HTTP error occurred. HTTP Result Code: 500 Debugging information follows. Path: /batch?id=572&op=do StatusText: Service unavailable (with message) ResponseText:

I just cannot see what is wrong. No errors are in the error logs or on screen. I'm at the end of my tether, having spent all day, and would really appreciate a pointer as to where to start!

Using Migrate 7.x-2.x-dev - But the same on 7.x-2.5

how to import using postal address uing csv file

i imported user details from csv file using migrate module. in my site i'm using address field module, and i wish to import postal address for each user from cvs file to address field. how can i do this?

My tipp

Please create an issue in the address field module issue queue.

Good luck.

Wusel

import using postal address field

i do like this format to importing address field and its work. This is the csv source to mapping used in array

<?php
$columns
= array(
0=> array('city', t('city (for pro_contact_information)')),
1=> array('state', t('state(for pro_contact_information)')),
2=> array('zip', t('zip(for pro_contact_information)')),
3=> array('country', t('country(for pro_contact_information)')),
);
?>

i used to following this code to map csv file to postal address field using addFieldMapping

<?php
$argument
= array( 'thoroughfare' => array('source_field' => 'address'),
'locality' => array('source_field' => 'city'),
'administrative_area' => array('source_field' => 'state'),
'postal_code' => array('source_field' => 'zip'),
);   
// The country ISO code should be passed in as the primary value.
   
$this->addFieldMapping('field_ftf_address','country')
          ->
arguments($argument);
?>

generate password randomly

i'm using migrate module. when i import a cvs file user account created successfully. i want to generate password randomly for each user automatically when import cvs file. how can i do this?

generate password with prepareRow

Hi.

The solution is to use the prepareRow function.

Let's assume that you have an CSV column with the title 'password', where you can have pre-generated passwords OR you can leave empty cells and let you migration code create random ones.

In you mapping fields, you have something like this inside __construct():

    $this->addFieldMapping('pass', 'password')
      ->defaultValue('password')
      ->description(t("User's password (plain text)"));

After you close __construct(), and still inside the class, you can add something like this:

  public function prepareRow($current_row) {
  $pass=$current_row->password;

  // Validate the password
  if (strlen($pass)>0) {
  $current_row->password = $pass;
  } else {
  $current_row->password = implode('',array_rand(array_flip(array_merge(range('a','z'),range('A','Z'),range('0','9'))),8));
  }
   }

This function will analyze every row.
It's very handy! :)

NULL value couldnt to store the database

i'm using migrate module. when i import a cvs file profile2 fields created successfully. In my csv file have some filed to import to create profile field. if any one column is NULL the database as store blank space and its display on only field name. In this situation i want to omit that data storing in database and also do not display on my profile view page how can i do this

Page status

No known problems

Log in to edit this page

About this page

Drupal version
Drupal 7.x
Audience
Programmers, Site administrators
Level
Intermediate, Advanced
Keywords
CSV-File, import, migrate, MigrateDestinationProfile2, MigrateDestinationUser, MigrateSourceCSV, profile2, sourceMigration, user

Administration & Security Guide

Drupal’s online documentation is © 2000-2013 by the individual contributors and can be used in accordance with the Creative Commons License, Attribution-ShareAlike 2.0. PHP code is distributed under the GNU General Public License. Comments on documentation pages are used to improve content and then deleted.