1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Contact Form 7】複数フォーム&選択項目が頻繁に更新されるフォームでのバリデーション

Last updated at Posted at 2025-03-02

概要

ContactForm7(以下、CF7)で作った問い合わせフォームでは、 wpcf7_validate をフックしてバリデーションを実施できます。詳細は以下参照。

ここでの問題点

以下のような場合、厄介なことになりそう(なった)

  • CF7で作成したフォームが同一サイト内で複数存在する
  • フォームを複製作成してしまい、name値が同じでも、inputの種類や選択項目が違う
  • チェックボックスなどの選択項目の内容が、頻繁に更新される

特に、選択項目の評価基準となるものがバリデーション関数内にベタ書きだと、ここの処理も更新作業が発生します。
そのため、常に最新のフォームから選択項目を参照する必要があります。

functions.php
add_filter('wpcf7_validate', 'my_form_validate', 11, 2);
function my_form_validate( $result, $tags ) {
	$form = WPCF7_Submission::get_instance();
	if($form) {
		foreach( $tags as $tag ) {
            $type = $tag['type'];
            $name = $tag['name'];
            $post_data = $_POST[$name];
        switch($type) {
            case 'text':
        	case 'text*':
		        //何か処理入れる
        	    break;
            case 'select':
	        case 'select*':
		        $list = ['AAA', 'BBB', 'CCC'];
		        // ↑選択項目と同じ項目リスト。問い合わせフォームが更新されたら修正
		        if( !in_array( $post_data, $list ) ){
			        $result->invalidate($name, "エラー" );
		        }
	        break;
	      }
    	}
  }
  return $result;
}

Formデータを取得

ということで、フォームを表示するためのフォームデータを取得し、そこから選択項目などを引っ張ってきます。

CF7のカスタムバリデーションの記事を参考に判定処理を書くとこんな感じに(関数名が長い&ダサいので、適宜変更を推奨)。

まとめたコード

functions.php

// CF7の投稿IDからフォームデータを返す
function my_get_wpcf7_form_values_by_id( $id ) {
  $form = wpcf7_contact_form($id);
  $res = [];
  if($form) {
    $manager = WPCF7_FormTagsManager::get_instance();
    $form = $form->prop( 'form' );
    $form = $manager->replace_with_placeholders( $form );
    $form = $manager->restore_from_placeholders( $form );
    $form = $manager->replace_all( $form );
    $res = $manager->get_scanned_tags();
  }
  return $res;
}
// inputのname値から選択項目を返す
function my_get_form_values_by_name( $name, $tags ) {
  $res = [];
  if ( !is_array($tags) ) return $res;
  if($tags) {
	  foreach( $tags as $tag ) {
	    if( $tag->name == $name) {
	      $res = $tag->values;
	    }
	  }
  }
  return $res;
}

// バリデーション処理
add_filter('wpcf7_validate', 'my_form_validate', 11, 2);
function my_form_validate( $result, $tags ) {
  $form = WPCF7_Submission::get_instance();
  if($form) {
    $contact_form = WPCF7_ContactForm::get_current();
    $contact_form_id = $contact_form->id;
    $contact_tags = my_get_wpcf7_form_values_by_id($contact_form_id);
    
    $invalid_required = '必須項目に入力してください。';
    $invalid_input = '入力内容に誤りがあります。';

    foreach( $tags as $tag ) {
      $type = $tag['type'];
      $name = $tag['name'];
      $post_data = $_POST[$name];
      $option_values = my_get_form_values_by_name($name, $contact_tags);

      switch($type) {
        case 'text':
        case 'text*':
          // require
          if( $type == 'text*' && $post_data == '') {
            $result->invalidate( $name, $invalid_required);
          }
          // TODO: その他処理追加
          break;
        case 'select':
        case 'select*':
        case 'radio':
        case 'radio*':
          if( in_array( $type, array('select*','radio*') ) && $post_data == '' ) {
            $result->invalidate( $name, $invalid_required );
          }
          if( !in_array( $post_data, $option_values ) ) {
            $result->invalidate( $name, $invalid_input );
          }
          break;
        case 'checkbox':
        case 'checkbox*':
            if( $type == 'checkbox*' && is_null($post_data) ) {
              $result->invalidate( $name, $invalid_required );
            }
            if($post_data) {
              foreach( $post_data as $data ) {
                if( !in_array( $data, $option_values ) ) {
                  $result->invalidate( $name, $invalid_input );
                }
              }
            }
          break;
        case 'email':
        case 'email*':
              if( $type == 'email*' && $post_data == '' ) {
                $result->invalidate( $name, $invalid_required);
              }
              if( !empty($post_data) && !is_email($post_data) ) {
                $result->invalidate( $name, $invalid_input );
              }
          break;
        case 'tel':
        case 'tel*':
            if( $type == 'tel*' && $post_data == '' ) {
              $result->invalidate( $name, $invalid_required);
            }
            if( !empty($post_data) && !wpcf7_is_tel( $post_data ) ) {
              $result->invalidate( $name, $invalid_input );
            }
          break;
        case 'textarea':
        case 'textarea*':
          if( $type == 'textarea*' && $post_data == '' ) {
            $result->invalidate( $name, $invalid_required );
          }
          break;
        case 'number':
        case 'number*':
          if( $type == 'number*' && $post_data == '' ) {
            $result->invalidate( $name, $invalid_required );
          }
          if ( !empty($post_data) && !wpcf7_is_number($post_data) ) {
            $result->invalidate( $name, $invalid_input );
          }
          break;
        case 'date':
        case 'date*':
          if( $type == 'date*' && $post_data == '' ) {
            $result->invalidate( $name, $invalid_required );
          }
          if ( !empty($post_data) && !wpcf7_is_date($post_data) ) {
            $result->invalidate( $name, $invalid_input );
          }
          break;
      }
    }
  }
  return $result;
}

ポイントなど

$_POSTからが推奨らしい

バリデーション系の記事を読み漁っていくと、WPCF7_Submissionクラスのget_posted_data()で送信内容を入れるパターンもありましたが、これはプラグイン内でサニタイズしたデータだそうです。
CF7も生の$_POSTで検証を奨めていたので、そちらを採用しました。

選択項目のバリデーション

my_get_form_values_by_name($name, $contact_tags); で選択項目が配列で返ってくるので、ベタ書きしたリスト配列から置き換え。
※CF7は標準でjsでのバリデーションを行っているようですが、所謂「悪意あるユーザー」対策として、選択項目に対しても厳密なバリデーションを行っています。

if( !in_array( $post_data, $option_values ) ) {
    $result->invalidate( $name, $invalid_input );
}

判定処理の関数

ここは個人の好みの問題だったり、状況に応じて書いていただきたいところですが、今回はWPとCF7内にあったバリデーション関数を使ってみました(長いものには巻かれろ精神)。

  • is_email($post_data)
  • wpcf7_is_tel( $post_data )
  • wpcf7_is_date($post_data)
    など
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?