It would seem appropriate to allow for field mapping from Source Data to destination node on import.

My example: I have to import a large user base from CSV, user import works great but I have related data unique to each user: Address, City, State, Zip, Phone, Etc... It would be useful to be able to map additional data to fields when importing.

Ideally it would work as importing users from CSV followed by adding additional import functions and choosing where the function will dump its data from a select list of fields.
Ex: Mapping Source Label: Zip | Target: field_zip(Profile)/field_zip(Location)
and I would be able select field_zip(Profile) as its the appropriate field even though I use a duplicate field in the Location Content Type.

Comments

uwe_a’s picture

why not just create two feeds importers, one for profiles and one for locations ??

johnv’s picture

I do not really understand your problem:
Do you want one source-field to be imported in 2 target fields? You can add the same field twice in the mapper
Mapping Source 1 Label: Zip | Target: field_zip(Profile)
Mapping Source 2 Label: Zip | Target: field_zip(Location)
Is your Location data not showing in the mapper (I suppose you have Location attached to your Profile Content Type)?
Use this module for mapping: http://drupal.org/project/location_feeds, see issue 'Location_feeds for Drupal 7';

kpastore’s picture

I agree this is an issue. You cannot add fields to users using feeds. Only the bare minimum is allowed. This needs to be addressed if Feeds is to take the place of other modules in D7, such as node import, that did not have this issue.

To answer uwe above, you can only import a feed to a content type. Using Profile2 for extra user fields, one cannot import a feed to this since it is not a content type. This is a serious need as there are many websites with unique user information that cannot be imported into D7 now.

johnv’s picture

Title: Field Mapping of additional data on import » Mapping of additional fields on user import

So this only applies to users? Changing title..

wusel’s picture

@#3:

This is the same problem as in
#1228062: Feeds integration.

How to import Profile2-fields for new users from one CSV-file?

Thanks in advance

Martin P.’s picture

Is there a resolution meanwhile? I have the same problem.

I have many additional fields für the Users, which i created as hidden fields (users should not edit the values manually). So I have to import the additional Values

AND

i have to import the user role! that are the two most important aspects. Maybe this helps:

http://drupalcontrib.org/api/drupal/contributions!feeds!plugins!FeedsUse...

?? If anybody knows how to add my additional fields and the user role field as target for the feed user importer - please contact me :)

wusel’s picture

My solution you can find at http://drupal.org/node/1285276 ("Import new users and their Profile2 fields from one CSV file") using the module migrate.

But you have to change the code you find on that cookbook-page!

Good luck!

Martin P.’s picture

I think that wont be my way ^^ You did a good job by creating this tutorial. But i want to find a way to change the mapping and add targets on the Feeds Module. I thin this would be much more comfortable. Besides i dont want to install thousands of Modules für one Task. I think i will check how to add the fields to feeds user targets :)

Martin P.’s picture

Maybe this could help:

$account = user_load($uid); // Loading account
$edit = array(
  'field_some_custom_field' => array(
    'und' => array(
      0 => array(
        'value' => $new_value,
      ),
    ),
  ),
);
user_save($account, $edit);

What is 'field_some_custom_field' ? Where do i find, what name i have to write there? I want to add custom hidden fields as targets for Feeds Module (to import users automatically one time a day).

Maybe somebody can help me how to add this function in the FeedsUserProcessor.inc.php

I have found out, that you have to add 2 parts of code for every target you want to add. I have found the code for Adding User Roles for example:

    if ($account->roles_list) {
     $roles = explode(',', $account->roles_list);
     foreach ($roles as $role_name) {
       $role_name = trim($role_name);
       if (!$role = user_role_load_by_name($role_name)) {
         // Create new role if role doesn't exist
         $role = new stdClass();
         $role->name = $role_name;
         user_role_save($role);
         $role = user_role_load_by_name($role->name);
     }
       $account->roles[$role->rid] = $role->name;
     }
   } 

and

	  'roles_list' => array(
		'name' => t('User roles'),
		'description' => t('User roles'),
      ),

I also know, that the first part is to use / work with the the input (but i dont know where it gets saved) and the second part is for naming and describing the target for the backend UI. But i am not good enough to use this knowledge for adding other/additional user fields.

Maybe somebody could make an example?

Martin P.’s picture

I got the solution for this problem!

First: All Profile Fields i added were normal fields or hidden fields (Field Hidden-Module). I added them in the Account Configuration.

To add all the additional profile fields to the feeds user import you have to edit the "./sites/all/modules/feeds/plugins/FeedsUserProcessor.inc" file. Somerewhere you will find this code:

    // Remove pass from $edit if the password is unchanged.
    if (isset($account->feeds_original_pass) && $account->pass == $account->feeds_original_pass) {
      unset($edit['pass']);
    }

Lets call this code (A) and somewhere you will find this code:

    $targets += array(
      'name' => array(
        'name' => t('User name'),
        'description' => t('Name of the user.'),
        'optional_unique' => TRUE,
       ),
      'mail' => array(
        'name' => t('Email address'),
        'description' => t('Email address of the user.'),
        'optional_unique' => TRUE,
       ),
      'created' => array(
        'name' => t('Created date'),
        'description' => t('The created (e. g. joined) data of the user.'),
       ),
      'pass' => array(
        'name' => t('Unencrypted Password'),
        'description' => t('The unencrypted user password.'),
      ),
      'status' => array(
        'name' => t('Account status'),
        'description' => t('Whether a user is active or not. 1 stands for active, 0 for blocked.'),
      ),
      'language' => array(
        'name' => t('User language'),
        'description' => t('Default language for the user.'),
      )
    );

