MailChimp form using API v3.0 and jQuery ajax

As per notification at the top of this page, all prior versions of the API will not be supported after 2016.

I created a simple HTML page for a dynamic MailChimp sign-up form using jQuery ajax. This means that your users can signup for your MailChimp list without leaving your page. Better than that, they will signup without a page refresh, as the jQuery and `ajax()` will dynamically update the page with the response from the MailChimp API server. This means that you can use jQuery animations to fade out the form, display an animated spinner while the user waits, and then fade in the message. With jQuery, and a little imagination, the possibilities are endless.

The PHP files are “hidden” in the background where the user never sees them yet the jQuery ajax can still access them invisibly. Even when your website is static HTML, without any PHP, this solution will work so that nobody will ever know PHP is being used in the background.

1) Download a PHP wrapper that supports API v3.0. As of this writing, there is nothing official listed in the latest MailChimp docs that supports v3.0, but several are listed on GitHub, so I selected this one.

2) Create the following PHP file, `store-address.php`, using your own API key and list ID, and then place it in the same directory as the wrapper from step one. Remember to follow the documentation for your wrapper, but they all seem fairly similar to this.

<?php // for MailChimp API v3.0

include('MailChimp.php');  // path to API wrapper downloaded from GitHub

use \DrewM\MailChimp\MailChimp;

function storeAddress() {

    $key        = "xxxxxxxxxxxxxxx-us1";
    $list_id    = "xxxxxx";

    $merge_vars = array(
        'FNAME'     => $_POST['fname'],
        'LNAME'     => $_POST['lname']
    );

    $mc = new MailChimp($key);

    // add the email to your list
    $result = $mc->post('/lists/'.$list_id.'/members', array(
            'email_address' => $_POST['email'],
            'merge_fields'  => $merge_vars,
            'status'        => 'pending'     // double opt-in
            // 'status'     => 'subscribed'  // single opt-in
        )
    );

    return json_encode($result);

}

// If being called via ajax, run the function, else fail

if ($_POST['ajax']) { 
    echo storeAddress(); // send the response back through Ajax
} else {
    echo 'Method not allowed - please ensure JavaScript is enabled in this browser';
}

3) Create your HTML/CSS/JavaScript(jQuery) form (It is not required to be on a PHP page, and the visitor will never see that PHP is being used in the background.)

The response is in JSON so you’ll have to handle it correctly.

Here is what my `index.html` file looks like:

<form id="signup" action="index.html" method="get">
    First Name: <input type="text" name="fname" id="fname" />
    Last Name: <input type="text" name="lname" id="lname" />
    email Address (required): <input type="email" name="email" id="email" />
    <input type="submit" id="SendButton" name="submit" value="Submit" />
</form>
<div id="message"></div>

<script src="jquery.min.js"></script>
<script>
$(document).ready(function() {
    $('#signup').submit(function() {
        $("#message").html("Adding your email address...");
        $.ajax({
            url: 'inc/store-address.php', // proper url to your "store-address.php" file
            type: 'POST', // <- IMPORTANT
            data: $('#signup').serialize() + '&ajax=true',
            success: function(msg) {
                var message = $.parseJSON(msg),
                    result = '';
                if (message.status === 'pending') { // success
                    result = 'Success!  Please click the confirmation link that will be emailed to you shortly.';
                } else { // error
                    result = 'Error: ' + message.detail;
                }
                $('#message').html(result); // display the message
            }
        });
        return false;
    });
});
</script>

When CodeIgniter’s CSRF Protection breaks your Ajax

CSRF stands for “Cross Site Request Forgery” and if you’re using forms on your site, you’ll probably want to protect yourself and users against this kind of attack.

You just finished your latest PHP project using the CodeIgniter framework and decide to enable the CSRF protection option in your `config.php` file.

$config['csrf_protection']  = TRUE;  // <- set to TRUE
$config['csrf_token_name']  = 'csrf_token';   // <- name this whatever
$config['csrf_cookie_name'] = 'csrf_cookie';  // <- name this whatever
$config['csrf_expire'] = 7200;  // <- default is two hours

Enabling it within `config.php` is not enough. You also need to use the form helper `form_open()` function to construct the form's HTML markup. This function constructs the form so that it contains a `<input type="hidden">` element containing the CSRF token value. If the submitted form data is missing this token, it will not submit.

