Event Espresso ConstantContact Integration

My client wanted to integrate Event Espresso with ConstantContact. Unfortunately, Event Espresso did not already have an add-on that provided this integration — they do have one for MailChimp, if that helps you. Credit to the developers of the MailChimp add-on, because I referenced some of their code in creating the ConstantContact integration.

What I’m about to detail below took me a long time to figure out, partly because I had never worked extensively with WordPress actions, filters, and hooks, or PHP namespaces. A more adept WordPress/PHP programmer may have had an easier time, but for the sake of documenting my process, I’ll provide some explanation and cite my sources.

The breakthrough came when I stumbled upon a function that writes user generated output to WordPress’s debug log.

To enable this capability, make sure the following are set in your wp-config.php file:

// enable WP_DEBUG mode
define( 'WP_DEBUG', true );
// enable Debug logging to the /wp-content/debug.log file
define( 'WP_DEBUG_LOG', true );

This allowed me to troubleshoot every aspect of the Event Espresso ConstantContact integration, and a function I will include in every child theme moving forward. Thank you to David Lee on StackExchange for this gem.

if( !function_exists( 'write_log' ) ){
function write_log( $log ){
if( true === WP_DEBUG ){
if( is_array( $log ) || is_object( $log ) ){
error_log( print_r( $log, true ) );
} else {
error_log( $log );

Armed with the write_log function, I got to work. First off, in Event Espresso, I created a question group with the opt-in checkbox asking the Primary Registrant if they wanted to sign up for ConstantContact.

For my integration to work, the name of the email list in ConstantContact must be identical to the event name in Event Espresso.

Also, to set expectations, this is not a refined plug-in like the MailChimp add-on. It certainly can be made into one with a little TLC, but for my immediate need, I have the API Key, Access Token, and Question ID for the opt-in checkbox hard-coded within functions in my child theme’s functions.php file.

So, I first had to know where to hook in the integration. A support ticket to Event Espresso provided this guidance. And with a little reverse engineering of the MailChimp add-on, I was ultimately able to arrive at the function below:

function ee_cc_hook( EE_SPCO_Reg_Step_Attendee_Information $spco_obj, $spc_data ){
$spco_registrations = $spco_obj->checkout->transaction->registrations( $spco_obj->checkout->reg_cache_where_params, TRUE );
if( !empty ( $spco_registrations ) ){
foreach( $spco_registrations as $registration ){
if ( $registration instanceof EE_Registration ){
// get the answer to the custom CC optin question
$answers = $registration->answers();
if( !empty ( $answers ) ){
foreach( $answers as $answer ){
if ( $answer instanceof EE_Answer ){
$question = $answer->question();
$question_answers[ $question->ID() ] = $answer->pretty_value();
$optin = $question_answers[YOUR QUESTION ID];
if( $optin === "Yes" ){
// get the attendee
$attendee = $registration->attendee();
if ( $attendee instanceof EE_Attendee ){
// event information
$EVT_ID = $registration->event_ID(); // not needed, but left for reference
$event_name = $registration->event()->name();
// attendee information
$att_id = $attendee->ID(); // not needed, but left for reference
$att_email = $attendee->email();
$fname = $attendee->fname();
$lname = $attendee->lname();
$data = array(
'evt_name' => $event_name,
'att_email' => $att_email,
'fname' => $fname,
'lname' => $lname
cc_integration( $data );
add_action( 'AHEE__EE_Single_Page_Checkout__process_attendee_information__end', 'ee_cc_hook', 10, 2 );

In summary, I am verifying that the Primary Registrant opted-in to the ConstantContact sign-up. In my case, the Question ID for the opt-in checkbox was “27”. Then, I got the salient information for using ConstantContact’s API to sign-up a user — email, first name, and last name. I also needed the event name to compare against ConstantContact email lists.

From there, I downloaded ConstantContact’s PHP SDK and more or less modified their email sign-up form sample code.

// require the autoloaders
require_once get_stylesheet_directory() . '/ctct/src/Ctct/autoload.php';
require_once get_stylesheet_directory() . '/ctct/vendor/autoload.php';
use Ctct\ConstantContact;
use Ctct\Components\Contacts\Contact;
use Ctct\Exceptions\CtctException;
function cc_integration( $data ){
if ( !defined( "CTCT_APIKEY" ) ){
define( "CTCT_APIKEY", "YOUR API KEY" );
$cc = new ConstantContact( CTCT_APIKEY );
// attempt to fetch lists in the account, catching any exceptions and printing the errors to screen
$lists = $cc->listService->getLists( CTCT_ACCESS_TOKEN );
}catch( CtctException $ex ){
foreach( $ex->getErrors() as $error ){
write_log( $error );
if( !isset( $lists ) ){
$lists = null;
foreach( $lists as $list ) {
if( $data['evt_name'] == $list->name ) {
$ctct_list = $list;
$action = "Getting Contact By Email Address";
// check to see if a contact with the email address already exists in the account
$response = $cc->contactService->getContacts( CTCT_ACCESS_TOKEN, array( "email" => $data['att_email'] ) );
// create a new contact if one does not exist
if( empty( $response->results ) ){
$action = "Creating Contact";
$contact = new Contact();
// get the list ID based on the event name
// the list and the event must be identical
$contact->addEmail( $data['att_email'] );
$contact->addList( (string)$ctct_list->id );
$contact->first_name = $data['fname'];
$contact->last_name = $data['lname'];
$returnContact = $cc->contactService->addContact( CTCT_ACCESS_TOKEN, $contact );
// update the existing contact if address already existed
$action = "Updating Contact";
$contact = $response->results[0];
if( $contact instanceof Contact ){
// get the list ID based on the event name
// the list and the event must be identical
$contact->addList( (string)$ctct_list->id );
$contact->first_name = $data['fname'];
$contact->last_name = $data['lname'];
$returnContact = $cc->contactService->updateContact( CTCT_ACCESS_TOKEN, $contact );
} else {
$e = new CtctException();
$e->setErrors( array( "type", "Contact type not returned" ) );
throw $e;
// catch any exceptions thrown during the process and write the errors to debug.log
}catch( CtctException $ex ){
write_log( 'Error: ' . $action );
write_log( $ex->getErrors() );

Event Espresso has informed me that their top priorities on their product roadmap are:

  1. Wait lists
  2. Automated email reminders
  3. Recurring events

Once those are done, they will be investigating Zapier integration to connect Event Espresso to many web services. So, in the meantime, I hope this helps someone else out there (thanks Dwayne).