Tracking Registration Forms and Payments with WordPress

Banner Image: Tracking Conference Registration and Payments End-to-End on WordPress

It seemed like a simple request from a customer with an existing WordPress site: set up a registration form for a small conference they were hosting, allow them to get all registrations on a spreadsheet, let registrants pay online using PayPal, and set up a tracking ID so registrations can be reconciled with PayPal statements and checks that arrive in the mail.  Getting all the pieces together into a cohesive system took a little digging, but the customer is happy with the solution.  Here’s a writeup for posterity — something I wish I had when I started. If there’s an easier way (other than buying professional conference software) please don’t hesitate to tell me in the comments.

Initial Conditions:

  • Customer has self-hosted WordPress site (version 4.0)

Added WordPress Plugins:


Requirement #1: Registration form up and running.

Contact Form 7 is my go-to submission form package. It has been downloaded over 20 Million times for a reason and comes with plenty of documentation. I also installed an used Really Simple CAPTCHA which is implemented by the same author.

Requirement #2: Saving the results in a database and posting the data to users.

I used a plugin for this called Contact Form DB. This plugin has its own video tutorial, so I won’t go into details how to use it here.  What I did find very useful for the conference chair is to give them their own password-protected page loaded with a bunch of Contact Form DB shortcodes to keep track of registrations. Here are some examples. Note that the shortcodes are specific to names of items in the form, so use the shortcode builder that comes with Contact Form DB to generate the right codes for you.

  • [cfdb-count form="Conference Registration"] is a shortcode that prints out the number of registrants on a WordPress page or post.
  • [cfdb-count form="Conference Registration" filter="registration-category=Student"]  is a shortcode that prints out how many of those registrants applied for student rate.
  • [cfdb-table form="Conference Registration" show="first-name,last-name, email,registration-category"] Shows a table of registrants with their name, email, and category.
  • [cfdb-export-link form="Conference Registration"]  is a link to the whole table.

Note that the free version of Contact Form DB does not allow one to edit/revise entries in the database, only delete them. There is a paid version available that does enable editing of fields in the database.  I’ll bet half the purchase price that the customer will pay for it before the conference is over.

Requirement #3: Time/Date Stamp

Since prices change after certain deadlines, it was important to know exactly when a person registered.  Contact Form 7 has [_date] and [_time] shortcodes for emailing this, and Contact Form DB records the times as well.  Always nice when plugins just do the right thing.

Requirement #4: Get a PayPal payment button to appear when the form is successfully submitted.

Contact Form 7 strongly prefers a simple text message when a form is submitted correctly.  There is a hook for successful submissions to fire some Javascript, which seems to be used mostly for redirecting the page (against the plugin author’s recommendation), or firing Google Analytics events. This hook is available at the very bottom of the form editor in a text block  labeled “Additional Settings”.  The syntax is dead simple

on_sent_ok: "(javascript goes here)"

Using the PayPal merchant tools to create a payment button with three registration fees (member, nonmember, & student), I had a sizeable blob of HTML that I wanted to insert. I could have used this hook to redirect to a different page, but I decided to do something more gentle and less alarming for the user.  I set the “Additional Settings” thusly.

on_sent_ok: "$('.wpcf7-mail-sent-ok').load( '/buttons.html #paypal-conference2015-early');"

This code is written in jQuery and showcases the power of its “.load()” function. I use it here to substitute a section of the existing HTML file with a section of loaded HTML file. In particular, it replaces the success message from Contact Form 7 with other HTML from the resources file. The other HTML has my PayPal button nested inside. I would have preferred putting the HTML fragment in a unlisted post, but WordPress does not have such a concept in their vocabulary, which is regrettable.  I just dropped a HTML file called buttons.html directly into the home directory of the webserver. Here’s what the contents look like

Note, I added a unique ID for the text input on line 7.  That will come in handy later.


Requirement #5: The tracking code.