Now CSRF is working but you discover that your jQuery ajax requests are all suddenly failing with a type 500 server error. This is a direct result of activating the CSRF Protection option in CodeIgniter. As just explained, the submitted form data must contain the CSRF token, but it's missing from your ajax requests.

The solution is simple. You need to make sure that your ajax requests simulate a regular form submission by including the CSRF token value within the submitted data.

There are two types of solutions:

Solution #1:

This only works if your ajax requests occur when a form is already constructed on the page, such as when doing remote validation to check to see if a password or username already exists.

You'll need to copy the value from the hidden field called `csrf_token` (the name is exactly as per your `$config['csrf_token_name']` option setting) and send this along with your ajax request.

var csrf = $('input[name="csrf_token"]').val();  // <- get token value from hidden form input

$.ajax({
    // your other ajax options,
    data: {  // submit token value with YOUR token name
        csrf_token: csrf
    }
});

Solution #2:

This works for all ajax requests, even when you do not have a form on the page, such as remotely loading some content.

In this case, you can't get the CSRF token from a hidden field, since there is no form. You must retrieve it from the CSRF cookie. I'm using a jQuery cookie plugin.

var csrf = $.cookie('csrf_cookie');  // <- get token value from cookie

$.ajax({
    // your other ajax options,
    data: {  // submit token value with YOUR token name
        csrf_token: csrf
    }
});

Notice how the ajax in both solutions is sending the token with the same name, that's your name as per your configuration, `csrf_token`. Only the source of the token value is different... Solution #1 gets the token value from the hidden field, where Solution #2 gets the same token value from the cookie.

You can only use Solution #1 when you have a form on the page constructed with the `form_open()` function. However, you can use Solution #2 with or without a form, in all cases.

NOTES:

I have CodeIgniter v2.1.4 and by default, the `$config['csrf_token_name']` option is set to `csrf_test_name`. This mismatch might get a little confusing, but you can use whatever naming convention you wish. In my solution above, I changed it to `csrf_token`.

  • To retrieve the current token from the hidden input, use the name assigned to the `$config['csrf_token_name']` option.
  • To retrieve the current token from the cookie, use the name assigned to the `$config['csrf_cookie_name']` option.

No matter how you retrieve the token value, the important thing to remember is to always send the token value along with whatever name you've assigned to the `$config['csrf_token_name']` option.

jQuery Nivo Slider has broken effects within WordPress

I’m using the jQuery Nivo Slider plugin on a WordPress project. Keep in mind that this is the free jQuery plugin version, not the WordPress plugin version, so I’m doing the integration myself into a child theme of the stock Twenty Thirteen WordPress theme.

To make it align properly with the other page entries, I used the standard WordPress classes on the wrappers…

<div class="hentry">
    <div class="entry-content">
        <div class="slider-wrapper theme-default">
            <div id="slider" class="nivoSlider">
            ....

The problem is, although the slider is nicely positioned on the page, the transition effects are broken. The slider is still working but just before each transition animation is supposed to start, you get a flicker of a tiny thumbnail in the upper-left corner and then the new slide appears… no slicing, no boxing, no wiping… nothing but sadness.

I was able to recreate my exact slider code in a jsFiddle and it worked flawlessly. After much troubleshooting, I discovered that the WordPress class `.entry-content` in the parent theme was the culprit.

However, the removal of `.entry-content` fixes Nivo slider, it also breaks the layout. By the time I figure out how to recreate the necessary parts of `.entry-content` to fix the layout, I’ve a whole bunch of unnecessarily redundant CSS.

Another look at the default CSS for the parent Twenty Thirteen theme reveals line #659…

.entry-content img {
    max-width: 100%;
}

Yes, this is it. This one CSS rule is completely breaking Nivo slider’s animation effects.

The fix is to simply un-set `max-width` to the default value of `none` by very specifically targeting the slider `img` elements. I placed this rule in my child theme’s `style.css` file.

.entry-content #slider img {
    max-width: none;
}

Since `.entry-content #slider img` is more specific than the original selector, `.entry-content img` in the parent theme, it will automatically take precedence.

Nivo slider is now working as designed.

The various ways to declare your jQuery Validate rules

The following are all acceptable methods for declaring validation rules for the jQuery Validation plugin.

