WordPress – Contact 7 Form – Using A ShortCode Parameter To Determine Email Recipient

The Problem

The challenge was that different WordPress pages pointed to a form where the only difference on the form was the recipients email address. This meant for every page a form needed to be created, this meant a lot of overhead as a large number of forms needed. All the same apart from the recipient email address.

Solution

Create the same form, but interrupt the form before it was sent, using a short code parameter to provide information that could be looked up a table (php array) and then override the recipient email. Not perhaps the most tidiest solution but good enough this particular user case.

Note this has only been tested on Contact 7 Forms version 6.1.4.

For example a short cut maybe like this

[contact-form-7 id="000000" title="Contact Form - Coordinator" dynamic-recipient="lookupkey"]

The lookupkey can be set to whatever your like, and will later be mapped to an email address.

Enabling ShortCode ATTRIBUTES

This dynamic-recipient short code attr needs to be processed within the contact-form-7 shortcode. One way is to amend the current wordpress themes functions.php file. and add the following:

add_filter( 'shortcode_atts_wpcf7', 'custom_shortcode_atts_wpcf7_filter', 10, 3 );
function custom_shortcode_atts_wpcf7_filter( $out, $pairs, $atts ) {
    $my_attributes = array('dynamic-recipient', 'another-parameter');
    foreach( $my_attributes as $value ) {
        if (isset($atts[$value])) {
            $out[$value] = $atts[$value];
        }
    }
   return $out;
}

The $my_attributes is an array, which means this routine will allow other shortcut attributes to be added in the future. For the time being we have added the dynamic-recipient parameter.

Again within the functions.php the following array const was setup to provide the various lookup capabilities:

CONST WPCF7_DYNAMIC_EMAIL_ROUTING = [
    'form_titles' => [
        'Contact Form',
        'Another Form'
    ],
    'form_routes' => [
        'route1'.                       => 'route1@emailaddress.com',
        'route2'                        => 'route2@emailaddress.com'
    ]
];

Following this adding the following code snippet provides a way of interrupting the form before it is actually sent. I found various mashes of AI and older versions of this, stating changes to this functionality in the later versions of Contact 7.

/*
 * Copes With different forms - where a parameter is sent with a dynamic-recipient value
 * and this is looked up to an email address.
 *
 * Change routing to cope with different regions.
 *
 * Will check if this applied to the form via the WPCF7_DYNAMIC_ROUTING['form_titles']
 * If it is then check that there is a valid route passed by they param `dynamic-recipient`,
 * this is then looked up in the WPCF7_DYNAMIC_ROUTING['form_routes'] keys
 * If it exists will replace the mail recipient with the value in the WPCF7_DYMANIC_ROUTING.
 */
add_filter( 'wpcf7_before_send_mail', function($WPCF7_ContactForm) {
    // Filter - Only run against specific form titles
    if(!in_array($WPCF7_ContactForm->title(), WPCF7_DYNAMIC_EMAIL_ROUTING['form_titles'])) {
        return;
    }
    // Submit in the background
    $submission = WPCF7_Submission::get_instance();
    if (!$submission) return; // Invalid submission - just return with the errors shown


    $posted_data = $submission->get_posted_data();
    $routeLookUp = sanitize_text_field($posted_data['dynamic-recipient']);
    
    // Check if the form_route exists, if not just return, will just allow to send - check validation routine to stop this
    if (!array_key_exists($routeLookUp, WPCF7_DYNAMIC_EMAIL_ROUTING['form_routes'])) return; // may need to skip here

    // Override email properties
    $mail = $WPCF7_ContactForm->prop('mail');
    $mail['recipient'] = WPCF7_DYNAMIC_EMAIL_ROUTING['form_routes'][$routeLookUp];
    $WPCF7_ContactForm->set_properties(['mail' => $mail]);
});

The function above, will check if the Contact Form title exists in the WPCF7_DYNAMIC_ROUTING, and if it does not it just exists out and the form is processed as normal.

There is a flaw in the above, if the form_title is valid and the the lookup value specified by the dynamic-recipient does not exists it will send the form, just to the mail recipient in the form. This is not all that desirable but needs to be handled in a different Contact 7 hook. See below:

/**
 * Following is used to validate before sending the form.  It will see if the form
 * exists using the form_title checking it exists against the WPCF7_DYNAMIC_ROUTE['form_titles'].
 * If it does not just continue.
 *
 * If it does check that the dynamic-recipient exists in the WPCF7_DYNAMIC_ROUTE['form-routes']
 * array_keys.  If it does not make the form invalid.
 */
add_filter('wpcf7_validate', function($result, $tags) {
   $contact_form = WPCF7_ContactForm::get_current();
   if (!in_array($contact_form->title(), WPCF7_DYNAMIC_EMAIL_ROUTING['form_titles'])) return $result;

   $submission = WPCF7_Submission::get_instance();
   if (!$submission) return $result;

   $data = $submission->get_posted_data();

   if (empty($data['dynamic-recipient']) ||
       !in_array($data['dynamic-recipient'], array_keys(WPCF7_DYNAMIC_EMAIL_ROUTING['form_routes'])))
   {
       $result->invalidate('dynamic-recipient', 'Invalid dynamic recipient');
   }
   return $result;
},  10, 2);

The above interrupt that validation, it checks if it should be applied against the form, using the form title. Then it checks if the route exists in the WPCF7_DYNAMIC_ROUTING and if it does not it reports back and invalidates the form. Note this is hidden from the user, but is present tin the payload received back from the feedback request.

Improvements

A better way would be to break this out into a plugin, use custom posts to setup form title validation, and form routes, and then this could be configurable from the WordPress Admin dashboards.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.