lets call it (B).

For every Field you want to add as Target for the Feeds User Importer you have to add the following:

After (A)

	if ($account->[PLACEHOLDERNAME]) {
	$edit['[FIELDNAME]'] = array(
			'und' => array(
				0 => array(
				'value' => $account->[PLACEHOLDERNAME],
				),
			),
	);
	}

[PLACEHOLDERNAME] could be something like city or maybe gender and [FIELDNAME] is the real name of the field you added in accountconfiguration (mostly: field_name) like field_gender.

Thats the first part. And additional you have to put another part IN (B)

      '[PLACEHOLDER]' => array(
        'name' => t('[PLACEHOLDER]'),
        'description' => t('[FIELDDESCRIPTION]'),
      ),

Part (A) should now look like this:

    // Remove pass from $edit if the password is unchanged.
    if (isset($account->feeds_original_pass) && $account->pass == $account->feeds_original_pass) {
      unset($edit['pass']);
    }

	if ($account->[PLACEHOLDERNAME]) {
	$edit['[FIELDNAME]'] = array(
			'und' => array(
				0 => array(
				'value' => $account->[PLACEHOLDERNAME],
				),
			),
	);
	}

and Part (B) should look like this (have a look at the commas after every part):

    $targets += array(
      'name' => array(
        'name' => t('User name'),
        'description' => t('Name of the user.'),
        'optional_unique' => TRUE,
       ),
      'mail' => array(
        'name' => t('Email address'),
        'description' => t('Email address of the user.'),
        'optional_unique' => TRUE,
       ),
      'created' => array(
        'name' => t('Created date'),
        'description' => t('The created (e. g. joined) data of the user.'),
       ),
      'pass' => array(
        'name' => t('Unencrypted Password'),
        'description' => t('The unencrypted user password.'),
      ),
      'status' => array(
        'name' => t('Account status'),
        'description' => t('Whether a user is active or not. 1 stands for active, 0 for blocked.'),
      ),
      'language' => array(
        'name' => t('User language'),
        'description' => t('Default language for the user.'),
      ),
      '[PLACEHOLDER]' => array(
        'name' => t('[PLACEHOLDER]'),
        'description' => t('[FIELDDESCRIPTION]'),
      )
    );

The last step (after you put in all the field you want to) you have to add

    user_save($account, $edit);

at the end of A. So the Solution could looke like this:

(A):

    // Remove pass from $edit if the password is unchanged.
    if (isset($account->feeds_original_pass) && $account->pass == $account->feeds_original_pass) {
      unset($edit['pass']);
    }
	if ($account->city) {
	$edit['field_city'] = array(
			'und' => array(
				0 => array(
				'value' => $account->city,
				),
			),
	);
	}	

	if ($account->gender) {
	$edit['field_gender'] = array(
			'und' => array(
				0 => array(
				'value' => $account->gender,
				),
			),
	);
	}	
    user_save($account, $edit);

(B):

    $targets += array(
      'name' => array(
        'name' => t('User name'),
        'description' => t('Name of the user.'),
        'optional_unique' => TRUE,
       ),
      'mail' => array(
        'name' => t('Email address'),
        'description' => t('Email address of the user.'),
        'optional_unique' => TRUE,
       ),
      'created' => array(
        'name' => t('Created date'),
        'description' => t('The created (e. g. joined) data of the user.'),
       ),
      'pass' => array(
        'name' => t('Unencrypted Password'),
        'description' => t('The unencrypted user password.'),
      ),
      'status' => array(
        'name' => t('Account status'),
        'description' => t('Whether a user is active or not. 1 stands for active, 0 for blocked.'),
      ),
      'language' => array(
        'name' => t('User language'),
        'description' => t('Default language for the user.'),
      ),
	  'city' => array(
		'name' => t('city'),
		'description' => t('The City the user is from.'),
      ),
	  'gender' => array(
		'name' => t('gender'),
		'description' => t('The users gender.'),
      )
    );

Have fun :)

firfin’s picture

Nice work on figuring all that out Martin.
However, you do realize you have written a tutorial on hacking the feeds module, right? Every update of the module will erase your code and you may also get unexpected issues. See Do not hack core most of this page also applies to contrib modules.

A better approach is to try and create a patch for feeds or write a module for this. I think hook_feeds_processor_targets_alter() and a accompanying callback in feeds.api.php is your best bet for what you are trying to achieve.
Also see The developer's guide to Feeds especially the section on the mapping API.

Keep up the good work. ;-)

Martin P.’s picture

I dont got the time to solve these problem :( In my apprenticeship i have to find fast ways to solve those problems. Most time I am working with another cms (webEdition), which is much more simple and gives me a lot of posibilities too. In my apprenticeship I dont have any time to learn more about own modules or something like that :( So but I see the problem. For now this solution has to suffice.

MegaChriz’s picture

Issue summary: View changes
Status: Active » Closed (outdated)

I might not be sure what this issue is about, but as of today you can map to additional fields on the user account. For Profile2 support, see #1228062: Feeds integration.. As an alternative, you could also try the Feeds entity processor module.