1) Declared within `.validate()`

Use this when you’re trying to keep your JavaScript separate from your HTML markup.

$(document).ready(function() {
        
    $('#myform').validate({
        rules: {
            fieldName: {
                required: true
            }
        }
    });
        
});

DEMO: http://jsfiddle.net/uTt2X/2/

NOTE: If your field `name` contains special characters such as brackets or dots, you must enclose the `name` in quotes

$(document).ready(function() {
        
    $('#myform').validate({
        rules: {
            "field.Name[234]": {
                required: true
            }
        }
    });
        
});

—–

2) Declared by `class`:

Only use this when your rules can be declared by a boolean `true` as you cannot pass any parameters.

<input name="fieldName" class="required" />

DEMO: http://jsfiddle.net/uTt2X/1/

—–

3) Declared by HTML5 validation attributes:

Use this if you already have HTML 5 validation attributes within your form. Only use this when your rules can be declared with HTML 5 validation attributes. Not all rules can be declared in this fashion.

<input name="fieldName" required="required" />

DEMO: http://jsfiddle.net/uTt2X/

—–

4) Declared using the `.rules()` method:

You must use this method if you’re dynamically creating form elements.

$('input[name="fieldName"]').rules('add', {
    required: true
});

DEMO: http://jsfiddle.net/uTt2X/3/

However, as per the documentation, this method only applies to the first matched element. The solution is then to wrap it within a jQuery `.each()` for assigning rules to many inputs at once.

$('.myclass').each(function() {
    $(this).rules('add', {
        required: true
    });
});

DEMO: http://jsfiddle.net/uTt2X/8/

—–

5) By assigning one or more rules to your own `class` using the `.addClassRules()` method:

Use this for assigning rules to fields by their class or for creating an arbitrary `class` representing the rule. Great for creating “compound” rules. Compound rules are rules that are composed of two or more standard rules, like `required` and `email`.

$.validator.addClassRules("myClass", {
    required: true,
    email: true 
});

Then apply to your HTML:

<input name="fieldName" class="myClass" />

DEMO: http://jsfiddle.net/uTt2X/4/

How to properly initialize the jQuery Validate plugin

Based on time spent at Stack Overflow, there seems to be a popular misconception that the `.validate()` method is how you would directly “validate” or test validity when you submit the form.  This leads to all kinds of clever over-thinking… like wrapping `.validate()` inside of `click` and `submit` handlers,  which then leads to all kinds of problems like having to click twice before validation messages appear or a form submission with no validation at all. This is because the `.validate()` method is only used for initialization of the plugin and can only be called once on DOM ready (or anytime after the form’s markup is created). Any/all subsequent calls to `.validate()` are always ignored.

The plugin works simply and it automatically captures the click of the submit button to prevent a form submission until certain validation rules are satisfied.  I mean, that’s the whole point of the plugin… if you had to create your own `click` handlers and test things manually before submitting, then you might as well not have the plugin at all.

To properly initialize this plugin, all you need to do is call the `.validate()` method within the DOM ready event handler.  This is where you would declare rules, options, or over-ride any callback functions.

$(document).ready(function() { // <- ensure DOM is ready

    $('#myform').validate({
        // your rules, options and callback functions
    });

});

Once properly initialized as above, the plugin will automatically perform validation upon various event triggers such as on `keyup` during data entry, on `focusout` of the field, and on `click` of the submit button, not to mention the events that trigger validation of the `select`, `radio` and `checkbox` elements. It’s only after all validation rules are satisfied that the form will be allowed to submit.

To programmatically check validation you would use the `.valid()` method on the entire form or a single element. For example, let’s say you want to use a link (an anchor element), `<a>`, in place of the `type=”submit”` input/button. This code is only used for illustration as the most semantically correct way to do this is to use a `type=”submit”` `<input>` or `<button>` element.

