Subscribe To Our NewsLetter
Share This Post:
Integrating Pipedrive, a powerful CRM tool, with a Drupal Webform can automate lead capturing, tracking, and data management. By using Webform, we can create a custom form and submit form data directly to Pipedrive, enabling a seamless flow of information from your website to your CRM
In this post, we’ll walk through the process of creating a Drupal Webform and then show how to configure a submit handler to send form data to Pipedrive.
Prerequisites
Before we begin, ensure that you have the following:
- A Pipedrive account and API access (API key).
- A Drupal installation with the Webform module installed and enabled.
Integrating Pipedrive with Drupal Webform: A Step-by-Step Guide
Step 1: Install the Webform Module in Drupal
The Webform module allows you to create forms and manage submissions in Drupal. To install the Webform module, follow these steps:
- Install via Composer: Open your terminal and run: composer requires Drupal/Webform
- Enable the Webform module
Step 2: Create the Webform
Now, let's create a simple web form that will collect information like Name, email, and message. This is the form whose data will be sent to Pipedrive.
1. Navigate to Structure > Webform
2. Click on Add Webform to create a new form.
3. Give it a name like "Contact Form" or "Lead Capture Form".
4. Add fields to the form. For example:
- Text field for Name
- Email field for Email Address
- Textarea for the Message
5. Save the form.
Step 3: Create a Submit Handler for Pipedrive Integration
To submit form data to Pipedrive, we need to create a custom submit handler. This handler will be triggered when the form is submitted, and it will send the data to Pipedrive's API.
Now, for this, you need to create one custom module in Drupal.Simply, if you are using a drush, you can use the command:
Drush generate module
Drush will prompt you to fill in details about your module. Here's what you'll be asked.
Module name: A human-readable name (e.g., My Custom Module).
Machine name: A lowercase machine-readable name (e.g., my_custom_module).
Path: The directory where the module should be placed. Typically, you'll choose modules/custom.
Description: A brief description of what your module does. Etc.
Or Simply, you can create a custom module:
1. Create a folder with the Name of the module, like custom_module, under the module>custom directory of your Drupal setup.
2. Create webform_pipedrive.info.yml file and place the below code
name: webform pipedrive
type: module
description: Use to connect webform with pipedrive API and configuration for API
package: Custom
core: 8.x
core_version_requirement: ^8 || ^9
dependencies:
webform:webform
3. If you may want to attach any specific css and JS, you can have a file like this in your module: Create webform_pipedrive.libraries.yml if you want to include any libraries.
# Custom module library for general purposes.
webform_pipedrive:
js:
js/webform-pipedrive.js: {}
css:
component:
css/webform-pipedrive.css: {}
dependencies:
- core/drupalSettings
4. Create webform_pipedrive.module if you need to use any hook or to include libraries.
function webform_pipedrive_preprocess_page(array &$variables) {
$variables['#attached']['library'][] = 'webform_pipedrive/WebformPipedrive';
}
5. Create webform_pipedrive.services.yml and place the below code.
services:
webform_pipedrive.PipedriveIntegration:
class: Drupal\webform_pipedrive\Service\PipedriveIntegration
6. Create a src folder. Directory: webform_pipedrive>src
7. Under Src > create Plugin folder and under Plugin create WebformHandler folder to create webform hander file.
Directory: webform_pipedrive>src>Plugin>WebformHandler
8. Now under WebformHandler folder create a directory to define you form class with the same name as your class like WebformPipedrive.php and use the below code:
?php
namespace Drupal\webform_pipedrive\Plugin\WebformHandler;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;
use Drupal\user\Entity\User;
use Drupal\user\RoleInterface;
use Drupal\user\UserInterface;
use Drupal\webform\Plugin\WebformHandlerBase;
use Drupal\webform\WebformSubmissionInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Http\ClientFactory;
use GuzzleHttp\Exception\RequestException;
use Drupal\webform\Entity\WebformSubmission;/**
* Webform example handler.
*
* @WebformHandler(
* id = "webform_pipedrive",
* label = @Translation("WebformPipedrive"),
* category = @Translation("WebformPipedrive"),
* description = @Translation("Send the values to the api on
* form submission."), cardinality =
* \Drupal\webform\Plugin\WebformHandlerInterface::CARDINALITY_UNLIMITED,
* results =
* \Drupal\webform\Plugin\WebformHandlerInterface::RESULTS_PROCESSED,
* submission =
* \Drupal\webform\Plugin\WebformHandlerInterface::SUBMISSION_OPTIONAL, * tokens = TRUE,
* )
*/
class WebformPipedrive extends WebformHandlerBase { /**
* The user Account.
*
* @var \Drupal\user\UserInterface
*/ /**
* The entity Field Manager.
*
* @var \Drupal\Core\Entity\EntityFieldManagerInterface
*/
protected $entityFieldManager; /**
* The language Manager.
*
* @var \Drupal\Core\Language\LanguageManagerInterface
*/
protected $languageManager; /**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
$plugin = parent::create($container, $configuration, $plugin_id, $plugin_definition);
$plugin->entityFieldManager = $container->get('entity_field.manager');
$plugin->languageManager = $container->get('language_manager');
return $plugin;
} /**
* {@inheritdoc}
*/
public function defaultConfiguration() {
return [
'endpoint' => 'your_endpoint_url',//to set default value in configuration
'access_token' => your_access_token,//to set default value in configuration
'enable_mapping' => false,
'user_field_mapping' => [],'user_field_mapping_org' => [],
];
} /**
* {@inheritdoc}
*/
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
/** @var \Drupal\Core\Session\AccountProxyInterface $user */
Get webform settings.
/** @var \Drupal\webform\WebformInterface $webform */
$webform = $this->getWebform();
$webform_settings = $webform->getSettings();
$mapping_options = $this->getMappingOptions();
// configuration field to add endpoint url
$form['mapping']['endpoint'] = [
'#type' => 'textfield',
'#title' => $this->t('End Point'),
'#required' => TRUE,
'#default_value' => $this->configuration['endpoint']
];// configuration field to add access_token key
$form['mapping']['access_token'] = [
'#type' => 'textfield',
'#title' => $this->t('Access Token'),
'#required' => TRUE,
'#default_value' => $this->configuration['access_token']
];
// configuration checkbox field to enable for organisation form field mapping
$form['mapping']['enable_mapping'] = [
'#type' => 'checkbox',
'#title' => $this->t('Is Organisation'),
'#description' => $this->t('Check this box to enable mapping of webform elements to Organisation fields.'),
'#default_value' => $this->configuration['enable_mapping'],
'#parents' => ['settings', 'enable_mapping'],
];
// configuration fields for organisation form field mapping
$form['mapping']['user_field_mapping_org'] = [
'#type' => 'webform_mapping',
'#description' => $this->t('Map webform element values to organisation fields.'), '#required' => FALSE,
'#source' => $mapping_options['source'],
'#destination' => $mapping_options['orgdestination'],
'#default_value' => $this->configuration['user_field_mapping_org'],
'#source__title' => $this->t('Organisation Webform element'),
'#destination__type' => 'select',
'#destination__title' => $this->t('Organisation field destination'),
'#destination__description' => NULL,
'#parents' => ['settings', 'user_field_mapping_org'],
'#states' => [
'visible' => [
':input[name="settings[enable_mapping]"]' => ['checked' => TRUE],
],
],
];
// configuration fields for Person form field mapping
$form['mapping']['user_field_mapping'] = [
'#type' => 'webform_mapping',
'#description' => $this->t('Map webform element values to Persons fields.'),
'#required' => FALSE,
'#source' => $mapping_options['source'],
'#destination' => $mapping_options['destination'],
'#default_value' => $this->configuration['user_field_mapping'],
'#source__title' => $this->t('Persons Webform element'),
'#destination__type' => 'select',
'#destination__title' => $this->t('Persons field destination'),
'#destination__description' => NULL,
'#parents' => ['settings', 'user_field_mapping'],
]; return $form;
}
/**
* {@inheritdoc}
*/
public function validateForm(array &$form, FormStateInterface $form_state, WebformSubmissionInterface $webform_submission) {
parent::validateForm($form, $form_state, $webform_submission); /** @var \Drupal\user\UserInterface $account */
$account = NULL;
// Get the user data from the webform.
// $user_data = $this->getWebformUserData($webform_submission); $this->userAccount = $account;
}
/** * {@inheritdoc}
*/
public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
parent::validateConfigurationForm($form, $form_state); // Get the mapping between webform elements and user entity properties or
// fields.
$user_field_mapping = $form_state->getValue('user_field_mapping', []);
} /**
* {@inheritdoc}
*/
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
parent::submitConfigurationForm($form, $form_state);
$this->applyFormStateToConfiguration($form_state);
} /**
* {@inheritdoc}
*/
public function postSave(WebformSubmissionInterface $webform_submission, $update = TRUE) {
$submissionID = $webform_submission->id();
$webform_data = $webform_submission->getData();
$webform_name = $webform_submission->getWebform()->label();
$webform_uuid = $webform_submission->getWebform()->uuid();
$submission = WebformSubmission::load($submissionID);
$submission_uuid = $submission->get('uuid')->value;
$user_field_mapping = $this->configuration['user_field_mapping']; $enableMapping = $this->configuration['enable_mapping'];
$endPoint = $this->configuration['endpoint'];
$accessToken = $this->configuration['access_token']; $orgId = 0;
$user_field_mapping_org = [];
$orgData = [];
//to push submission source page url into notes
$submission_lead_source = '';
if (isset($webform_data['lead_source'])) {
$submission_lead_source = $webform_data['lead_source'];
}
//to check if the checkbox field checked for organisation forms fields if($enableMapping != false){
$user_field_mapping_org = $this->configuration['user_field_mapping_org'];
foreach ($user_field_mapping_org as $webform_key => $user_field) {
//to get phone number from the telephone field array
if($user_field == 'cfa2efceff7bcea1749bdf8414785a5d1a510a66'){
$orgData[$user_field] = $webform_data[$webform_key]['phone'];
}else{
$orgData[$user_field] = $webform_data[$webform_key];
}
}
//API service for organisation form
$orgId = \Drupal::service('webform_pipedrive.PipedriveIntegration')->sentWebformSubmissionToPipeDriveForOrganisation($orgData, $accessToken, $endPoint);
}
$personData = [];
$personData['org_id'] = $orgId;
foreach ($user_field_mapping as $webform_key => $user_field) {
if($user_field == 'phone'){
$personData[$user_field] = $webform_data[$webform_key]['phone'];
}else{
$personData[$user_field] = $webform_data[$webform_key];
}
}
//API service for person form
$apiResponse = \Drupal::service('webform_pipedrive.PipedriveIntegration')->sentWebformSubmissionToPipeDriveForPersonWithDeal($personData,$orgData, $accessToken, $endPoint , $orgId,$submission_lead_source); return $apiResponse;
}
/**
* Helper function to return a array of source and destination options.
*
* Source options would contain possible webform elements.
* Destination options would contain user entity properties and fields:
* [
* 'source' => [
* 'first_name'
* 'last_name' * ...
* ],
* 'destination' => [
* 'name'
* 'mail'
* ...
* ]
* ].
*
* @return array
* Array of source and destination options.
*/
protected function getMappingOptions() {
$source_options = [];
$destination_options = []; // Load all webform elements.
/** @var \Drupal\webform\Plugin\WebformElementInterface[] $webform_elements */
$webform_elements = $this->webform->getElementsInitializedFlattenedAndHasValue();
foreach ($webform_elements as $key => $element) {
$source_options[$key] = $element['#admin_title'] ?: $element['#title'] ?: $key;
} // Load all user entity fields.
/** @var \Drupal\Core\Entity\EntityFieldManagerInterface $entity_storage */
//person form fields
$user_fields = [
'name' => 'Name',
'first_name' => 'First Name',
'last_name' => 'Last Name',
'phone' => 'Phone',
'email' => 'Email',
];
//Organisation form
$organisation_fields = [
'name' => 'Name',
'9ad05aa82a1507d234ad6' => 'Whatsapp',
'512e497e9e941e5aa2ee8618' => 'Remarks',we
'512e497e9e941e5aa2ee8618' => 'Remarks1',
'512e497e9e941e5aa2ee8618' => 'Remarks2',
'512e497e9e941e5aa2ee8618' => 'Remarks3',bform_pipedrive
]; * @var string $key
* @var \Drupal\Core\Field\FieldDefinitionInterface $field
*/
foreach ($user_fields as $key => $field) {
$destination_options[$key] = $field;
}
foreach ($organisation_fields as $orgkey => $orgfield) {
$org_destination_options[$orgkey] = $orgfield;
}
return [
'source' => $source_options,
'destination' => $destination_options,
'orgdestination' => $org_destination_options,
];
}
9. Under src folder create Service Folder to create service file to handle Pipedrive Integration.
Directory: webform_pipedrive>src>Service
10. Create Service file with the name PipedriveIntegration.php
?php
namespace Drupal\webform_pipedrive\Service;
use Drupal\Core\DependencyInjection\ServiceProviderBase;
class PipedriveIntegration extends ServiceProviderBase {
/**
* Default generateTokensByResourceOwner implementation.
*
* @inheritDoc
*/
public function sentWebformSubmissionToPipeDriveForOrganisation($orgData, $accessToken, $endPoint) {
$org_id = '';
$endpoint_api_url = $endPoint."/v1/organizations?api_token=".$accessToken; $http_client = \Drupal::service('http_client');
// URL to which you want to make the POST request.
try { $response = $http_client->post($endpoint_api_url, [
'json' => $orgData,
'headers' => [
'Content-Type' => 'application/json', // Adjust the content type as needed.
],
]);
// Get the response body.
$response_body = $response->getBody()->getContents();
// Handle the response data as needed.
$data = json_decode($response_body, true);
if($data){
$org_id = $data['data']['id'];
}
return $org_id;
} catch (RequestException $e) {
// Handle exceptions or errors.
$message = $e->getMessage();
\Drupal::logger('webform_pipedrive response_body')->notice('<pre><code>' . print_r($response_body, TRUE) . '</code></pre>' );
}
return $org_id;
}
/**
* Default generateTokensByResourceOwner implementation.
*
* @inheritDoc
*/
public function sentWebformSubmissionToPipeDriveForPersonWithDeal($personData, $orgData, $accessToken, $endPoint , $orgId,$submission_lead_source) { $endpoint_api_url = $endPoint."/v1/persons?api_token=".$accessToken;
$http_client = \Drupal::service('http_client');
// URL to which you want to make the POST request.
$totalkids = $personData['no_of_child'];
// echo $totalkids;
unset($personData['no_of_child']);
// echo "<pre>";
// print_r($personData);exit();
try {try {
$response = $http_client->post($endpoint_api_url, [
'json' => $personData,
'headers' => [
'Content-Type' => 'application/json', // Adjust the content type as needed.
],
]);
// Get the response body.
$response_body = $response->getBody()->getContents();
// Handle the response data as needed.
// For example, output the response body.
$data = json_decode($response_body, true);
$person_id = $data['data']['id']; $deals = array(
'title' => '[Website] '. $personData['name'],
'person_id' => $person_id,
// 'pipeline_id' => 9,
'org_id' => $orgId,
);
$dealUrl = $endPoint.'/v1/deals?api_token='.$accessToken;
// $deals_data = json_encode($deals); $dealResponse = $http_client->post($dealUrl, [
'json' => $deals,
'headers' => [
'Content-Type' => 'application/json', // Adjust the content type as needed.
],
]);
$dealresponse_body = $dealResponse->getBody()->getContents();
$datadeal = json_decode($dealresponse_body,true);
$deal_id = $datadeal['data']['id'];
//create needed calculator fields to send the data as notes in pipedrive
$contact_person_at_the_company = "{Blank}";
$job_title = "{Blank}";
$full_phone_number1 = "{Blank}";
$email_address = "{Blank}";
$company_address = "{Blank}";/* Now we can override these variables and return any needed information */
if($orgData['company']){ $contact_person_at_the_company = $orgData['company'];
}
if($orgData['jtitle']){
$job_title = $orgData['jtitle'];
}
if($orgData['phone']){
$full_phone_number1 = $orgData['phone'];
}
if($orgData['email_address']){
$email_address = $orgData['email_address'];
} if($orgData['address']){
$company_address = $orgData['address'];
}
$html = '
<img src="your_image_url" style="margin-left: 6%;" alt="alt"><br><br>
<b><u>Web form submission summary</u></b><br><br>
<b>Group (Full name)/Organisation (Nom complet)</b><br>
'.$orgData['name'].'<br><br>
<b>Contact person at the company/Interlocuteur entreprise</b><br>
'.$contact_person_at_the_company.'<br><br>
<b>Job Title/Fonction</b><br>
'.$job_title.'<br><br>
<b>Telephone number/Téléphone</b><br>
'.$full_phone_number1.'<br><br> }else{
if($personData['company']){
$contact_person_at_the_company = $personData['company'];
}
if($personData['jtitle']){
$job_title = $personData['jtitle'];
}
if($personData['phone']){
$full_phone_number1 = $personData['phone']; }
if($personData['email_address']){
$email_address = $personData['email_address'];
} if($personData['address']){
$company_address = $personData['address'];
} <img src="your_image_url" style="margin-left: 6%;" alt="alt"><br><br>
<b><u>Web form submission summary</u></b><br><br>
<b>Group (Full name)/Organisation (Nom complet)</b><br>
'.$personData['name'].'<br><br>
<b>Contact person at the company/Interlocuteur entreprise</b><br>
'.$contact_person_at_the_company.'<br><br>
<b>Job Title/Fonction</b><br>
'.$job_title.'<br><br>
<b>Telephone number/Téléphone</b><br>
'.$full_phone_number1.'<br><br>
';
} $notice_endpoint_url = $endPoint.'/v1/notes?api_token='.$accessToken;
$noticedata = array(
'content' => $html,
"deal_id" => $deal_id,
"person_id" => $person_id,
'org_id' => $orgId,
"add_time" => date("Y-m-d h:i:s"),
);
$noticeresponse = $http_client->post($notice_endpoint_url, [
'json' => $noticedata,
'headers' => [
'Content-Type' => 'application/json', // Adjust the content type as needed.
], ]);
$noticeresponse_body = $noticeresponse->getBody()->getContents(); $noticeresult = json_decode($noticeresponse_body);
if($noticeresult){
$notice_id = $noticeresult->data->id;
}
// Set a status message.
// Get the response body.
// \Drupal::logger('webform_pipedrive response_body')->notice('<pre><code>' . print_r($response_body, TRUE) . '</code></pre>' );
// \Drupal::logger('webform_pipedrive response_body2')->notice('<pre><code>' . print_r($dealResponseBody, TRUE) . '</code></pre>' );
// drupal_set_message('Response: ' . $noticeresult);
} catch (RequestException $e) {
// Handle exceptions or errors.
// drupal_set_message('Error: ' . $e->getMessage(), 'error');
$message = $e->getMessage();
\Drupal::logger('webform_pipedrive response_body')->notice('<pre><code>' . print_r($response_body, TRUE) . '</code></pre>' );
}
}
11. You can call the service in you webform handler to process the submitted data to Pipedrive like in the screenshot.
$apiResponse = \Drupal::service('webform_pipedrive.PipedriveIntegration')->sentWebformSubmissionToPipeDriveForPersonWithDeal($personData,$orgData, $accessToken, $endPoint , $orgId,$submission_lead_source);
12. And then in the service file.
public function sentWebformSubmissionToPipeDriveForPersonWithDeal($personData, $orgData, $accessToken, $endPoint , $orgId,$submission_lead_source) {
After creating these files you can add code for configuration for the Access Key,API Endpoint and Users Field Mapping in the WebformPipedrive.php in point number 7 above.
Now you can add your logic to integrate the Webform data to Pipedrive for the API’s Like: Person,Deals,Organisation and can create notes as well for the API’s and can manage it from the webform handler using services as created in step number 10.
API Usage for Pipedrive
For Person API
public function sentWebformSubmissionToPipeDriveForPersonWithDeal($personData, $orgData, $accessToken, $endPoint , $orgId,$submission_lead_source) {
$endpoint_api_url = $endPoint."/v1/persons?api_token=".$accessToken;
$http_client = \Drupal::service('http_client');
try {
$response = $http_client->post($endpoint_api_url, [
'json' => $personData,
'headers' => [ 'Content-Type' => 'application/json', // Adjust the content type as needed.
],
]);
For Deal API
$dealUrl = $endPoint.'/v1/deals?api_token='.$accessToken;
// $deals_data = json_encode($deals);
$dealResponse = $http_client->post($dealUrl, [
'json' => $deals,
'headers' => [ 'Content-Type' => 'application/json', // Adjust the content type as needed.
],
]);
$dealresponse_body = $dealResponse->getBody()->getContents();
$datadeal = json_decode($dealresponse_body,true);
$deal_id = $datadeal['data']['id'];
And then you can also add notes HTML for the data like:
$notice_endpoint_url = $endPoint.'/v1/notes?api_token='.$accessToken;
$noticedata = array
( 'content' => $html,
"deal_id" => $deal_id,
"person_id" => $person_id,
'org_id' => $orgId,
"add_time" => date("Y-m-d h:i:s"),
);
$noticeresponse = $http_client->post($notice_endpoint_url, [ 'json' => $noticedata,
'headers' => [
'Content-Type' => 'application/json', // Adjust the content type as needed.
],
]);
$noticeresponse_body = $noticeresponse->getBody()->getContents();
After setup the code and create your login you need to Enable the custom module in the extend from the backend or by using drush command.
Step 4: Configure Webform to Use the Submit Handler
1. Navigate to Structure > Webforms, and edit your form.
2. Under Form settings, go to the Handlers tab.
3. Click Add handler and choose Custom handler.
4. Select the handler you created (WebformPipedrive) in step number 3.8 from the available handlers.
5. In the same webform handler screen you can check there is option available to add endpoint and access token for pipedrive.
6. Now you need to map the field of your webform with the destination field of Pipedrive which you define under the selected webform hander.
Step 5: Testing the Integration
- Go to your Drupal site and fill out the Webform.
- Submit the form
- Check your Pipedrive account to see if the new person (lead) was created with the form data.
In Conclusion
Integrating Pipedrive with Drupal Webform streamlines your lead management by automating form data submissions directly to your CRM. Following the steps in this guide, you can easily set up the integration, map form fields to Pipedrive, and test the process to ensure smooth data flow. This setup eliminates manual data entry, saving time and improving your workflow. Start leveraging this powerful integration today and enhance your lead management efficiency.
LN Webworks is the right Drupal development company for your business. We specialize in creating seamless integrations that optimize your business processes. Our expert team can help you implement and customize Drupal development services tailored to your unique needs.
Share This Post:
Author Information
Manpreet Singh
Drupal ExpertManpreet is a detail-oriented website and web application developer with 6+ of experience delivering solutions, ranging from small microsites to big portals, including corporate intranets. He has been building Drupal-powered sites since version 7.