Clone this into your extension folder, enable this civicrm extension. and voila.
This extension allows an external petition tool to synchronise the action taken there with CiviCRM. The petition tool simply push each action to a rest interface provided by this extension, that then transform them into the entities civicrm knows.
Campaign->CiviCRM Campaign Signature->Activity type "petition signature" AND either
- create the contact if needed (and do the opt-in "click here to confirm" email)
- update the contact if needed
The petition tool doesn't have a notion of "unique user" (eg. an id) that they send to the CRM, so we use the email as the unique identifier (ie. each email is a single person). This is obviously not 100% true, but the alternative (several persons can share an email), did create lots of invalid duplicates, because the same person would use different name (eg Bob vs Robert, Maria Lopez Gonzales vs Maria Lopez, Jean Christophe vs Jean-Christophe...). So for now, each email identifies uniquely a person.
If opt-in mode is enabled, Each new contact (new email) has to "opt-in", ie. she will receive an email containing links, and needs to click on one of them. This should happen only onces, ie. once a person has confirmed they want to be contacted, we don't need to ask them every time.
In confirmation email there are two links. First for confirmation the signature with agreement for receiving mailings. Second for only confirmation the signature without agreement (NO BULK EMAILS
switched on). Each message template for confirmation needs to contain #CONFIRMATION_BLOCK
.
Email is confirmed if a contact has a group Members
on status Added
.
We use a special group Members
to flag those that have been confirmed (ie. sent an email is "Pending", once clicked on the link is "Added"). __ If the contact is manually removed from that group, she will receive the opt-in email again next time they sign __
Once a contact accepts to be contacted, we need to assign it to one of the languages we use (eg. "french speaking..", "german speaking.."). I can be done manually (eg. everyone that signed a petition for a campaign in french can go to the french speaking group) but would be much easier if done automatically. It doesn't have to be real time, but can be done in batch mode every hour (or daily).
However, few rules:
- a contact should be in only one language group (eg. I shouldn't receive both english and french mailings).
- The latest "specific" (ie. everything but english) language of a petition the member signs is her preferred language
Language of campaign is determine by Internal name
in speakout. We use format like this 2015-11-TTIP-ES, where last -ES
determine the spanish language.
Country | language in Internal name | language in custom field |
---|---|---|
Danish | DK | da_DK |
Dutch | NL | nl_NL |
English | EN | en_GB |
French | FR | fr_FR |
German | DE | de_DE |
Greek | GR | el_GR |
Italian | IT | it_IT |
Polish | PL | pl_PL |
Portuguese | PT | pt_PT |
Romanian | RO | ro_RO |
Spanish | ES | es_ES |
It's possible to designate a gender of a user. If speakout petition has a additional field before a first name then user can select his gender. SpeakCivi extension convert those values in gender in CiviCRM. We use such positions: Female, Male and Unspecified.
If gender is specified during signing a petition then It could be possible to set up a proper prefix. For females is Mrs.
, for males is Mr.
for others is not setting at all. There is only one english language version.
If gender and language is specified then It could be possible to set up a proper email greeting. First of all we have to configure email greeting option groups with special format in description [locale]:[gender]
- examples
de_DE:F
stands for german females,fr_FR:M
stands for french males andit_IT:
stands for italian unspecified gender - In spanish version each gender has the same email greeting, so we have only one email greeting type as
es_ES:
Each contact in group Members
supposed to be a member of LANGUAGE language Members
group
title | name (internal, not visible from CiviCRM admin interface) |
---|---|
Danish language Members | da-language-activists |
Dutch language Members | nl-language-activists |
German language Members | de-language-activists |
Greek language Members | el-language-activists |
English language Members | en-language-activists |
Spanish language Members | es-language-activists |
French language Members | fr-language-activists |
Italian language Members | it-language-activists |
Polish language Members | pl-language-activists |
Portuguese language Members | pt-language-activists |
Romanian language Members | ro-language-activists |
Other speaking Activists (default) | other-language-activist |
- In SpeakCivi
group
is determined byname
, - Only IT team can update
name
value! Remember about this when you will be creating new one or changing names, - If language can't be determined or there isn't proper group then we use default group,
- On
Speakcivi API Settings
page we have such fields:Default language group Id
,Suffix of language group name
,
- Adding to such group is invoked after click on confirmation link (in both versions confirm and optout),
- Contact can have only one language group,
- If contact has already language group, new group is not added,
- If Speakcivi can't determine language group, default group is adding to contact,
- Default group is skipping during checking if contact has a language group.
Each contact in group Members
supposed to be a member of can speak LANGUAGE-SHORTCUT
tag
tag
is determined byname
,- Format:
can speak SHORTCUT-LANGUAGE
- this is necessary to find out proper tag by shortcut, Speakcivi API Settings
page we have a fieldPrefix of language tag name
with default value iscan speak
,- Examples:
can speak en
,can speak de
, - If tag doesn't exist It's creating new one,
- Contact can have many tags (not only one).
Country | Tag |
---|---|
Danish | can speak da |
Dutch | can speak nl |
English | can speak en |
French | can speak fr |
German | can speak de |
Greek | can speak el |
Italian | can speak it |
Polish | can speak pl |
Portuguese | can speak pt |
Romanian | can speak ro |
Spanish | can speak es |
Message templates for new and current users can be set up in custom fields at campaign edit form.
- We use two different message template,
message_new
for new users - body for the emails to the contacts that aren't already members and need to confirm their signature,message_member
for current users - body for the emails to the contacts that are already members and don't need to confirm their signature,
- each templates have a default content in proper language,
message_new
has to contain line <div>#CONFIRMATION_BLOCK</div>,message_member
has to contain line <div>#SHARING_BLOCK</div>,- It's possible to improve default content by edit in Edit Campaign form.
Content of messages and subjects are prepared by Smarty
. Therefore It's possible to use variables in such format:
Example of contact's variables:
First name: {$contact.first_name}
Last name: {$contact.last_name}
Display name: {$contact.display_name}
Special variables:
Link to confirm: {$url_confirm_and_keep}
Link to confirm and opt out: {$url_confirm_and_not_receive}
Content of messages are prepared by Smarty
. Therefore It's possible to create simple a/b test. Look at example:
{if $contact.id mod 2 eq 0}
Hi {$contact.display_name}
{else}
Hi {$contact.first_name}
{/if}
- Cautions! WYSIWYG editor adds additional HTML tags to line with smarty code! In order to save such template you need to:
- switch to
Source document
layout, - remove additional <p></p> tags,
- save campaign.
- switch to
There are two types of confirmation link in email - confirm and optout.
Template for confirm:
https://SITE
/civicrm/speakcivi/confirm?id={contact.contact_id}
&hash={speakcivi.confirmation_hash}
&cid=CID
&aid=AID
Template for optout:
https://SITE
/civicrm/speakcivi/optout?id={contact.contact_id}
&hash={speakcivi.confirmation_hash}
&cid=CID
&aid=AID
Where:
SITE
REQUIRED ;-) - our site,{contact.contact_id}
REQUIRED - token for contact id,{speakcivi.confirmation_hash}
REQUIRED - token for confirmation hash,CID
- Campaign ID from CiviCRM (not from Speakout!),- based on this id Speakcivi has a information about language of campaign and in next step speakcivi add user to language group and tag!
AID
- Activity ID- If AID is not set and CID is set then
- Speakcivi tries to find all activities for this campaign and changed their status
- If AID is not set and CID is set then
When user click on confirmation link in confirmation email then:
- contact is added to group
Members
, - unique activity
Join
type is added to contact- with subject
confirmation_link
, - with campaign if it's set in link,
- with parent activity set up to
Petition Signature
- with subject
So even If user clicks several times on the same confirmation link, only one unique Join
activity will be added to contact.
User receives confirmation email for new user when he/she is not member of Members
group.
- He/she has to click on confirmation link in order to confirm his/her signing,
- email contains #CONFIRMATION_BLOCK,
- after click user receives confirmation email for current user in order to share.
User receives confirmation email for current user when
- he/she is member of
Members
group or - he/she is from UK
- email contains #SHARING_BLOCK
source param | destination custom field |
---|---|
$param->source->source | utm_source |
$param->source->medium | utm_media |
$param->source->campaign | utm_campaign |
source param | destination custom field |
---|---|
$param->source->source | source |
$param->source->medium | medium |
$param->source->campaign | campaign |
source param | destination custom field |
---|---|
$param->source->source | source |
$param->source->medium | medium |
$param->source->campaign | campaign |
source param | destination custom field |
---|---|
$param->metadata->tracking_codes->source | source |
$param->metadata->tracking_codes->medium | medium |
$param->metadata->tracking_codes->campaign | campaign |
$param->metadata->tracking_codes->content | content |
- Campaign is retrieved by
external_id
- If campaign doesn't exist in CiviCRM It will be created based on information from Speakout API
- Language of campaign is determined by name
- example: Name EN, Name_EN
- language: en_GB
- Language of campaign is determined by name
- Campaign has custom fields
optin message id
- id of message template which will be used in confirmation emaillanguage
- campaign languagesender email
- who is a sender of a email
- petition
- create/get contact, add activity, send confirmation mail
- share
- create/get contact, add activity
SpeakCivi searches contact by primary email.
- If there isn't any contacts, SpeackCivi creates new one (New contact)
- If there is exactly 1 result, SpeakCivi choose this contact (Existing contact)
- If there are more than 1 results, SpeakCivi determine which of them is the most similar (Existing contact)
- the same first name, last name and primary email
- the oldest (the smallest id)
created_date
of contact is given from action datacontact type
: Individual- added to group
Members
on statusPending
preferred_language
based on language of campaignsource
-> value:speakout [action_type] [external_id]
- If
opt_in
= 1 (Default) -> activity status =Scheduled
- If
opt_in
= 0 -> activity status =Completed
- Do you want to be updated about this and other campaigns?
- If user choose
NO
then:- activity status =
Opt-out
- activity status =
- If user choose
- Activity type:
Petition
(fill out petition form)share
(click on button Share on facebook or Share on twitter)
- detail of activity = your comments from petition
- email content is based on
optin message id
- email has a link for confirmation with
contact id
activity id
campaign id
hash
- There are two types of confirmation:
- confirm with agreement for mailing
- in this case
NO BULK EMAIL
is set up toFALSE
- in this case
- confirm without agreement for mailing
- in this case
NO BULK EMAIL
is set up toTRUE
- in this case
- confirm with agreement for mailing
- If contact has a group on status
Pending
-> change status toAdded
- If contact doesn't have a group -> add group on status
Added
- If
activity id
is set up, then- If activity has a status
Scheduled
-> change status toCompleted
- If activity has a status
- If
activity id
is NOT set up and we have acampaign_id
, then- find all activities for this campaign
- If activity has a status
Scheduled
-> change status toCompleted
- If
campaign id
is set up, then- determine country by language
- change post url into
[country]/post_confirm
in order to present proper language version
- Add contact to group
Members
- Update address
- If contact has no address -> add new address
- If contact has 1 address -> update by new values
- If contact has more than 1 address ->
- update similar address by missing value
- add next if there aren't any similar address
- Send confirmation mail
- If
NO BULK EMAIL
is set up toTRUE
content of mail also contains#CONFIRMATION_BLOCK
- If
To increase the reliability and decrease the processing time, you can push the speakout activities to an AMQP broker and dispatch them to this extension.
- Make sure you have composer installed, or download it to the
amqp
directory of this extension. - Make sure the file
tools/path.inc
contains the path to your drupal site (without trailing slash) - Update you CiviCRM settings with the following constants, depending on your AMQP server:
- MAILJET_AMQP_HOST
- MAILJET_AMQP_PORT
- MAILJET_AMQP_USER
- MAILJET_AMQP_PASSWORD
- MAILJET_AMQP_VHOST
- From the amqp directory, run
php composer.phar install
(adapt if you have a global composer)
Manually:
From the amqp
directory: php consumer.php -q name_of_queue
(as the same user as CiviCRM)
The script does not ensure that the queue exists before reading from it.
The script consumes messages only when the load on the server is lower than SC_MAX_LOAD.