So I’m working on a project for teh client. He requested some extra mumbo jumbo crazy stuff form to be delivered, so I thought – “Contact Form 7”, download, install – done. Nope, that wasn’t the case this time 😀

Basically the form he wants to have has a built in data validation for the phone number (some regex digit parsing) – this feature is unfortunately not built in the CF7 plugin…

After doing some brief search I found this topic:
http://wordpress.org/support/topic/plugin-contact-form-7-phone-number-validation?replies=10


It basically solved the whole issue, apart from the fact, that the solution is wrong…
Well, not exactly wrong, but – never ever, edit core plugin files, unless it’s totally impossible to do it other way around – if you do, then any update will simply overwrite them and your work will be lost leaving the client unsatisfied.

For CF7 it’s really easy to add the requested and I’ll show you how to do it from within a theme functions.php file – the case is similar – if it’s your own theme, feel free to edit the functions.php file, if it’s not, and it will probably get updated, then create a child theme, or make a plugin – so that your changes wouldn’t get overwritten.

Here’s what I did (I used the code from the above forum, so most of the credit goes to cutescar2nis)

First let us split the code, so that I’d make more sense. In your theme directory create a dir, for example cf7extra, create two .php files inside – cf7hooks.php and cf7funcs.php.

This should look like that:

-- theme_name
   -- cf7extra
      -- cf7hooks.php
      -- cf7funcs.php

Then inside the functions php add the following:

