adi_contact – Form field validation, spam prevention, email header/body extras, database update, MailChimp subscription

This plugin is used in conjunction with zem_contact_reborn and zem_contact_reborn v4.5+ to provide the following functionality:

  • submitted field combination check
  • submitted field content validation
  • anti-spam measures
  • database update
  • email header options (CC & BCC)*
  • append lines to email body*
  • MailChimp list subscription*

Once installed, a collection of new tags are available.

Validation & spam detection:

Email header/body options:*

Database update:

MailChimp list subscription:*

*Requires zem_contact_reborn v4.5+.

Use the above tags within a <txp:zem_contact> ... </txp:zem_contact> container. A full example of usage is provided at the end.

A number of additional CSS classes are automatically applied to help with styling.

Beware! If you’re using the database update feature, the load order for this plugin must be set higher than any other anti-spam plugins that interact with zem_contact (e.g. pap_contact_cleaner), otherwise there is a danger that the database will be updated with spam information. When you install or update adi_contact its load order will automatically be set to 9. Be aware of the consequences if you manually change this. Also, you should understand that if you are running plugins from the plugin cache (rather than installing them normally) then the load order cannot be determined or predicted.


Form field combinations (adi_contact_combo)

Sometimes certain combinations of form fields are required from users, for example:

  • fill in at least one of “Likes”, “Dislikes”, “Other comments”
  • if “Phone number” is filled in then “Best time to call” is also required
  • if “Region” is Other, then “Other Region” field is required

For example, to make sure the user fills in at least one field in a specified list:

<txp:zem_contact>
  ...
  <txp:zem_contact_textarea name="likes" label="Likes" required="0" />
  <txp:zem_contact_textarea name="dislikes" label="Dislikes" required="0" />
  <txp:zem_contact_textarea name="comments" label="Other comments" required="0" />
  <txp:adi_contact_combo names="likes,dislikes,comments"
    restrict="min" number="1" />
</txp:zem_contact>

Or if an extra field has to be filled in:

<txp:zem_contact>
  ...
  <txp:zem_contact_text name="phone" label="Your phone number"
    required="0" />
  <txp:zem_contact_text name="when" label="When should we call you?"
    required="0" />
  <txp:adi_contact_combo names="phone" require="when" />
</txp:zem_contact>

And to specify a required field depending on the value of a supplied field:

<txp:zem_contact>
  ...
  <txp:zem_contact_select name="region" label="Where do you live?"
    list=",UK,France,Germany,Other" />
  <txp:zem_contact_text name="region_other" label="If Other, then where?" required="0" />
  <txp:adi_contact_combo names="region" value="other" require="region_other"
    message="Where else do you live?" />
</txp:zem_contact>

You can also generate custom error messages by using required="0" in the standard ZCR tags and required="1" in adi_contact_combo. For example:

<txp:zem_contact>
  ...
  <txp:zem_contact_text name="name" label="Name" required="0" />
  <txp:adi_contact_combo names="name" required="1" message="Don't be shy!"/>
</txp:zem_contact>

No real magic here – required="1" is actually the equivalent of restrict="equal" number="1".

adi_contact_combo – attributes

names="name list"

- comma separated list of field names that are of interest. Default = “” (none).

value="value"

- If value specified then additional fields of interest will only be flagged if the supplied name field has this value. Default =”“ (required/restricted fields not dependent on value). Used in conjunction with require and restrict.

restrict="restriction"

- defines a minimum (min), a maximum (max), or an exact number (equal),

number="integer"

- number of fields, used in conjunction with restrict.

case_sensitive="boolean"

- defines whether to take notice of case when checking value. Default = “0” (case-insensitive).

require="name list"

- comma separated list of field names that are required (or if used with restrict then of additional interest), depending on the presence or values of fields in names list.

required="boolean

- the specified field is required (useful for creating custom error messages). Default = “0” (not required).

message="text"

- alternative error message (see below for list of placeholders).

checkbox

- this attribute is no longer valid (use adi_contact_checkboxes tag instead).


Form field validation (adi_contact_validate)

This enables the contents of fields to be validated, for example to check that a phone number field has been filled in properly:

<txp:adi_contact_validate names="home_phone" type="phone" />

Or to check that fields have been filled in the same (e.g. for double checking supplied email addresses):

<txp:adi_contact_validate names="email1,email2" type="equal" />

adi_contact_validate – attributes

names="name list"

- comma separated list of field names that should be validated. Default = “” (none).

type="validation"

