Picture
Phil Boden Drupal Developer and Themer
August 31, 2020

What We're Doing Here: Webforms and Third Party Integration

In Drupal 8, the Webform module can do a lot out of the box. It can do even more with the multitude of its contributed modules. But every now and then a situation arises where you need to get into the guts of create some custom webform magic to get the job done.

Overview: Submitting Results to a Third Party Site as a Query

We will look at one way to integrate the power of webforms with some third party integration and custom code. We are going to have a webform modify the submitted results into a query string, and redirect the user to a third party url with the query attached. We will use a remote submission handler to tell Drupal that when the form is submitted, it also needs to submit those values to a remote, third party URL. In our case, the third party site is bookdirect.com, the client is a Destination Marketing Organization (DMO) and we need to format the submitted values to work with their jackrabbit api. Ultimately, we are using a Drupal webform, to send the user to Bookdirect/Jackrabbit with their lodging search filled in.

Our remote submission handler will define our base URL, but outside of that, the handler doesn't give us much else to do what we need to do in the UI. And while we wanted to give our client the freedom to add more fields to the webform in the future, we wanted to keep it simple for them so they would only have to add the correct base URL and not have to worry about any code. 

For our form, it wasn't necessary to save any submitted results, however, we are going to use a webform api hook that fires right after a submission would normally be saved. That hook is hook_webform_handler_invoke_alter and hook_webform_handler_invoke_METHOD_NAME_alter.

More specifically, since we want to act after saving and everything else has ran, the hook we want is: 
hook_webform_handler_invoke_post_save_alter.

Even if the results are set to not save, webforms will still trigger this "post save" hook. Versions of these hooks are: 

  • hook_webform_handler_invoke_pre_create_alter
  • hook_webform_handler_invoke_post_create_alter
  • hook_webform_handler_invoke_post_load_alter
  • hook_webform_handler_invoke_pre_delete_alter
  • hook_webform_handler_invoke_post_delete_alter
  • hook_webform_handler_invoke_pre_save_alter
  • hook_webform_handler_invoke_post_save_alter

Looking at the method name in these hooks, you can see when they act on a webform submission. For example, if you need to alter a value before the submission is initially saved, you can use hook_webform_handler_invoke_pre_save_alter.

How We're Doing It: 10 Steps

Even though this example is based on working with Bookdirect, I will try to keep the code somewhat generalized so that you can hopefully adjust it to your needs.

1. Create a simple webform

For our form, we required a date form item with the name of start_date, a date form item with the name of end_date, and a taxonomy select form item with the name lodging_category, where we choose from a list of terms. Use any form items you need and adjust the code as needed. I will show you ways to alter those field values before passing them into our remote url query.

2. Add a remote submission handler to your webform

Once you have your webform, you need to add a remote submission handler. Go to your forms Settings tab, then click on Emails/Handlers. Click on Add Handler. Select Remote post handler from the modal and fill in the Completed URL as the base URL that we will be submitting to. Remember to Save your handler. You can also select or deselect what values will be submitted. For our case we only need the 3 form items. We will add some of our own values in the submission query later.

3. Make a module to hold your code

Create a new module or use an existing custom module. The hook and code will need to go into the MYMODULE.module file of your module. For instructions on how to create a module, please see the Drupal.org manual page on module creation

4. Declare your hook

In your MYMODULE.module file, add our hook snippet

/**
 *  Implements hook_webform_handler_invoke_post_save_alter().
 */
function MYMODULE_webform_handler_invoke_post_save_alter(\Drupal\webform\Plugin\WebformHandlerInterface $handler, array &$args) {

}

Make sure to adjust the MYMODULE name with the actual name of your module

5. Setting up some variables

To make things a little easier to play with, we will create some variables to help define our data and info that we will work with. Inside of your new function add:

$webform = $handler->getWebform();

$webform_submission = $handler->getWebformSubmission();

$webform_id = $webform->id();

$handler_id = $handler->getHandlerId();

 

6. Narrowing down our code

And since we want to make sure we only run on our desired webform and with our remote submission handler, add the following snippet after the variables:

if ($webform_id == 'FILL_IN_WITH_THE_ID_OF_YOUR_WEBFORM' && $handler_id == 'FILL_IN_WITH_THE_ID_OF_YOUR_REMOTE_HANDLER') {
    // Our magic goes here  
}

(make sure to update the IDs above with the actual ID's of your webforms.

7. Get your handler configuration

To get the configuration setup of your handler, use:

$configuration = $handler->getConfiguration();

To pull the settings out of that configuration, step into the settings array and look for the completed_url value.

$bookdirect_url = $configuration['settings']['completed_url'];

 

8. Alter your data

We need to alter the start_date data from what webform submits (MM-DD-YYYY), to what bookdirect requires (MM/DD/YYY). We will use the getElementData() on the webform submission data to pull out the initial submitted value. We will make our change to that submitted data, and then apply the altered value back into the submission array using the setElements() method. The same alteration needs to be done to the end_date field. 

$start_date = $webform_submission->getElementData('start_date');
$start_date = explode('-', $start_date);
$start_date = [$start_date[1], $start_date[2], $start_date[0]];
$start_date = implode('/', $start_date);
$webform_submission->setElementData('start_date', $start_date);

Another alteration we need to make for our example bookdirect form is to take the taxonomy term value and switch it out with a field value on that term. Our taxonomy terms have term id's that the webform uses in the select widget, but we need to submit a bookdirect ID that corresponds to those taxonomy terms. You can use this concept to switch out field values with different field values from different entities on your webform submissions.

// First check if a value was submitted.
if ($lodging_term_id = $webform_submission->getElementData('lodgingID')) {
    
    // Load up our term to test if it has a book direct value
    $lodging_term = \Drupal\taxonomy\Entity\Term::load($lodging_term_id);
    if ($lodging_term->hasField('field_bookdirect_id') && $bookdirect_id = $lodging_term->get('field_bookdirect_id')->first()->getValue()) {

        // If it has a bookdirect field and a value, switch out our tid value with our bookdirect ID value.
        $webform_submission->setElementData('lodgingID', $bookdirect_id['value']);
    };
};

 

9. Build your query

Get our submitted data.

$query = $webform_submission->getData();

Alter values into another key. Maybe the fields were created before you knew what the required name should have been for the final destination. In this example, start_date is now supposed to be checkin, but we can't easily change it on our webform.

$query['checkin'] = $query['start_date'];
unset($query['start_date']);
$query['checkout'] = $query['end_date'];
unset($query['end_date']);

Add some static values to our query that were not part of our submitted webform values. Since this is a bookdirect example, these are values that bookdirect requires, but we don't need or want to add to our form directly.

$query['widget_id'] = 'WIDGET_ID_HERE';
$query['campaign'] = 'CAMPAIGN_ID_HERE';

 

10. Build the URL and redirect the user

Build your URL with our built up query and send our user to the URL with a 301 redirect.

$url = \Drupal\Core\Url::fromUri($bookdirect_url);
$url->setOptions(array('query' => $query));
$destination = $url->toString();

$response = new RedirectResponse($destination, 301);
$response->send();

 

Final Code and Related Case Study

You can find the final code here on github. And you can read more about the client website here: Visit Rapid City Case Study.