[php]
// this will access the cf7extra directory and require_once all the files kept inside
// should work for child themes and plugins (not sure, I haven’t tested that and I can’t
// remember
foreach( glob(STYLESHEETPATH . ‘/cf7extra/*.php’) as $project_include ){require_once $project_include;}
[/php]

Next inside the cf7hooks.php place the following code:
[php]

// this add’s two shortcodes for digit and digit* defined in the
// rgicgier_text_shortcode_handler callback function
wpcf7_add_shortcode( ‘digit’, ‘rgicgier_text_shortcode_handler’, true );
wpcf7_add_shortcode( ‘digit*’, ‘rgicgier_text_shortcode_handler’, true );

add_filter( ‘wpcf7_validate_digit’, ‘rgicgier_text_validation_filter’, 10, 2 );
add_filter( ‘wpcf7_validate_digit*’, ‘rgicgier_text_validation_filter’, 10, 2 );

// this add’s error message for our digit shortcode
add_filter(‘wpcf7_messages’, ‘rgicgier_messages’, 1);

[/php]

Ok so, we’re adding some shortcodes using wpcf7_add_shortcode and a callback function. the “rgicgier” prefix can be any, that’s just a little credit to me 😉

Afterwards add the below code to the cf7funcs.php file:

[php]

function rgicgier_text_shortcode_handler( $tag ) {
if ( !is_array( $tag ) )
return ”;

$type = $tag[‘type’];
$name = $tag[‘name’];
$options = ( array ) $tag[‘options’];
$values = ( array ) $tag[‘values’];

if ( empty( $name ) )
return ”;

$validation_error = wpcf7_get_validation_error( $name );

$atts = $id_att = $size_att = $maxlength_att = ”;
$tabindex_att = $title_att = ”;

$class_att = wpcf7_form_controls_class( $type, ‘wpcf7-text’ );

if ( ’email’ == $type || ’email*’ == $type )
$class_att .= ‘ wpcf7-validates-as-email’;

if ( ‘digit’ == $type || ‘digit*’ == $type )
$class_att .= ‘ wpcf7-validates-as-digit’;

if ( $validation_error )
$class_att .= ‘ wpcf7-not-valid’;

foreach ( $options as $option ) {
if ( preg_match( ‘%^id:([-0-9a-zA-Z_]+)$%’, $option, $matches ) ) {
$id_att = $matches[1];
} elseif ( preg_match( ‘%^class:([-0-9a-zA-Z_]+)$%’, $option, $matches ) ) {
$class_att .= ‘ ‘ . $matches[1];
} elseif ( preg_match( ‘%^([0-9]*)[/x]([0-9]*)$%’, $option, $matches ) ) {
$size_att = ( int ) $matches[1];
$maxlength_att = ( int ) $matches[2];
} elseif ( preg_match( ‘%^tabindex:(\d+)$%’, $option, $matches ) ) {
$tabindex_att = ( int ) $matches[1];
}
}

$value = ( string ) reset( $values );

if ( wpcf7_script_is() && preg_grep( ‘%^watermark$%’, $options ) ) {
$class_att .= ‘ wpcf7-use-title-as-watermark’;
$title_att .= sprintf( ‘ %s’, $value );
$value = ”;
} elseif ( empty( $value ) && is_user_logged_in() ) {
$user = wp_get_current_user();

$user_options = array(
‘default:user_login’ => ‘user_login’,
‘default:user_email’ => ‘user_email’,
‘default:user_url’ => ‘user_url’,
‘default:user_first_name’ => ‘first_name’,
‘default:user_last_name’ => ‘last_name’,
‘default:user_nickname’ => ‘nickname’,
‘default:user_display_name’ => ‘display_name’ );

foreach ( $user_options as $option => $prop ) {
if ( preg_grep( ‘%^’ . $option . ‘$%’, $options ) ) {
$value = $user->{$prop};
break;
}
}
}

if ( wpcf7_is_posted() && isset( $_POST[$name] ) )
$value = stripslashes_deep( $_POST[$name] );

if ( $id_att )
$atts .= ‘ id=”‘ . trim( $id_att ) . ‘”‘;

if ( $class_att )
$atts .= ‘ class=”‘ . trim( $class_att ) . ‘”‘;

if ( $size_att )
$atts .= ‘ size=”‘ . $size_att . ‘”‘;
else
$atts .= ‘ size=”40″‘; // default size

if ( $maxlength_att )
$atts .= ‘ maxlength=”‘ . $maxlength_att . ‘”‘;

if ( ” !== $tabindex_att )
$atts .= sprintf( ‘ tabindex=”%d”‘, $tabindex_att );

if ( $title_att )
$atts .= sprintf( ‘ title=”%s”‘, trim( esc_attr( $title_att ) ) );

$html = ‘‘;

$html = ‘‘ . $html . $validation_error . ‘‘;

return $html;
}

function rgicgier_text_validation_filter( $result, $tag ) {
$type = $tag[‘type’];
$name = $tag[‘name’];

$_POST[$name] = trim( strtr( ( string ) $_POST[$name], “\n”, ” ” ) );

if ( ‘digit’ == $type || ‘digit*’ == $type ) {
if ( ” == $_POST[$name] ) {
$result[‘valid’] = false;
$result[‘reason’][$name] = wpcf7_get_message( ‘invalid_required’ );
} elseif ( ” != $_POST[$name] && !is_telnum( $_POST[$name] ) ) {
$result[‘valid’] = false;
$result[‘reason’][$name] = wpcf7_get_message( ‘invalid_dig’ );
}
}

return $result;
}

function is_telnum( $telnum ) {
$regexp = ‘/^[0-9\+\-]{7,}$/’;

$regexp1 = ‘/^\(?([0-9]{3})\)?[-. ]?([0-9]{3})[-. ]?([0-9]{4})$/’;
$regexp2 = ‘/^\(?([0-9]{3})\)?[-. ]?([0-9]{4})$/’;

if ( preg_match( $regexp2, $telnum ) || preg_match( $regexp1, $telnum ) )
return true;
else
return false;
}

function rgicgier_messages( $messages ) {
$messages = array(
‘invalid_dig’ => array(
‘description’ => __( “There is a field that sender is needed to fill in with numbers”, ‘wpcf7’ ),
‘default’ => __( ‘Please fill in your phone #’, ‘wpcf7’ )
)
);

return $messages;
}
[/php]

Well I ain’t gonna explain all of that. Note the following.

I added 4 functions:

rgicgier_text_shortcode_handler which is used on Front End adds a class to the digit shortcode, actually this is the least important part, though the longest one. The only difference between the original function are these lines
[php]
if ( ‘digit’ == $type || ‘digit*’ == $type )
$class_att .= ‘ wpcf7-validates-as-digit’;
[/php]

I’m not sure if all of that is needed (surely not) but I have not time to play with that, it doesn’t matter for the moment.

rgicgier_text_validation_filter this function validates the input, using the
is_telnum function, and the latter checks if the number is of the form XXX XXXX or XXXXXXX or XXX-XXXX, if not it returns false – simple, yet clever.


rgicgier_messages
is a function that returns a specific error message while digit* is not valid.

That’s it – our code won’t be affected by plugin updates, it’s quite logically separated into hooks and functions. Obviously it’s not a noob tutorial, but if you have any questions then post them below and I’ll reply ASAP 🙂

If you don’t get everything, then read:

add_filter on Codex

Reverse Engineering