How to Easily Create Drupal Webforms in Code

Drupal webforms are useful in a variety of contexts, but the most typical context is something like a contact form: user-facing functionality that needs to exist when a site launches, and be easily edited by a site owner post-launch. In that context, webforms should be created automatically for a smooth, predictable launch. There are a few ways you can do that, including the Webform Features module, the Universally Unique IDentifier (UUID) module or custom code, maybe following documentation on Drupal.org.

When making webforms on a recent site, none of these options appealed to me. I wanted to manage webforms in code pre-launch, then hand them to a content editor to manage (outside code) post-launch. The Features-based options for creating webforms were okay pre-launch, but would add overhead post-launch. And creating a webform node from scratch seemed overly complicated to manage pre-launch. So I wrote the interface I wanted for creating and managing Drupal webforms, and it's now in the Config in Code (CINC) module for anyone to use.

Here's the example linked above from Drupal.org, implemented in this new CINC-based approach:

$webform = CINC::init('Webform')->machine_name('Contact Us');
 
$components = array();
 
$components[] = CINC::init('WebformComponent')->set('form_key', 'gender')
  ->set('type', 'select')
  ->set('mandatory', 1)
  ->set('extra.items', "Mrs|Mrs\nMiss|Miss\nMr|Mr")
  ->set('extra.aslist', 1);
 
$components[] = CINC::init('WebformComponent')->set('form_key', 'name')
  ->set('name', 'Last name')
  ->set('mandatory', 1);
 
$components[] = CINC::init('WebformComponent')->set('form_key', 'first_name')
  ->set('mandatory', 1);
 
$components[] = CINC::init('WebformComponent')->set('form_key', 'city');
 
$components[] = CINC::init('WebformComponent')->set('form_key', 'country')
  ->set('type', 'select')
  ->set('extra.options_source', 'countries')
  ->set('extra.aslist', 1);
 
$components[] = CINC::init('WebformComponent')->set('form_key', 'email_address')
  ->set('type', 'email')
  ->set('mandatory', 1);
 
$components[] = CINC::init('WebformComponent')->set('form_key', 'subject')
  ->set('type', 'select')
  ->set('extra.items', "s1|Subject 1\nother|Other")
  ->set('extra.aslist', 1)
  ->set('mandatory', 1);
 
$components[] = CINC::init('WebformComponent')->set('form_key', 'message')
  ->set('type', 'textarea')
  ->set('mandatory', 1);
 
$components[] = CINC::init('WebformComponent')->set('form_key', 'mandatory_fields')
  ->set('type', 'markup')
  ->set('value', '<p>Fields with * are mandatory</p>')
  ->set('extra.format', 'full_html');
 
foreach ($components as $index => $component) {
  $webform->add_component(
    $component->set('weight', $index * 5)->set('extra.title_display', 'inline')
  );
}
 
$webform->add_email('somebody@example.tld');
 
$webform->create();

The line count on that (52) is less than a third of the non-CINC example on Drupal.org (170), and did not require any time clicking around in a browser to create and export the webform. The code is also far more readable than both a Features export and starting from scratch, which makes it more maintainable. You may look at that "city" component and think I left something out, but that's really the entire code needed for a textfield with a name matching its form_key. Sensible defaults are nice.

As an added bonus, the CINC interface can also be used to read, update, and delete existing webforms. So if you need your Drupal webforms in code and Features isn't the best option for some reason, I invite you to enjoy the ease of creating webforms programmatically with CINC.

Code Drupal Drupal Planet

Read This Next