$('#myLink').on('click', function(e) {
    e.preventDefault();     // <- block the '<a>' default behavior, history, page jump on click, etc.
    $('#myform').valid(); {  // <- triggers validation test of whole form, similar to the test on a submit button click.
});

Bottom line, the `.validate()` method, most typically, only goes inside the DOM ready event handler function to be called once on page load. It only has one purpose, to initialize the plugin on your form and to declare any plugin options during that initialization.

jQuery Validate plugin requires a name attribute

Remember that no matter how you declare your rules when using jQuery Validate, even if you target by `id` and declare with the `.rules(‘add’)` method, you must absolutely have a `name` attribute on any form element you wish to validate.

<input name=”firstName” type=”text” …

See the Markup recommendations section of the Reference docs page:

“The name attribute is ‘required’ for input elements, the validation plugin doesn’t work without it.”

Why? The `name` attribute is how the jQuery Validate plugin keeps track of the inputs internally. Even though the documentation doesn’t specify it, it only stands to reason that if this is how the plugin is keeping track of everything, you must make sure each `name` is unique.

MailChimp form using jQuery ajax

NOTE: This posting was originally written for MailChimp API version 1 and MailChimp will stop support for API versions 1 & 2 at the end of 2016.

UPDATE:  Click HERE to view the updated solution using MailChimp API v3.0

——

I created a simple HTML page for a dynamic MailChimp sign-up form using jQuery ajax. This means that your users can signup for your MailChimp list without leaving your page. Better than that, they will signup without a page refresh, as the jQuery and `ajax()` will dynamically update the page with the response from the MailChimp API server. This means that you can use jQuery animations to fade out the form, display an animated spinner while the user waits, and then fade in the message. With jQuery, and a little imagination, the possibilities are endless.

The PHP files are “hidden” in the background where the user never sees them yet the jQuery ajax can still access them invisibly. Even when your website is static HTML, without any PHP, this solution will work so that nobody will ever see a `.php` in their URL.

1) Download the PHP 5 jQuery example here…

apidocs.mailchimp.com/downloads/mcapi-simple-subscribe-jquery.zip

2) Follow the directions in the Readme file by adding your API key and List ID to the `store-address.php` file at the proper locations.

3) You may also want to collect the user’s first & last name and/or other form information. You’ll have to add an array to the `store-address.php` file using the corresponding Merge Variables.

Here is what my `store-address.php` file looks like where I also gather the first name, last name, and email type:

<?php
    function storeAddress(){
    
    	require_once('MCAPI.class.php');  // same directory as store-address.php

    	// grab an API Key from http://admin.mailchimp.com/account/api/
    	$api = new MCAPI('123456789-us2');

        // Merge Variables
    	$merge_vars = Array( 
    		'EMAIL' => $_GET['email'],
        	'FNAME' => $_GET['fname'], 
        	'LNAME' => $_GET['lname']
        );
    	
    	// grab your List's Unique Id by going to http://admin.mailchimp.com/lists/
    	// Click the "settings" link for the list - the Unique Id is at the bottom of that page. 
    	$list_id = "123456a";
    
    	if($api->listSubscribe($list_id, $_GET['email'], $merge_vars , $_GET['emailtype']) === true) {
    		// It worked!	
    		return 'Success!&nbsp; Check your inbox or spam folder for a message containing a confirmation link.';
    	} else {
    		// An error ocurred, return error message	
    		return '<b>Error:</b>&nbsp; ' . $api->errorMessage;
    	}
    	
    }

    // If being called via ajax, autorun the function
    if($_GET['ajax']){ echo storeAddress(); }
?>

4) Create your HTML/CSS/jQuery form. It is not required to be on a PHP page.

Here is what my `index.html` file looks like. This code is contained between the `<body></body>` tags:

<form id="signup" action="index.html" method="get">
        <input type="hidden" name="ajax" value="true" />
        First Name: <input type="text" name="fname" />
        Last Name: <input type="text" name="lname" />
        email Address (required): <input type="text" name="email" />
        HTML: <input type="radio" name="emailtype" value="html" checked="checked" />
        Text: <input type="radio" name="emailtype" value="text" />
        <input type="submit" />
</form>
<div id="message"></div>

<script src="jquery.min.js" type="text/javascript"></script>
<script type="text/javascript">
    $(document).ready(function() {
        $('#signup').submit(function() {
            $("#message").html("<span class='error'>Adding your email address...</span>");
            $.ajax({
                url: 'inc/store-address.php', // proper url to your "store-address.php" file
                data: $('#signup').serialize(),
                success: function(msg) {
                    $('#message').html(msg);
                }
            });
            return false;
        });
    });
</script>

Required pieces…

`index.html` constructed as above or similar. With jQuery, the appearance and options are endless.

