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();
});

10 thoughts on “Conditional Required Contact Form 7 Fields”

  1. How could you accomplish the same result but instead of a dropdown selection it was a checkbox?
    Exp. textarea_B is only required if checkbox_A is selected.

    1. Hello Justin,

      To check against a checkbox, you would use a different filter:

      add_filter( ‘wpcf7_validate_textarea’, ‘my_site_conditional_required’, 10, 2 );
      add_filter( ‘wpcf7_validate_textarea*’, ‘my_site_conditional_required’, 10, 2 );

      Checkboxes are sent through as arrays in the POST, so you would check against the first element in the array. For example, let’s say that your checkbox was set up this way in Contact Form 7:

      Checkbox
      [checkbox need-message “true”]

      So, the array element would be $_POST[‘need-message’][0] and the value, if checked, would be true. In your my_site_conditional_required function, you can then check for that to be true:

      if ( “your-message” == $name && “true” == $_POST[‘need-message’][0]) :
      if ( ” == $value ) :
      $result->invalidate( $tag, wpcf7_get_message( ‘invalid_required’ ) );
      endif;
      endif;

      Then, you can change the jQuery to trigger on the checkbox click and if it is checked, add the asterisk. Hope this helps!

  2. This is great! Do you know if there is a way to modify this so that if a field IS valid then change the value of the field?

    I am using jQuery to mask the phone field but I need to remove some characters when the field is valid, or on submission.

    Any thoughts?

  3. I feel like the answer to my problem may be here but I cannot sort it out yet!

    How would I add validation to ensure that at least one checkbox is checked in a form where there are several checkboxes? So something like this,

    What is your favorite drink?
    ___ soda
    ___ tea
    ___coffee

    And I want to be sure they check at least one of those boxes. Thanks in advance for any assistance!

    1. Hello Jim,

      The checkbox validation filter for Contact Form 7 is found in contact-form-7/modules/checkbox.php around line 198. You can add your own filter in your functions.php file or in your own plug-in for checkboxes:

      function my_site_checkbox_validation_filter( $result, $tag ) {
      	$tag = new WPCF7_FormTag( $tag );
      
      	$type = $tag->type;
      	$name = $tag->name;
      
      	$value = isset( $_POST[$name] ) ? (array) $_POST[$name] : array();
      
      	if ( 'No' == $_POST['have-water'] && "favorite-drink" == $name && empty( $value ) ) {
      		$result->invalidate( $tag, wpcf7_get_message( 'invalid_required' ) );
      	}
      
      	return $result;
      }
      
      add_filter( 'wpcf7_validate_checkbox', 'my_site_checkbox_validation_filter', 10, 2 );
      add_filter( 'wpcf7_validate_checkbox*', 'my_site_checkbox_validation_filter', 10, 2 );
      

      In my example, I am making the favorite drink option required if the user selects that they are not having water ('No' == $_POST['have-water']). If the user is not having water, and we’re checking the “favorite-drink” checkboxes, and the checkboxes are empty, we will display the error. I hope this helps! If you have any questions, let me know.

      Scott

  4. Good Morning,
    I’m developing a form, where I have two options on a radio button “Yes” and “No”, by default the “No” option is checked, but when the user checks yes it displays a new input file field to attach a file to the form (This option is displayed only if “Yes on the radio button” is marked).
    This is all done in Jquery ..
    However, if you check the “Yes” option, the input file field is mandatory .. (required)
    And I still can not figure it out ..
    Does anyone have any ideas?
    Remembering that the form is from contact form 7.

  5. Hi there,

    I was quite happy seeing there is a way to hack into CF7’s validation. Currently tried to do it with a checkbox that makes a telephone field required. It actually works, when I a) have the fields (i.e. fields are not missing on a form) and b) check the checkbox that makes the phone field required. As long as I don’t have those fields or don’t check the checkbox, the form just won’t validate. Did something change about the code for current CF7 versions?

    The code in use:

    add_filter( ‘wpcf7_validate_tel’, ‘xxx_conditional_required’, 9, 2 );
    add_filter( ‘wpcf7_validate_tel*’, ‘xxx_conditional_required’, 9, 2 );

    function xxx_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 && ‘Rückruf gewünscht’ == $_POST[‘Callback’][0] ) :
    if ( ” == $value ) :
    $result->invalidate( $tag, wpcf7_get_message( ‘invalid_required’ ) );
    endif;
    endif;

    return $result;
    }

    Thanks in advance

    Eno

Leave a Reply

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