Building an Online Petition feature in Drupal using CRM Core

Error message

The spam filter installed on this site is currently unavailable. Per site policy, we are unable to accept new submissions until that problem is resolved. Please try resubmitting the form in a couple of minutes.


Building a feature using CRM Core profile is easy. In this demo we will demonstrate the step-by-step instruction on how to do it. Please note this is a follow up and more in-depth guide to

What are we building

In this demo we will be building an “online petition” feature that allows a website to:

  1. Create an online petition for a particular cause.
  2. Collect information from petition signers such as name, email, city and state.
  3. Run a report to see how many people have signed the petition and optionally export the data to a spreadsheet.
  4. Display a counter to show how many people have signed a specific petition.

Why don’t we use Web-form

Webform is a popular and powerful data collection tool in Drupal. It can be used to achieve the items that are laid-out above, so why not use it?

  • Insufficient views integration
    To show the actual webform submission data, additional modules (webform views, data module, etc have to be installed and configured)
  • Type of information it can collect
    Webform does not use entity-field API therefore it is missing the ability to collect complex data types such as phone number, address, etc.
  • Lack of normalization
    Webform does not differentiate if information should belong to a contact, an activity, or others. If we create another petition and some signers from previous petition signed the new one we will have to do data correlation to determine that information and link the two petition signatures.

What you need

To get started, your will need to have CRM Core modules running on your Drupal installation and have the CRM Core Profile module enabled. The easiest way to get started is to grab a quick CRM Core Demo installation profile from github.

You should also be familiar with the Features module and exportable objects. Knowledge of using CRM Core and views is recommended as well.

Building the components

Creating a “Petition” content type

We will first start by creating a content type called “Online petition”, this content type will hold information about any particular petition.

It will contain the following fields:


  • Body (Petition description)
  • Goal (integer) – A number we are looking to reach.
  • Image
  • Petition duration (date) – A date until which this petition will be active.

Verify contact fields exists

We mentioned that we would like to collect the name, email, city and state of the petition signer; that means those fields should exist in the contact type. If they do not exist let’s add them:

  • Contact Name: (a name field)
  • Email: (an email field)
  • Address: (postal address field)

In the example above, the “individual” contact type already has both a name field and an email field. It also has a billing address field, but we will create another field for the petition signing address.

Creating an “petition signature” activity type

The next step is to create a petition signature activity type which we will store the information about the petition signature. We will create the additional fields:

  • Public display (whether the petition signer gives consent to display his/her name on a public list of petition signers)
  • Petition Reference (A reference field back to the online petition content)

Create a CRM Core Profile form

Now we have created all of the components that will store online petition data. We have a content type, a contact type “individual” and an activity type “petition signature”.

The last step in configuration will be to create a CRM Core profile form, which will essentially be “the petition signing form”.

There are a couple of things we would like to customize on the form:

  1. We’d like to make the submit button say “Sign”
  2. We do not wish to collect the entire address; instead we only want to collect city and state information.

We will visit these 2 issues in the “Additional Customization” section below.

Export the feature

Now it’s time to export everything we have done into a “feature” module.

Additional Customization

Now that we have our “feature” exported, we can now implement additional customizations. We will do the following:

1. Permission
We want to introduce a permission so that only certain user roles can view the petition signing form. In this particular use case we don't have a great need for a permission, since we would like to allow everyone including anonymous users to be able to sign our petitions. Since many other use cases will require it, though, we include it for completeness.

// crm_core_petition.module

 * Implements hook_permission
function crm_core_petition_permission() {
  return array(
'crm_core sign online petition' => array(
'title' => t('Allow online petition signing'),
'description' => t('Ability to use petition signing form on online peition pages'),

2. Customize UI
The aforementioned customization on the form needs to be performed. We would also like to show the petition form on the petition content itself.

 * Implements hook_node_view
function crm_core_petition_node_view(&$node, $view_mode) {
   if (!
user_access('crm_core sign online petition')) {

// let's embed the petition signing form on the online petition content itself
if ($node->type == 'online_petition') {
$crm_core_profile = crm_core_profile_load('petition_signing_form');
    if (!empty(
$crm_core_profile)) {
module_load_include('inc', 'crm_core_profile', 'crm_core_profile.forms');
$node->content['crm_core_petition_form'] = drupal_get_form('crm_core_profile_entry_form', $crm_core_profile);     
$node->content['crm_core_petition_form']['#weight'] = 999;

The above code simply embeds the petition signing form we have created earlier into the petition content.

 * Implements hook_form_FORM_ID_alter().
function crm_core_petition_form_crm_core_profile_entry_form_alter(&$form, &$form_state, $form_id) {
$profile = $form_state['profile'];

// making sure we are on the correct crm_core_profile
if ($profile['name'] != 'petition_signing_form') {

// adding css class to the form for additional style customization
if (empty($form['#attributes']['class'])) {
$form['#attributes']['class'] = array('crm_core_petition_signing_form');
  else {
$form['#attributes']['class'] += array('crm_core_petition_signing_form');
// Change the form button value and hide some of the address components
$form['submit']['#value'] = t('Sign the petition');
$form['field_contact_address'][LANGUAGE_NONE][0]['street_block']['#access'] = FALSE;
$form['field_contact_address'][LANGUAGE_NONE][0]['locality_block']['postal_code']['#access'] = FALSE;
$form['field_contact_address'][LANGUAGE_NONE][0]['country']['#access'] = FALSE;  

We also do some UI customization such as adding CSS class to the form and hiding parts of the address field we don't need (street, locality, and country blocks).

3. Misc.
There are other things we would like to do such as setting a default value on the petition signature activity.

 * Implements hook_crm_core_profile_activity_alter().
 * We are just setting some default value to the crm_core_profile form in the activity data container
 * the $form here refers to the $form['activity'] data container from the original crm_core_profile form
function crm_core_petition_crm_core_profile_activity_alter(&$form, $profile_name) { 
  if (
$profile_name != 'petition_signing_form') {
// since we are embedding the online petition form in the content itself, we can get the content information
  // as well
$node = menu_get_object();
// we are just setting the reference (association) of the activity back to the petition content
$default_value = sprintf('%s (%s)', $node->title, $node->nid);
$form['field_crm_petition_reference'][LANGUAGE_NONE][0]['target_id']['#default_value'] = $default_value;

All done in less than 100 line of code. We can now test our feature.

Reporting and more

Now let’s create a simple report to show how many people have signed a particular petition as well as all the petition signers for a petition. We will also create a block counter to show the number of people who have signed the petition.

We will be using views and views data export module to achieve our goal.

Now that we have a general report showing a list of petitions created online, let’s create the petition signer report for an individual petition.

We now have a pretty good report showing all the signers of a petition as well. We can also create a petition signer count block and place it on the petition content:

Lastly, let’s update our feature with the report and other new components created.

That’s it, now you have a fully working online petition feature that can be deployed on any Drupal website with CRM Core and CRM Core Profile enabled.

Take it one step further

Let’s suppose that the following additional requirements have come in:

  1. We also want to track the source of the petition signers. We want to know if they came from an email campaign, a paid search engine campaign, or some other source.
  2. Upon successful signing of a petition, we want the user to be redirected to a customized thank you page where he/she can forward the petition to a friend, spread the word on social media, or take another action on the website.
  3. Suppose that we would like to make the petition time sensitive so they can only be signed in a specific time intervals and they will automatically become unavailable after the time has expired.

How would you go about implementing these additional requirements? Post your ideas in the comments, and we'll be happy to discuss them with you.