Sometimes things that look simple get really complicated. The idea here was just to create a little code that would show up in both PayPal statement and the registration forms so that the accounting would be easier. Since it’s a small conference and accounting is done by hand, this code doesn’t need strong guarantees of uniqueness so a random string would suffice.

5.a Generate a random string

I went into the functions.php file of the child theme and added the following code.

This gives me a shortcode [trackingcode] that I can use in WordPress pages.

5.b  Populate form with the tracking code

Here is where I used Contact Form 7 Dynamic Text Extension.  It works with Contact Form 7 and adds two additional form types dynamic text field, and dynamic hidden field. This basically is a shortcode that allows another shortcode to be embedded inside.  Here’s the shortcode I used in the Contact Form 7 editor   [dynamictext tracking-code id:tracking-code uneditable "trackingcode"] .  The first word is the type of the short code. The second becomes the name shortcode for email purposes.  Third is becomes the “id” attribute of the HTML element.  This is useful for later, and it needs to be unique in the HTML document.  The forth word, uneditable, makes it so the user can see the tracking code assigned to them, but cannot change it.  Last is “trackingcode” which is the shortcode I created in step 4.a except it doesn’t have the square brackets ([]).

The form looks like this.Uneditable Tracking CodeUsers can highlight the text inside the field and copy/paste it elsewhere for reference, but they cannot edit the content of the field.

 5.c Propagate the tracking code to the PayPal Button

Now that we have the string and I labelled it with a unique ID, it is not hard to extend the reveal of the PayPal button to also populate the text field and make it uneditable as well.  Going back to the Contact Form 7 editor, down in the Additional Settings, I expanded the code as follows (NOTE: I reproduce it here across multiple lines of ease of reading.)

Basically, I added a completion handler to the .load() function.  After the PayPal button is loaded, it pulls the tracking-code (using the HTML attribute “id” from section 4.b) and inserts it in the value of the HTML element  with id=paypal-tracking-id (from Requirement #4).  I also set the property to make it readonly.

There’s only one problem with this solution. It doesn’t work.  The reason is subtle, on_sent_ok is an event after the data is submitted and the form resets.  Technically, the page does an HTML POST, then reloads as a separate GET operation. Thus a new random string is generated and appears in the PayPal button, not the one that just went out in email.

The solution is to store a little bit of data between form submission and reload. The solution is to use cookies.

5.d Cache the tracking code so they are the same in the email and the PayPal button.

A cookie is just a way of storing a key-value pair on a browser for later use.  To manipulate cookies easily from JavaScript, I grabbed the jquery.cookie.js file from GitHub and dropped it in the wp-includes/js/jquery/ directory of the WordPress installation. Then I’ll make a one-line change in the Additional Settings of my Contact Form 7 editor to pull the value of the string from the cookie instead of the HTML element.

Now all I need to do is push the value of the right field into a cookie at the right time.  There are many JavaScript files on the server that I could have modified to do this, but the use is so specific to this one page I wanted a solution that would isolate the changes.  This is where I turned to another plugin, CSS & Javascript Toolbox.  This allows me to create snippets of CSS or JavaScript code in the header or footer of a document and control exactly which pages get it.  I imagined this plugin would use custom content types to accomplish its task, but was a little surprised to see how many tables it created in the WordPress database.

The jQuery I really care about is amazingly concise:

Of course we need to do some housekeeping: namely load the jquery.cookie.js file into the page,  wrap this code in <script> HTML tags, and wrap the interesting part in the cumpulsory “no conflict” incantations of JavaScript. The entire entry in CSS & Javascript Toolbox looks like this.  I just assign it to the page containing the Contact Form.


With just a few key pieces of PHP and jQuery, I was able to lash several plugins together into a good end-to-end solution for this customer. Now that they have the capability, they are beginning to think about using the same mechanism for monthly meetings and annual subscriptions instead of just this one-off conference.

There’s still a some work getting the registration page, the internal stats page, and the emails right. I will submit an update after the conference was over with experience from setting this up.

Leave a Reply

Your email address will not be published. Required fields are marked *