Salesforce Suite, pt. II: Return of Salesforce Suite

Over a year after my last post on Drupal-Salesforce integration, some of my wishes have been answered, at least for Drupal 7 users.

The Salesforce Suite 7.x-3.x release is a total reworking of the codebase. It is based on the OAuth API for Salesforce, which means you no longer have to worry about keeping your WSDL up to date. The module just works out of the box, as long as you have Entity API installed.

In 7.x-3.x, the Suite now consists of four main modules: Salesforce API, Salesforce Mapping, Salesforce Push, and Salesforce Pull.

The Salesforce SOAP module is also included as a small wrapper module for using Salesforce methods not provided by the OAuth API. Salesforce SOAP uses the PHP Partner Client though, not the Enterprise Client used by previous versions, so a WSDL is still not necessary. The Libraries module is used to manage the location of the Partner Client.

Initial Setup: Authorization

The OAuth authorization screen for the Salesforce Suite

The OAuth authorization screen for the Salesforce Suite

To use the Salesforce Suite, you must first go to the Configuration section of the admin interface to grant OAuth authorization to your Drupal site. This requires a consumer key and secret, which you obtain from your Salesforce instance. The module has a good help page in the Drupal interface explaining how to set this up. One note I would add, however, is that if you are attempting to access a sandbox you need to modify includes/ so $this->login_url = '' rather than ''. There is an issue open on to discuss making this customizable.

Mapping Fields

Once you've authorized the Suite, you go to a configuration page in the Structure section of the admin interface to set up your mappings of Drupal objects to Salesforce objects. On that page you can either create a new mapping or import a mapping from another site.

The selection screen for field mappings

The selection screen for field mappings

For each mapping you wish to create, you must first choose a name for the mapping and what entities to map. The module uses AJAX to pull up the record type and fields from Salesforce once you've selected a Salesforce object.

Mapping the fields themselves is relatively straightforward, although you will need to grasp the distinction between what the module calls "Properties" of a Drupal entity, "Tokens", "Constants", and "Related entities". Properties are the actual entity values, like $node->published or $user->mail; tokens are what the Token API produces (though there is no interface for seeing what tokens are available); constants are simply static values. Related entities seem to be a way to pull in data from linked Drupal entities, such as the node author's user record or a term with which a post was tagged; however, I was unable to get them to work on my testing so far. There is one additional bug: the body property always seems to be available, even if a given node type doesn't have a body field.

The fieldmapping interface for controlling how a record syncs between Drupal and Salesforce

The fieldmapping interface for controlling how a record syncs between Drupal and Salesforce

On the Salesforce side, only regular fields are available, although the usability of the field dropdown degrades rapidly as your number of custom fields increases. I have an instance of Salesforce with nearly the maximum number of custom fields on Contact (500) and it is difficult to find the right one in the list, especially since it is not sorted in alphabetical order.

For each field that is mapped, you have the ability to determine whether the mapping is Drupal-to-Salesforce only, Salesforce-to-Drupal only, or "sync" (bi-directional). This is a distinct improvement in granular control over the previous versions of the Salesforce Suite. You can also specify whether a field is an external key, which can be useful for updating existing Salesforce records (for example, by matching email).

However, in order for the key functionality to work, the field must be set as an External ID in Salesforce, which means you can't match on the core Salesforce Email field since that field can't be set as an External ID. This is a step backward from the Salesforce Prematch module which used to be available, since that could match records based on any field or combination of two or three fields in Salesforce. Hopefully, something similar to Salesforce Prematch will be added back in a future version of the Suite.

The other significant regression in the 7.x-3.x fieldmapping interface as compared to previous versions is that it doesn't automatically add in the required Salesforce fields to the mapping, so you have to know in advance what those are and ensure that you have all of them mapped.

After you've finished mapping fields, you need to specify which actions on both the Drupal and Salesforce side will trigger an sync. On either side, you can choose from create, update, and delete. The Salesforce Push module handles the actions on the Drupal side and the Salesforce Pull module handles the actions on the Salesforce side. You can also set actions to go into a queue to be processed asynchronously when cron is run. Furthermore, if you enable the queue, you can send over items in batches, which cuts down on API requests.

Improvements Over Previous Versions

This new push/pull paradigm, made possible by the OAuth API, is a dramatic improvement over the export/import paradigm in previous versions of the Salesforce Suite. Queueing used to be an add-on to the base Suite, and worked inconsistently in 6.x and not at all in 7.x-2.x (note: 7.x-1.x was never released). Now Drupal and Salesforce can simply listen for changes to the mapped entities, and take action as needed. The queue is baked in to the system for maximum stability. The updates from Salesforce take place only when cron runs, but on a well-maintained site that should be frequent enough not to pose problems.

Testing Your New Fieldmapping

The screen shown when you have synced a record to Salesforce

The screen shown when you have synced a record to Salesforce

After finishing your mapping, it's time to test. You'll be pleased to note that the Suite prints out a message at the top of the page when a sync occurs in real-time, indicating what the Salesforce ID is for the synced Drupal entity. Unfortunately, the Salesforce tab present on an entity page in earlier versions of the Salesforce Suite has been taken away, so you can't view the entity's Salesforce data from within Drupal. There are only two facts shown on the entity page: the time of the last Salesforce sync, and the Salesforce ID (as a hyperlink to the Salesforce record). In most cases, these may be sufficient, but the more detailed breakdown will be missed.


Like any modules still under development, the Salesforce Suite 7.x-3.x modules have some issues. Aside from those I already noted, there is an "Undefined variable: entity_type in salesforce_push_cron()" notice when I run the cron to sync Drupal entities to Salesforce. It doesn't seem to have any adverse effects, however. More significantly, I created a mapping of Drupal nodes to Salesforce Leads, set the changes to be pushed on cron in a queue, and discovered that the record type I had selected for the nodes wasn't being set. In the case of immediate pushes to Salesforce, however, it appears that the record type is set properly.


Despite the bugs, and some things lacking that were in previous versions of the Suite (prematching and outbound message support, largely), the Salesforce Suite 7.x-3.x is a major accomplishment and a great advance over previous versions. The simplicity of the OAuth API and the stability of the queue system combine to make it the clear choice for Salesforce integrations moving forward. I am excited to see what projects I can do with it in the coming months.

I'm also curious to know how other people are using Salesforce Suite 7.x-3.x. If you have experience with it, share it in the comments below. Because of my maintainership of the Ubercart/Salesforce Integration module for Drupal 6, I'm especially interested to know of any Ubercart or Drupal Commerce integrations that people may have pulled off.

We want to work with you!