`store-address.php` file downloaded as part of PHP examples on Mailchimp site and modified with your API KEY and LIST ID. You need to add your other optional fields to the array.

`MCAPI.class.php` file downloaded from Mailchimp site (version 1.3 for PHP 5). Place it in the same directory as your `store-address.php` file or you must update the url path within `store-address.php` file to find it.

Integrate Tooltipster with jQuery Validate

Prerequisites:

Tooltipster Plugin version 2.1 or 3.0 (The raw code for version 2.1 can be found inside the first jsFiddle below.)
jQuery Validate Plugin

First, initialize the Tooltipster plugin (with any options) on all specific `form` elements that will display errors:

$(document).ready(function () {

        // initialize tooltipster on form input elements
        $('#myform input[type="text"]').tooltipster({ 
            trigger: 'custom', // default is 'hover' which is no good here
            onlyOne: false,    // allow multiple tips to be open at a time
            position: 'right'  // display the tips to the right of the element
        });
    
});

Second, use Tooltipster’s advanced options along with the `success:` and `errorPlacement:` callback functions built into the Validate plugin to automatically show and hide the tooltips as follows:

$(document).ready(function () {
    
        // initialize validate plugin on the form
        $('#myform').validate({
            // any other options & rules,
            errorPlacement: function (error, element) {
                $(element).tooltipster('update', $(error).text());
                $(element).tooltipster('show');
            },
            success: function (label, element) {
                $(element).tooltipster('hide');
            }
        });
    
});

Working Demo: jsfiddle.net/2DUX2

Note that this code example takes advantage of the new Tooltipster API features released in version 2.1 on 2/12/13

For Tooltipster version 3.0

The latest version of Tooltipster, version 3.0, is supposed to be working more correctly than version 2.1.

That’s fine, except that an animation flicker is now occurring on every single keystroke even when no content has changed. I suppose we could disable the default `onkeyup` option in jQuery Validate, but when multiple rules are used, the user would not be aware of his data entry violation until after leaving the field or clicking the submit button.

The workaround is to set the `updateAnimation` option to `false`.

$(document).ready(function () {

        // initialize tooltipster on form input elements
        $('#myform input[type="text"]').tooltipster({ 
            trigger: 'custom',     // default is 'hover' which is no good here
            onlyOne: false,        // allow multiple tips to be open at a time
            position: 'right',     // display the tips to the right of the element
            updateAnimation: false // stops the flicker on every keyup
        });
    
});

Demo: jsfiddle.net/2DUX2/2/

I’ve made a suggestion to the developer to simply check the new incoming content against the existing content and only run the animation when they’re different. I can see other practical applications for this… any situation where the same content is sent repeatedly but yet we still want an animation to occur when/if it changes. I’ll update this posting as the situation warrants.

UPDATE:

The Tooltipster developer made the following suggestion to preserve the message update animation in version 3.0, which works very nicely. From within the jQuery Validate plugin’s `errorPlacement` callback function, this simple code makes sure the error message is not blank and has changed before calling Tooltipster’s `show` method. This has the added benefit of greatly reducing the number of calls to Tooltipster.

$(document).ready(function () {
    
        // initialize validate plugin on the form
        $('#myform').validate({
            // any other options & rules,
            errorPlacement: function (error, element) {
                var lastError = $(element).data('lastError'), // get the last message if one exists
                    newError = $(error).text();               // set the current message
            
                $(element).data('lastError', newError);  // set "lastError" to the current message for the next time 'errorPlacement' is called
      
                if(newError !== '' && newError !== lastError){  // make sure the message is not blank and not equal to the last message before allowing the Tooltip to update itself
                    $(element).tooltipster('content', newError); // insert content into tooltip
                    $(element).tooltipster('show');              // show the tooltip
                }
            },
            success: function (label, element) {
                $(element).tooltipster('hide');  // hide tooltip when field passes validation
            }
        });
    
});

Demo: jsfiddle.net/2DUX2/3/

404 errors (url: /a) in Google Webmaster Tools

As you may already know, I’ve been a Web Developer since 1999 and run Website Setup dot net.

I use Google Webmaster Tools for several of my and my customers’ websites. Recently, under Diagnostics > Crawl Errors, I discovered quite a few 404 (not found) errors pointing to the same non-existent location:

