For many online businesses, the contact form is one piece of a larger marketing and customer management system involving multiple services. You might be sending support requests into HelpScout, or adding interested readers to your MailChimp mailing list, or creating a new lead in your CRM.
WPForms may already have add-ons that integrate with your services, like MailChimp and Aweber. But what if you need to build your own integration? It is surprisingly easy.
Real World Examples
Here are some WPForms integrations I have built for clients. You can download and install these plugins yourself if you want to connect to these services:
- Integrate ConvertKit and WPForms
- Integrate Pardot and WPForms
- Integrate Lexicata and WPForms
- Integrate Emma and WPForms
- Integrate FeedBlitz and WPForms
Building a custom integration
You can use the wpforms_process_complete
hook to run your own custom code after the successful submission of a WPForms entry. This hook runs at the end because there are reasons a form submission might not reach the complete hook (required fields weren’t filled out, message was determined to be spam…).
This hook runs after submission of every form on your site. If you’d like to limit it to a specific form, you can use wpforms_process_complete_{form_id}
.
For a simple one-off integration, this is all you need. In your theme’s functions.php file or a core functionality plugin, add the following code and customize it to your service’s API specifications:
/**
* Integrate WPForms with CRM
*
* @author Bill Erickson
* @link https://www.billerickson.net/contact-form-integration/
*
* @param array $fields
* @param array $entry
* @param array $form_data
* @param int $entry_id
*/
function be_crm_connector( $fields, $entry, $form_data, $entry_id ) {
// Limit to Form ID = 123
if( 123 != $form_data['id'] )
return;
$api_url = 'http://example.com';
$body = array(
'name' => $fields['1']['value'],
'email' => $fields['2']['value'],
);
$request = wp_remote_post( $api_url, array( 'body' => $body ) );
}
add_action( 'wpforms_process_complete', 'be_crm_connector', 10, 4 );
If you plan to use this on multiple website or multiple forms, I recommend including a backend settings panel for managing the connection.
Backend Settings Panel
You can use internal WPForms filters and helper functions to add your own section to the form settings.
For my ConvertKit addon, I created a settings panel for managing an API key, selecting the ConvertKit Form ID, and selecting which fields to send.
We will first use the wpforms_builder_settings_sections
filter to add a section to the settings panel. It’s a simple array with a unique slug and label.
/**
* Add Settings Section
*
*/
function be_wpforms_settings_section( $sections, $form_data ) {
$sections['be_convertkit'] = __( 'ConvertKit', 'integrate_convertkit_wpforms' );
return $sections;
}
add_filter( 'wpforms_builder_settings_sections', 'be_wpforms_settings_section', 20, 2 );
Then we use the wpforms_form_settings_panel_content
filter to specify what content appears in that section.
/**
* ConvertKit Settings Content
*
*/
function be_wpforms_settings_section_content( $instance ) {
echo '<div class="wpforms-panel-content-section wpforms-panel-content-section-be_convertkit">';
echo '<div class="wpforms-panel-content-section-title">' . __( 'ConvertKit', 'be_wpforms_convertkit' ) . '</div>';
wpforms_panel_field(
'text',
'settings',
'be_convertkit_api',
$instance->form_data,
__( 'ConvertKit API Key', 'be_wpforms_convertkit' )
);
wpforms_panel_field(
'text',
'settings',
'be_convertkit_form_id',
$instance->form_data,
__( 'ConvertKit Form ID', 'be_wpforms_convertkit' )
);
wpforms_panel_field(
'select',
'settings',
'be_convertkit_field_first_name',
$instance->form_data,
__( 'First Name', 'be_wpforms_convertkit' ),
array(
'field_map' => array( 'text', 'name' ),
'placeholder' => __( '-- Select Field --', 'be_wpforms_convertkit' ),
)
);
wpforms_panel_field(
'select',
'settings',
'be_convertkit_field_email',
$instance->form_data,
__( 'Email Address', 'be_wpforms_convertkit' ),
array(
'field_map' => array( 'email' ),
'placeholder' => __( '-- Select Field --', 'be_wpforms_convertkit' ),
)
);
echo '</div>';
}
add_filter( 'wpforms_form_settings_panel_content', 'be_wpforms_settings_section_content', 20 );
I’m using the wpforms_panel_field()
function to create the fields. WPForms does all the heavy lifting for rendering, sanitizing, and saving these fields. Here are the parameters of the function:
wpforms_panel_field( $option, $panel, $field, $form_data, $label, $args, $echo )
- Option: What type of field it is (ex: text, select…). Look in wpforms/includes/admin/builder/functions.php for a list of all available options
- Panel: What panel it is in. These are all in a section of the Settings panel so we’re setting them all to ‘settings’
- Field: The field ID you’ll use to save/access this data.
- Form Data: Pass all the form data, which has important information for building out the fields. Use
$instance->form_data
, which is provided by the filter we’re using. - Label: The label you want associated with this field.
- Args: Any additional arguments you want to pass. For instance,
'field_map' => array( 'email' )
on a “select” field type will pre-populate the dropdown with every email field in the form - Echo: defaults to true
If WPForms rebuilds its form builder, you may need to update your backend settings to use its new helper functions, so you may want to include some method of updating your plugin in the future. You could release it on WordPress.org, or include a GitHub updater so you can push updates from your GitHub repo.
Using the backend settings
All of the backend settings you create will be accessible inside $form_data['settings']
.
Rather than limiting my code by the Form ID, I’m limiting it to only those that have an API key and ConvertKit Form ID specified. We can use this same code on multiple forms across the site.
I then access my backend settings for email and first name to get the field IDs for those respective fields, then include their field values in the $args
I’m sending to ConvertKit.
/**
* Integrate WPForms with ConvertKit
*
* @author Bill Erickson
* @link https://www.billerickson.net/contact-form-integration/
*
* @param array $fields
* @param array $entry
* @param array $form_data
* @param int $entry_id
*/
function be_send_data_to_convertkit( $fields, $entry, $form_data, $entry_id ) {
// Get API key and CK Form ID
$api_key = $ck_form_id = false;
if( !empty( $form_data['settings']['be_convertkit_api'] ) )
$api_key = esc_html( $form_data['settings']['be_convertkit_api'] );
if( !empty( $form_data['settings']['be_convertkit_form_id'] ) )
$ck_form_id = intval( $form_data['settings']['be_convertkit_form_id'] );
if( ! ( $api_key && $ck_form_id ) )
return;
// Get email and first name
$email_field_id = $form_data['settings']['be_convertkit_field_email'];
$first_name_field_id = $form_data['settings']['be_convertkit_field_first_name'];
$args = array(
'api_key' => $api_key,
'email' => $fields[$email_field_id]['value'],
'first_name' => $fields[$first_name_field_id]['value']
);
if( empty( $args['email'] ) || empty( $args['first_name'] ) )
return;
// Submit to ConvertKit
$request = wp_remote_post( add_query_arg( $args, 'https://api.convertkit.com/v3/forms/' . $ck_form_id . '/subscribe' ) );
}
add_action( 'wpforms_process_complete', 'be_send_data_to_convertkit', 10, 4 );
Joshua Nelson says
Bill,
Nice post! I haven’t used WPForms yet, but it sounds like it’s a good plugin. Do you still use Gravity Forms, or has WPForms provided a suitable replacement?
Also, I’m a little sad there isn’t a link on “now I’m using a custom (non-WordPress) CRM that Jared Atchison and I co-developed.” That sounds intriguing. I have yet to find a full CRM that works for me, mainly relying on FreshBooks and notes (ugh).
Cheers,
Joshua
Bill Erickson says
I’ve only used it on a few projects since it’s so new, but I’ve been happy with it. For what most of my clients need – a standard contact form – it’s definitely a suitable replacement. Even the free WPForms Lite will work for them since most don’t need any of the add-ons.
Gravity Forms is still my go-to plugin for more complicated integrations, like a form that generates a draft post in a custom post type, mapping fields to meta, etc.
The reason we haven’t posted about the non-WordPress CRM is that we’re rebuilding it AGAIN. We originally built it off of WordPress to simplify the database structure and make it faster to query. With thousands of posts (contact form submissions) and dozens post meta fields, the WordPress based ones became very sluggish.
But in the process we were constantly “reinventing the wheel” – rebuilding core WP functionality like user authentication, sanitization/escaping, inserting content into the database, transients…
Now we’re building a new version that’s a WordPress plugin but uses a separate table for the entries. Jared actually modeled it on his work with WPForms, which stores the entries in a separate table for performance reasons as well (Forms are a CPT though).
I think Jared has both versions of the CRM running, and I’m on the old one. I’ve been meaning to switch over and finish up some work on it (missing a few reports) but we’ve both been busy.
We also have a Share Count Plugin that will be launching soon, so keep your eyes out for a post about that.
Amber Hinds says
I think I mentioned at Pressnomics that I finally broke down and bought a CRM/project management tool last month because I didn’t have time to continue supporting our home-grown one. (We went with Insightly.) I’m so happy we finally made that change, but the annoying thing about switching platforms is that we have to transfer all the data over. Bill, when you have switched between CRMs are you doing manual data entry of old records or do you have a script that transfers things from one system to another? I’ve been thinking I might build something that uses WP API to import old data into Insightly, but I haven’t had time.
Are you beta testing the Share Count plugin? Would love to have a look, if so.
Bill Erickson says
Since my previous CRM was WordPress-based and installed on the same server as my new CRM, I created a WordPress template to export leads from WordPress to the new DB.
I grabbed 500 posts at a time, structured all the fields like my new CRM wants them, then inserted them into the new CRM’s database. Finally I mark those posts as ‘exported’ using post meta so that the next time I refresh this page it doesn’t import duplicates.
Susan Finch says
Amber, I’m considering Insightly for a client. BUT it seems the only email marketing system they integrate with is MailChimp or Emma. Love GetResponse, but I may be stuck with the monkey. What are you using? His site is WP using ContactForm7 and Contact Form DB with it.
Bill, I may be contacting you for a quote on custom integration. GetResponse plugin works well, but I want to also use Insightly, because it’s so user-friendly.
Bill Erickson says
One option is to use WPForms => Zapier => Insightly.
Zapier is a service that lets you connect 500+ services without any coding. Instead of WPForms writing an addon for every email marketing and CRM tool, they created a Zapier addon so now you can connect your form to any of Zapier’s supported services, including Insightly.
Joshua Nelson says
Bill,
Wow, sounds like you’ve been busy. I look forward to hearing more about all of this.
Cheers,
Joshua
Morten says
Bill,
I am very interested in your WordPress CRM … having searched far and wide for a useful WP CRM I think I can safely say; there are none out there.
Please consider making your CRM available one way or the other 🙂
Bill Erickson says
The new WordPress-based one will be publicly available when we finish it.
But there’s a very good chance my CRM won’t work perfectly for you. What I think is more important is you build your own CRM so that it does what you need, and can grow with you. Every few months I’m adding new reports to it to collect different type of data. For instance, in my recent post How long does it take to build a website, I added a report to analyze the modification period of past projects.
If you’re a WordPress developer, the simplest thing you can do is build a CRM on WordPress so you can customize it. Set up a separate WordPress install (crm.yoursite.com), use the code detailed above to send your contact form data to it, and write a simple API that takes that data and generates a WordPress post based on it. Add all your relevant fields as post meta, and create template pages for the different reports you want. Both TwentyTen CRM and Genesis CRM can provide guidance for this.
Morten says
Thank you for your advice – and sharing 🙂
Dimitrius says
Thanks! Very useful. How can i sent to 1 field of crm values of 3 fields from Gravity Forms?
I mean this row ‘clientaddress’ => $entry[‘3’], I need t osend somethin like this
‘clientaddress’ => $entry[‘3, 4, 5’],
Bill Erickson says
Like this:
'clientaddress' => $entry['3'] . $entry['4'] . $entry['5'],
Although if you’re using WPForms, you’ll want to change that to
$entry['3']['value']
etcAndy says
Hi Bill,
I have a question that I’m hoping is simple enough you can help me answer. I’ve got an HTML code block in my form that asks for and the retrieves the user’s geolocation using HTML5 (like this http://www.w3schools.com/html/html5_geolocation.asp ). This is working great so far, it returns the coordinates and the accuracy in the div. However I’m struggling to save that data off in the form somewhere. Can you point me to something that will help me understand how to set the field values so that the lat/long can be saved off in entry?
Trying to build a web app where a user can request a pickup at their exact location, the WPForms geolocation add on isn’t good enough.
Bill Erickson says
I think the best approach here is to create a new field type. That way the field data is actually saved with the entry. Here’s an example from a recent project I worked on.
The
init()
method is where you define the basic field settings (name, type, icon, order…). Thefield_options()
method lets you define the available options in the left sidebar when editing a field.field_preview()
is what’s shown in the form builder, andfield_display()
is what’s displayed in the actual form.Depending on what data is provided by the input field, you may want to use the
wpforms_process_filter
filter to modify the form data before it’s saved.I recommend including this in a core functionality plugin. At the top of the code snippet I show what you can put in your CF plugin – using
wpforms_loaded
action to load your code after WPForms has loaded.For more guidance, take a look at how WPForms builds its fields in /includes/fields, and /pro/includes/fields. You might also try asking the question on the WPForms support forum – I know Jared is always happy to help developers extend WPForms.
For more examples of building new field types,
Dave H says
Thank you for this, we are using contact form 7 and are rrying to integrate to an existing restful api service. In yor example, how would you handle a json response from the remote server, and send the user to a page formatted with this data that was returned ?
Latsly would you recommend WPforms over contact form 7 ?
Bill Erickson says
I had to check with the authoritative source on this – Jared Atchison, the developer of WPForms.
Use a very high priority on your function that’s hooked to wpforms_process_complete, like this:
add_action( 'wpforms_process_complete', 'be_my_integration', 100, 4 );
That way it’s the last thing to run, after WPForms has done all its processing, saving and emailing. Use
wp_redirect( $uri ); exit;
to redirec the user based on the data in your json response.Jacob Kim says
Bill your blog post has gotten me the closest to where I need to be with my current client. I am not quite there yet. I followed your instruction created the core-functionality plugin placed the coding into the plugin. My issue is I am trying to create a form for a utility broker that needs a response from the external api. I figured I could use most of this method until the response from the external api part. How do I go about finishing this?
Juan says
Bill Erickson, Good morning.
First of all, sorry for my English.
I’m not a pro in coding, I’m a newbie really, taking the first steps, but I’m really curious in how the APIs world works, and how to send data from wordpress forms to an external data base, and then I land here.
I took a look to your API code, but I don’t know whats in the inc/init.php file, can you show it? it´s possible? how to conect and to fill the data base?
Sorry again if I bother you, and thanks for your time.
Bill Erickson says
Where do you see inc/init.php referenced? I don’t see it mentioned anywhere so am not sure what you’re referring to.
Juan says
Thanks for the response.
In the last part of the publication: “It is received by my CRM, and added to the database. If you’re curious, the API looks like this.” and there is a link in : https://gist.github.com/billerickson/adcb5f261164932be02f
and there is in the line N.13: require_once( ‘inc/init.php’ );
Thank you.
Bill Erickson says
That simply loads the files required for the CRM: https://gist.github.com/billerickson/104b7f377e284a6e15901d75b4381b49
We’re using MeekroDB to connect with the MySQL database. So on line 40 where you see
$add = $db->insert( 'entries', $fields );
, that’s using MeekroDB.Juan says
Thank you very much for your help, I’ll going to try it.
I appreciate it.
Greetings.
Brad says
Bill,
Sorry for bringing up an old post, but what if there are some basic authentication requirements? How would I send the data via API?
Bill Erickson says
Every API is different so you’ll need to read their documentation. It’s usually as simple as passing an API key. See line 24 in the last code snippet on this article: https://www.billerickson.net/setup-convertkit-wordpress-form/
Murray says
Awesome! Works. Sending Contact info to a custom related site. Cool!
Thank you!
Abhi says
This not work on me when using confirmation type “Show Page” or “Go to URL”.
already add function and add action with ‘wpforms_process_complete’, and my function not hooked and the page direclty redirect;
Bill Erickson says
I recommend you contact WPForms support for help with your specific issue.