Building an Online Petition feature in Drupal using CRM Core

Nov
07

Introduction

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 http://www.trellon.com/content/blog/building-crm-core-feature.

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:

    Title

  • 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.

<?php
// 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.

<?php
/**
* Implements hook_node_view
*/
function crm_core_petition_node_view(&$node, $view_mode) {
  
   if (!
user_access('crm_core sign online petition')) {
     return; 
   } 

  // 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.

<?php
/**
* 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') {
    return;
  }

  // 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.

<?php
/**
* 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') {
    return; 
  }
 
 
// 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.

AttachmentSize
crm_core_petition-7.x-1.0-dev.tar67 KB

8 Comments

That is really interesting to

That is really interesting to see how the pieces can fit together. However, taking a step back this seems like it shouldnt require this much code (or any really) to complete something of this nature. Are there additional things planned that will make this easier and require less/no code?

Hi, Short answer is yes.

Hi,

Short answer is yes. There are patterns of building simple applications that emerges that eventually will going to the platform that allows creating features with even less or no code at all.

Hello, You explain why web

Hello,

You explain why web forms doesn't make much sense to you use. However, what about entity forms? It seems like entity forms would remove the need for the coding but I am not sure how well it integrates with your system. Can you please provide a little insight on that option? Cheers Kevin

I haven't tried it, but I

I haven't tried it, but I don't think it would take much to integrate. Submissions would be associated via submission uid and the related crm core contact for the user. This is something you can build in a view and display as a tab on each contact (if that's the sort of integration you're looking for). Any other reports, you would also need to build (maybe with views) to support matching users to contacts. I.e. entityform would not know about how a user relates to a contact in the crm, so any data on the contact you want to display or export would need to perform that lookup. Hope this helps.

Anonymous users are another

Anonymous users are another kettle of fish. E.g. you would want to collect an email and name on the form and then create a contact based on those fields on the form - this is not nearly as easy. This is something that crm_core_profile module attempts to handle, but doesn't deal with the case of attaching profile fields to another form (or entity). We're working on it :)

Hi, Am using CRM Core now.

Hi,

Am using CRM Core now. However I need to create a form whereby I have multiple child data (1-to-many relationship), e.g. a main participation form, with multiple participant names and contacts under the same form.

How could I do that?

Regards.

too much coding, not

too much coding, not maintainable by end users who'll feel overwhelmed immediately, after reading all these, finally decided to stick with Redhen CRM which integrates with Entity Registration & Redhen Membership easily, don't really expect the end users to write codes to launch any events. Anyway, thanks a lot for the tutorials.

This is cool, I am trying to

This is cool, I am trying to make a site like http://moveon.org. This is helpful, since I have to create a petition form which is accessible to anonymous user and upon creation of a petition user have to signup first.

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Lines and paragraphs break automatically.
  • You may post code using <code>...</code> (generic) or <?php ... ?> (highlighted PHP) tags.

More information about formatting options