http://baudindentalmission.org/a

Sure, a 404 error is totally expected. After all, the “/a” directory does not exist, however, the question remains, how did the Google-bot get the idea to crawl there in the first place? Perhaps a programming error on my part or a typo?

Well, this is strange, I’m now seeing it on more than one site and I’m finding other people complaining about the same thing suddenly appearing in their Webmaster Tools Dashboards.

Let’s now examine my Dashboard’s Linked From data:

http://baudindentalmission.org/donate.html
http://baudindentalmission.org/haiti.html
http://baudindentalmission.org/about.html

Hmm, no clues there. Nothing in any of those pages link to a “/a” location.

Let’s dig further into the JavaScript Includes. Searching the first JavaScript file (which happens to be the jQuery JavaScript Library) for “/a”…

<script src="/ajax/jquery/jquery-1.5.min.js" type="text/javascript"></script>

We find this occurrence…

<a style="color: red; float: left; opacity: .55;" href="/a">a</a>

What’s that doing in there? Actually, it doesn’t matter… it’s part of jQuery and very smart programmers spend countless hours developing, troubleshooting and refining jQuery… so, for this discussion, we’ll just trust them. What’s more important is that the Googlebot is actually crawling around inside an external JavaScript file, presumably searching for content. Why? Ask Google.

Personally, I fail to see the value in this practice of crawling JavaScript. If it’s searching for malware or some SEO trickery then great, but it shouldn’t be following things it thinks (assumes) are valid links and creating 404 errors. If it’s crawling JavaScript in order to figure out your site navigation, then shame on Google for rewarding such a poor programming practice. (Your content and code should be two separate things!) Malware or some goofy JavaScript navigation system, either way, these things should be penalized with lower rankings or removed from Google altogether.

What’s even more odd is that the particular JavaScript file it’s crawling is jQuery itself. Since jQuery is part of the Google Libraries API, you’d think it would quickly realize crawling around in there is kinda pointless.

Here is a jQuery Bug Report on this very issue. According to notes in that report, this is not something they intend on fixing. I can’t say that I’d blame them for this attitude, Google should not be crawling JavaScript if it doesn’t know how to properly parse it for valid content. (Although as mentioned before, I can’t imagine how one could argue that JavaScript should contain any content at all. Best practices indicate always maintaining a separation between content and code.)

What’s the solution to all this? You don’t want a bunch of 404 errors piling up… although Google is smart enough to drop bad URL’s from their index, they can also penalize a site for this by reducing the crawl rate.

Solution 1: Redirect “/a” to your home page with a 301 in your htaccess file. This approach has two minor issues. One, that your server is doing the work by sending the Googlebot back to your home page and two, the page never existed in any Search Index, theoretically, there should be no reason to redirect it elsewhere.

Solution 2: Block this location from the Googlebot in your robots.txt file. This puts the responsibility on Google to stay out of someplace they don’t belong.

Disallow: /a/
Disallow: /a

After several weeks, you should see these erroneous 404 errors disappear. Good luck!

_________________

EDIT: In this article, I’m only assuming this is an issue for sites that host jQuery locally. I cannot imagine the google-bot trying to crawl scripts hosted on it’s own CDN!

_________________

EDIT 2: Here is an official response from a Google employee posting in Google Groups:

JohnMu
Google Employee
4/28/11 – 4:39 AM

Hi guys

Just a short note on this — yes, we are picking up the “/a” link for many sites from jQuery JavaScript. However, that generally isn’t a problem, if we see “/a” as being a 404, then that’s fine for us. As with other 404-URLs, we’ll list it as a crawl error in Webmaster Tools, but again, that’s not going to be a problem for crawling, indexing, or ranking. If you want to make sure that it doesn’t trigger a crawl error in Webmaster Tools, then I would recommend just 301 redirecting that URL to your homepage (disallowing the URL will also bring it up as a crawl error – it will be listed as a URL disallowed by robots.txt).

I would also recommend not explicitly disallowing crawling of the jQuery file. While we generally wouldn’t index it on its own, we may need to access it to generate good Instant Previews for your site.

So to sum it up: If you’re seeing “/a” in the crawl errors in Webmaster Tools, you can just leave it like that, it won’t cause any problems. If you want to have it removed there, you can do a 301 redirect to your homepage.

Cheers
John