- the type of validation that is required:

  • alpha – alphabetic characters
  • alphanum – alpha-numeric characters
  • integer – digits only
  • numeric – a number (e.g. +0123.45e6 is a number)
  • phone – phone number (i.e. 0-9 + – . , () xX space)
  • url – a URL (with or without “http://”)
  • custom – use in conjunction with pattern
  • equal – two or more field values must be the same
  • base64 – base64 encoded

allow_whitespace="boolean"

- allow whitespace (i.e. space, tab, newlines etc) in addition to that specified in type. Default = “0” (No).

pattern="pattern string"

- a PCRE pattern that will be dropped straight into preg_match. Used in conjunction with type="custom". Default = “” (none).

message="text"

- alternative error message.


Spam prevention (adi_contact_spam)

This will prevent email header injection and stop emails that contain links (which is, after all, what spammers want to send you).

By default adi_contact_spam will check all fields, so if you want users to send you links then use the exclude attribute:

<txp:zem_contact>
  ...
  <txp:zem_contact_text name="website" label="Your website URL" />
  <txp:adi_contact_spam exclude="website" />
</txp:zem_contact>

adi_contact_spam – attributes

names="name list"

- comma separated list of field names that should be checked. Default = “” (all submitted fields).

exclude="name list"

- comma separated list of field names that should NOT be checked. Default = “” (none).

detect_mail_headers="boolean"

- detect the presence of to:, from:, bcc:, multipart, cc:, Content-Transfer-Encoding:, Content-Type:, Mime-Version: and flag as spam if found. Default = “1” (Yes).

detect_link_tags="boolean"

- detect the presence of [url, http, www, href and flag as spam if found. Default = “1” (Yes).

allow_www="boolean"

- allow the presence of www and do not flag as spam. Default = “0” (No).

message="text"

- alternative error message.


Error messages, labels and styling (adi_contact_labels & the ‘message’ attribute)

The ‘message’ attribute

The adi_contact tags will generate standard error messages in English and are placed in the same list as the standard zem_contact error messages. The messages can be customised by using the message="" attribute:

  • alter the standard message
  • translate the standard message into other languages
  • use [NAMES] (‘names’ attribute), [REQUIRE] (‘require’ attribute) & [NUMBER] (‘number’ attribute) placeholders

For example, if adi_contact_spam finds a link, say, in a field called Comments then the standard error message will be:

Link detected in “Comments” ([url, http, www, href not allowed).

But you can customise the error message:

message="Nice try! No spam allowed in [NAMES]."

to produce:

Nice try! No spam allowed in Comments.

adi_contact_labels – attributes

name1="label string 1" name2="label string 2"

- the labels to use in adi_contact error messages.

Important: The adi_contact_labels tag MUST be placed in the page/form before other adi_contact tags – otherwise your label strings won’t be picked up.

Example:

<txp:adi_contact_labels phone="Phone number" when="When to call"
  likes="Likes" dislikes="Dislikes" comments="Comments" />

Notes:

  • a label specified with adi_contact_labels does not have to match the actual label used in the form
  • labels specified with adi_contact_labels are only used in adi_contact error messages
  • the error messages will use labels in the following order of preference:
    • label specified in adi_contact_labels
    • form label retrieved from zem_contact (but only if a field has been filled in & submitted)
    • the field name (with first letter in upper case)

Checkboxes (adi_contact_checkboxes)

If you are using adi_contact to validate checkboxes then you need to identify them as such. Not required if you are just using adi_contact to update a database.

adi_contact_checkboxes – attributes

names="name list"

- comma separated list of field names that are checkboxes. Default = “” (no checkboxes to be processed by adi_contact).

Important: The adi_contact_checkboxes tag MUST be placed in the page/form before adi_contact_combo tags – otherwise checkbox validation won’t work.

Example:

<txp:zem_contact_checkbox name="orange" label="Orange" required="0" />
<txp:zem_contact_checkbox name="apple" label="Apple" required="0" />
<txp:zem_contact_checkbox name="banana" label="Banana" required="0" />
  ...
<txp:adi_contact_checkboxes names="orange,apple,banana" />
<txp:adi_contact_combo names="orange,apple,banana" restrict="min" number="1" message="Eat some fruit!" />

Email header options (adi_contact_headers)

To send the contact form email to CC (carbon copy) or BCC (blind carbon copy) addresses:

<txp:adi_contact_headers cc="cc@example.com" bcc="bcc@example.com" />

adi_contact_headers – attributes

cc="email address list"

- comma separated list of email addresses to be CC’d. Default = “” (none).

bcc="email address list"

- comma separated list of email addresses to be BCC’d. Default = “” (none).


Email body text (adi_contact_body)

To append text to end of email body:

<txp:adi_contact_body line="A line of extra text." />

Note that if you’re using adi_contact_mailchimp then lines appended using adi_contact_body will appear before any MailChimp diagnostic information.

adi_contact_body – attributes

line="text"

- text to be appended to email message. Default = “” (blank line).


Database update (adi_contact_db & adi_contact_db_data)

To insert information supplied in a contact form into a database, you need to use a combination of the adi_contact_db tag together with a number of adi_contact_db_data tags.

The adi_contact_db tag defines the table to be updated in the TXP database. The adi_contact_db_data tag defines the mapping between contact input fields and database columns, as well as providing default value and timestamp options.

adi_contact_db – attributes

table="database table"

- a table in the TXP database. Default unset. This attribute must be specified and the database table must already exist.

form="form name"

- a optional form containing the adi_contact_db_data tags. Defaults to container mode.

adi_contact_db_data – attributes

db_field="database table column"

- a column in the table specified in the adi_contact_db tag. Default unset. Must be specified.

contact_field="input name"

- the name of an input field in the contact form. If not specified, it is assumed to be the same as the database column name.

default="value"

- default value to be use in the database if the input field is empty. Default = no default value used (database column default will be used instead).

timestamp="type"

- specifies that the date/time should be entered into the database column. Default = “0” (no timestamp). Valid types are “datetime” (yyyy-mm-dd hh:mm:ss), “date” (yyyy-mm-dd) & “timestamp” (yyyy-mm-dd hh:mm:ss UTC). If timestamp used, a contact form input field is not required.

Container mode example:

<txp:adi_contact_db table="contacts">
    <txp:adi_contact_db_data db_field="db_column_1" contact_field="input_field_a" />
    <txp:adi_contact_db_data db_field="db_column_2" contact_field="input_field_b" />
    <txp:adi_contact_db_data db_field="db_column_2" contact_field="input_field_c" default="unknown" />
    <txp:adi_contact_db_data db_field="name_1" />
    <txp:adi_contact_db_data db_field="name_2" />
    <txp:adi_contact_db_data db_field="timestamp" timestamp="datetime" />
</txp:adi_contact_db>

Notes:

  • the specified database table must be created manually
  • no checks are done on the data written into database, ensure that column data types are suitable
  • if no default is supplied in the tag, then the database column defaults will be used for empty form input fields
  • timestamp format is “yyyy-mm-dd hh-mm-ss”
  • in the above example:
    • if “input_field_c” is empty, “unknown” is written to the database
    • data from input fields “name_1” & “name_2” is written to database columns of the same name

Troubleshooting adi_contact_db

To troubleshoot issues with adi_contact_db, switch your website’s Production Status to “debugging”.

If there are issues with the existence/naming of database tables or columns then error messages will be generated. For more detailed information about what’s happening (or not) in the background, look in the page’s Tag trace for adi_contact logs.


MailChimp list subscription (adi_contact_mailchimp & adi_contact_mailchimp_data)

To subscribe to a MailChimp mailing list, use a combination of the adi_contact_mailchimp tag together with a number of adi_contact_mailchimp_data tags.

The adi_contact_mailchimp tag contains the MailChimp mailing list information. The adi_contact_mailchimp_data tag defines the mapping between contact input fields and MailChimp list fields.

The API key and List ID can be obtained from your MailChimp account.

API key:

  1. Go to Account page
  2. Then “Extras” > “API keys”
  3. Click “Create A Key”
  4. Make a note of the key, e.g. abc123abc123abc123abc123abc123-us1

List ID:

  1. Go to Lists page
  2. Click on the list you’re interested in
  3. Go to “Settings” > “List name & defaults”
  4. Make a note of ID, e.g. abcdef12345

adi_contact_mailchimp – attributes

api_key="api key"

- your MailChimp account API key. Default unset. Must be specified.

list_id="list id"

- your MailChimp mailing list ID. Default unset. Must be specified.

status="status"

- the subscription status to be applied. Default “pending” (confirmation email will be sent my MailChimp). Other values: “subscribed” (subscribe immediately WITHOUT user confirmation).

opt_in_field="input name"

- the name of an input field in the contact form for the user to signal mailing list subscription intention. Default = “mailing_list”. Use “” to switch off explicit opt-in.

opt_in_value="value"

- the value of the opt-in field in the contact form, to signal mailing list subscription positive intention. Default = “Yes” (in the website’s language), which is suitable for a checkbox.

form="form name"

- a optional form containing the adi_contact_mailchimp_data tags. Defaults to container mode.

adi_contact_mailchimp_data – attributes

mailchimp_field="field name"

- the name of a MailChimp list field. Default unset. Examples: “email”, “FNAME”, “LNAME”. Must be specified.

contact_field="input name"

- the name of an input field in the contact form. Default unset. Must be specified.

adi_contact_mailchimp_email – attributes

In its simplest form, this tag:

<txp:adi_contact_mailchimp_email />

is functionally equivalent to:

<txp:adi_contact_mailchimp_data mailchimp_field="email" contact_field="email" />

If you need to specifiy a different contact field name for the email address use:

contact_field="input name"

- the name of the email input field in the contact form. Default = “email” (use contact field called “email”).

Examples:

If all you want to do is take an address from a contact field called “email”, where the opt-in field is a checkbox called “mailing_list”, and send it to MailChimp:

<txp:adi_contact_mailchimp api_key="abc123abc123abc123abc123abc123-us1" list_id="abcdef12345" />

For more complicated scenarios, try something like:

<txp:adi_contact_mailchimp api_key="abc123abc123abc123abc123abc123-us1" list_id="abcdef12345" opt_in_field="subscribe">
  <txp:zem_contact_email name="the_email" label="Your email" />
  <txp:zem_contact_text name="first_name" label="First name" />
  <txp:zem_contact_text name="last_name" label="Last name" />
  <txp:zem_contact_checkbox name="subscribe" label="Please put me on the mailing list" checked="1" />
  <txp:adi_contact_mailchimp_email contact_field="email" />
  <txp:adi_contact_mailchimp_data mailchimp_field="FNAME" contact_field="first_name" />
  <txp:adi_contact_mailchimp_data mailchimp_field="LNAME" contact_field="last_name" />
</txp:adi_contact_mailchimp>

Notes:

  • the opt-in “mailing_list” contact field is a checkbox, which must be ticked by the user for the MailChimp subscription request to be generated
  • contact fields “first_name” and “last_name” are mapped to their MailChimp equivalents, these are optional
  • merge field names (e.g. FNAME) are case-sensitive

Troubleshooting adi_contact_mailchimp

To troubleshoot issues with adi_contact_mailchimp, switch your website’s Production Status to “debugging”.

For detailed information about what’s happening (or not) in the background, look in the page’s Tag trace for adi_contact logs.

If an attempt has been made to subscribe an email address to your MailChimp list, there’ll be information pertaining to this appended to the contact form email. If no attempt has been made to subscribe (e.g. if the opt-in field is not filled in) no extra information is added to the form email.


Javascript (adi_contact_javascript)

adi_contact will normally automatically insert javascript into the page, so that the error case styling classes can be added as appropriate. However, in the situation where zem_contact is implemented as two forms i.e. with show_input="0" and show_error="0" then <txp:adi_contact_javascript /> must be explicitly present in both forms. Make sure it is placed before all other adi_contact tags.


Styling

Classes are automatically added to form label and input/textarea elements when errors are found.

A class of adi_contact_error is always added, together with the following:

adi_contact_comboadi_contact_combo_error, zemRequirederrorElement**

adi_contact_validateadi_contact_validate_error, errorElement

adi_contact_spamadi_contact_spam_error, errorElement

**This class is no longer generated by zem_contact_reborn v4.5+, required fields are given errorElement class instead. adi_contact_combo generates both zemRequirederrorElement & errorElement.


The Full Monty Example

The following is an example of a user feedback form:

<txp:zem_contact to="me@example.com" subject="Feedback form example" browser_validate="0">

  <p>Please fill in the form:</p>

  <!-- the feedback form presented to the user -->
  <txp:zem_contact_select name="title" label="Title" options=",Mr,Mrs,Miss" />
  <txp:zem_contact_text name="name" label="Name" />
  <txp:zem_contact_radio name="gender" label="Male" group="Gender" />
  <txp:zem_contact_radio label="Female" />
  <txp:zem_contact_checkbox name="general" label="General enquiry" required="0" />
  <txp:zem_contact_checkbox name="sales" label="Sales enquiry" required="0" />
  <txp:zem_contact_checkbox name="technical" label="Technical enquiry" required="0" />
  <txp:zem_contact_checkbox name="feedback" label="Feedback" required="0" />
  <txp:zem_contact_email name="email" />
  <txp:zem_contact_text name="phone" label="Your phone number" required="0" />
  <txp:zem_contact_select name="region" label="Where do you live?" options=",UK,France,Germany,Other" />
  <txp:zem_contact_text name="region_other" label="If Other, then where?" required="0" />
  <txp:zem_contact_text name="when" label="When should we call you?" required="0" />
  <txp:zem_contact_textarea name="comments" label="Comments" required="0" />
  <txp:zem_contact_textarea name="likes" label="Likes" required="0" />
  <txp:zem_contact_textarea name="dislikes" label="Dislikes" required="0" />
  <txp:zem_contact_checkbox name="mailing_list" label="Please put me on the mailing list" break="" required="0" />

  <txp:zem_contact_submit label="Send feedback" />

  <!-- specify labels to be used in error messages -->
  <txp:adi_contact_labels phone="Phone number" when="When to call" comments="Comments" />

  <!-- identify which fields are checkboxes -->
  <txp:adi_contact_checkboxes names="general,sales,technical,feedback,mailing_list" />

  <!-- "region_other" field required if "region" field is set to other -->
  <txp:adi_contact_combo names="region" value="other" require="region_other" message="Where else do you live?" />

  <!-- male or female required -->
  <txp:adi_contact_combo names="gender" required="1" message="Male or Female?" />

  <!-- at least one of "general,sales,technical,feedback" required -->
  <txp:adi_contact_combo names="general,sales,technical,feedback" restrict="min" number="1" message="What type of enquiry?" />

  <!-- "comments" required for "general,sales,technical" enquiries -->
  <txp:adi_contact_combo names="general,sales,technical" require="comments" />

  <!-- at least one of "likes,dislikes" required for "feedback" enquiry -->
  <txp:adi_contact_combo names="feedback" require="likes,dislikes" restrict="min" number="1" />

  <!-- if "phone" supplied then "when" required as well; include custom error message -->
  <txp:adi_contact_combo names="phone" require="when" message="You've given me a [NAMES] but I need to know [REQUIRE] too" />

  <!-- if "mailing_list" supplied then "email" required as well -->
  <txp:adi_contact_combo names="mailing_list" message="To be on our mailing list, please provide your email address" require="email" />

  <!-- validate the phone number -->
  <txp:adi_contact_validate names="phone" type="phone" />

  <!-- check for spam but allow user to send simple "www." URLs -->
  <txp:adi_contact_spam allow_www="1" />

  <!-- record name, email, phone, nature of enquiry & timestamp in database table "contacts" -->
  <txp:adi_contact_db table="contacts">
    <txp:adi_contact_db_data db_field="fullname" contact_field="name" />
    <txp:adi_contact_db_data db_field="email_address" contact_field="email" />
    <txp:adi_contact_db_data db_field="phonenumber" contact_field="phone" default="no phone" />
    <txp:adi_contact_db_data db_field="general" />
    <txp:adi_contact_db_data db_field="sales" />
    <txp:adi_contact_db_data db_field="technical" />
    <txp:adi_contact_db_data db_field="feedback" />
    <txp:adi_contact_db_data db_field="timestamp" timestamp="1" />
  </txp:adi_contact_db>

  <!-- simple MailChimp subscription -->
  <txp:adi_contact_mailchimp api_key="abc123abc123abc123abc123abc123-us1" list_id="abcdef12345" />

  <!-- send copies -->
  <txp:adi_contact_headers cc="the_other_me@example.com" bcc="the_secret_me@example.com" />

  <!-- email note -->
  <txp:adi_contact_body />
  <txp:adi_contact_body line="This is a Full Monty test." />

</txp:zem_contact>

Notes:

  • the adi_contact_labels tag is placed before the other adi_contact tags (only the labels for ‘phone’, ‘when’ & ‘comments’ are specified here because they’re required to be different from the actual form labels)
  • the adi_contact_checkboxes tag is placed before the adi_contact_combo tags
  • a name has been explicitly defined for every zem_contact field tag, and these are then used in the adi_contact tags – if a name is not specified then it is automatically generated in the markup & the adi_contact tags won’t be able to match them up
  • a checkbox that’s been ticked is taken to be “filled in”, so value="yes" is not required
  • in the database update:
    • a blank phone number will be stored as “no phone”
    • the ‘general’, ‘sales’, ‘technical’ & ‘feedback’ database column names match the contact form input field names
  • MailChimp subscription:
    • if there’s no subscription attempt (e.g. the mailing list opt-in is unticked), no diagnostic information is appended to the email message
  • the above code is using zem_contact_reborn v4.5+, hence:
    • using the options attribute with zem_contact_select, instead of list
    • browser_validate="0" on the zem_contact tag, to prevent browsers interfering with form field validation (HTML5)

Additional information

Support and further information can be obtained from the Textpattern support forum. A copy of this help is also available online. More adi_plugins can be found here.

Version 0.6 – Download (Uncompressed) Support – TXP 4.5, 4.6