Conditional Required Contact Form 7 Fields

Sometimes you may want to have a required field in Contact Form 7 only when another form field has a certain value. For example, if someone has an option to choose their preferred method of contact between email and telephone, you’d want to make the email address field or the phone call field required accordingly. This isn’t too difficult to accomplish in Contact Form 7. You can look at how Contact Form 7 validates text and email fields by viewing its code in:

contact-form-7/modules/text.php

Around line 91, you will see the validation filters defined by Contact Form 7:

add_filter( 'wpcf7_validate_text', 'wpcf7_text_validation_filter', 10, 2 );
add_filter( 'wpcf7_validate_text*', 'wpcf7_text_validation_filter', 10, 2 );
add_filter( 'wpcf7_validate_email', 'wpcf7_text_validation_filter', 10, 2 );
add_filter( 'wpcf7_validate_email*', 'wpcf7_text_validation_filter', 10, 2 );

Then, you can look at the function that handles the validation, wpcf7_text_validation_filter. The function accepts two parameters – $result and $tag. The $tag is the field being validated and the $result is, well, the result of the validation. In other words, did something go wrong?

The user-entered text of the field being checked is assigned to $value. Then, the function checks the current tag type. Is it text? Email? And it will process it accordingly. If a value is empty but the field is required, for example, the result will be invalid:

$result->invalidate( $tag, wpcf7_get_message( 'invalid_required' ) );

In this case the Contact Form 7 error message for required fields is given as an error (wpcf7_get_message( ‘invalid_required’ )). If $result-invalidate() is called, that field will fail validation and you will get a form error.

We’re not, of course, going to modify the plug-in’s files directly. We want to make our plug-in modifications safe from future plug-in updates so we will tie into the same filters that the plug-in uses. I can put this code in my theme’s functions.php file or put it into a my own plug-in. In my example, I am setting two conditional required fields – email and phone number. So, I will need to set my own custom validations for both text and email fields:

add_filter( 'wpcf7_validate_text', 'my_site_conditional_required', 10, 2 );
add_filter( 'wpcf7_validate_text*', 'my_site_conditional_required', 10, 2 );
add_filter( 'wpcf7_validate_email', 'my_site_conditional_required', 10, 2 );
add_filter( 'wpcf7_validate_email*', 'my_site_conditional_required', 10, 2 );

For both the text (phone) and email fields, I am using the function, my_site_conditional_required, for my own custom validations. Here is my complete function:

function my_site_conditional_required($result, $tag) {
    $tag = new WPCF7_Shortcode( $tag );

    $name = $tag->name;

    $value = isset( $_POST[$name] )
        ? trim( wp_unslash( strtr( (string) $_POST[$name], "\n", " " ) ) )
        : '';

    if ( "phone" == $name && 'Phone' == $_POST['contact-method'] ) :
        if ( '' == $value  ) :
            $result->invalidate( $tag, wpcf7_get_message( 'invalid_required' ) );
        endif;
    endif;

    if ( "email" == $name && 'Email' == $_POST['contact-method'] ) :
        if ( '' == $value ) :
            $result->invalidate( $tag, wpcf7_get_message( 'invalid_required' ) );
        elseif ( ! wpcf7_is_email( $value ) ) :
            $result->invalidate( $tag, wpcf7_get_message( 'invalid_email' ) );
        endif;
    endif;

    return $result;
}

Here is how it works. I am doing the same thing that Contact Form 7 does with setting the $value. Then, instead of checking the tag type, I want to check the tag name. I specifically want to look for the fields named “phone” or “email.” I also have a dropdown named “contact-form” so I can check the $_POST value of contact-form and use that to see if the field being checked should be required. If $_POST[‘contact-form’] is equal to “Phone,” I want the phone field to be required:

if ( "phone" == $name && 'Phone' == $_POST['contact-method'] ) :
        if ( '' == $value  ) :
            $result->invalidate( $tag, wpcf7_get_message( 'invalid_required' ) );
        endif;
endif;

I have an extra check for the email. I don’t just want to require the email address, I want to make sure it is a valid email address as well. Contact Form 7 provides a function to check an email, wpcf7_is_email:

elseif ( ! wpcf7_is_email( $value ) ) :

As you can see, my custom function works very similarly to the code in the plug-in. Finally, you probably want to show the user the field that is required based on their downdown selection. I added empty spans after the field labels that I can use to add and remove informational asterisks from:

<label class="email-label">Email</label>

Then, I can use jQuery to add and remove the asterisks:

jQuery(function() {
  add_required_asterisks();
  jQuery("select[name='contact-method']").on('change', function() {
    add_required_asterisks();
  });
});

function add_required_asterisks() {
  if ( jQuery("select[name='contact-method']").val() == "Phone" ) {
    jQuery(".phone-label .asterisk").html("*");
    jQuery(".email-label .asterisk").html("");
  }
  else {
    jQuery(".phone-label .asterisk").html("");
    jQuery(".email-label .asterisk").html("*");
  }
}

I created a JavaScript function that will see what my dropdown menu (named “contact-method”) is set to and then, based on that, turn the asterisks on or off. Then, I call that function on page load and, whenever the dropdown changes:

jQuery("select[name='contact-method']").on('change', function() {
add_required_asterisks();
});