投稿日:2022年10月8日

修正日:2022年10月10日(修正内容へ

先日、Contact Form 7 で作成した申し込みフォームに、上限に達したら受け付けを終了したいとの要望がありました。

Contact Form 7のデフォルトの設定には上記のようなエントリー数を制限する機能はありません。
プラグインがありそうなので検証してみました。

WPAppsDev – CF7 Form Submission Limit というプラグインが見つかりましたが、望んでいるような動作はしませんでした。

▲最新のWordPressにも対応しています。

▲色々な設定がありますが、申し込みページにアクセスした際にリダイレクトはされないようです。
submitをクリックした後に上限に達している内容のメッセージを表示します。
設定した日でリセットするようですが検証はしていません。

▲submitをクリックすると上記のメッセージが表示されます。
直訳すると「フォームの送信制限を超えたため、このフォームを送信できません。」です。
これではユーザーフレンドリーとは言えません。

以前の記事 で、Contact Form 7 の申し込み内容をデータベースに保存するContact Form 7 Database Addon – CFDB7 を紹介しました。

データベースに登録されたユーザーのID値を申し込み数とし、ajaxを使って取得。
設定した上限値を超えたら「申し込みは終了しました。」ページにリダイレクト。
というロジックにしたいと思います。

▲テーブル wp_db7_formform_id を申し込み数として取得します。

子テーマの中に headre.php を複製し下記の15〜55行目を追記します。
テーマは Twenty Twenty-One を使用しています。

if(end($idData)==xx){ //申し込み人数
	 header("Location:https://onebitious.net/cf7_num_limit/index.php/app_end/");
}

▲50〜52行目。
end($idData)で配列の最後の数値、すなわち総数を取得します。
総数が xx の数と一致したら、header("Location:〜);のPHP関数で指定したURLへリダイレクトさせます。
ただし、このPHPの関数 header("Location:〜); は57行目の<!doctype html>などのhtmlが出力する前に記述する必要があります。
htmlタグやheadタグが出力された後だとリダイレクトされないのでご注意ください。

<?php if(is_page(11)): ?>
  <header class="entry-header alignwide"><h1 class="entry-title"><?php the_title(); ?></h1></header>
<?php endif ?>

▲71〜73行目。
固定ページをホームページに設定すると、そのページのタイトルが表示されないというWordPressの仕様があります。

タグと属性を含めて the_title 関数で出力してます。

▲リダイレクトされました。

まとめ

今回の header.php に記述する方法は Full Site Editing に対応する以前のテーマが対象になります。
Twenty Twenty-One まではheader.phpが存在してましたが、Twenty Twenty-Two では存在しません。
headの出力はWordPress自体が担っている仕様に変更されたようです。
wp-includes > template-canvas.php の13行目。(下記)

<?php
/**
 * Template canvas file to render the current 'wp_template'.
 *
 * @package WordPress
 */

/*
 * Get the template HTML.
 * This needs to run before <head> so that blocks can add scripts and styles in wp_head().
 */
$template_html = get_the_block_template_html();
?><!DOCTYPE html>
<html <?php language_attributes(); ?>>
<head>
	<meta charset="<?php bloginfo( 'charset' ); ?>" />
	<?php wp_head(); ?>
</head>

<body <?php body_class(); ?>>
<?php wp_body_open(); ?>

<?php echo $template_html; // phpcs:ignore WordPress.Security.EscapeOutput ?>

<?php wp_footer(); ?>
</body>
</html>

▲13行目。
PHPの閉じタグ ?><!DOCTYPE html> の間に、前述のheadre.php 15〜55行目のソースを記述すれば動作はします。
が、WordPressのバージョンアップの際に元に戻ってしまうので良い方法ではありません。
色々試しましたが、今のところこれと言った解決策が見出せていません。

今回のエントリー数だけではなく、指定した日付になったら締め切るとかの仕様も検証していきたいと思います。

なお、ソースコードはご自由に使っていただいても構いませんが、不備など起こっても責任は負いませんのでご了承ください。

最後まで読んでくださりありがとうございました。

修正

PHPの関数 header("Location:〜); だとhtmlが出力される前に記述する旨を紹介しました。
後日、WordPress Codex を調べたところ wp_redirect という関数があることを知りました。

この関数を使えば functions.phpフックとして記述することができるのでこちらを推奨します。
ソースコードは下記

// 人数制限になったら締め切りページへ飛ばすフック
function limit_page_redirect(){
  if(is_page(11)){
	  function db_connect(){ //データベース接続関数
      $db_user = "xxxxxxxxx"; //ユーザー名
      $db_pass = "xxxxxxxxx"; //パスワード
      $db_host = "xxxxxxxxx"; //ホスト名
      $db_name = "xxxxxxxxx"; //データベース名
      $db_type = "mysql"; //データベースの種類
      $dns = "$db_type:host=$db_host;dbname=$db_name;charset=utf8";

      try {
        $pdo = new PDO($dns, $db_user, $db_pass);
        $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
      } catch (PDOException $Exception) {
        die('接続エラー:' . $Exception->getMessage());
      }
      return $pdo;
    }
    $pdo = db_connect(); //データベースへ接続

    // フィールドform_idを取得
    $idStmt = $pdo->prepare("SELECT form_id FROM wp_db7_forms");
    $idStmt->bindValue(':form_id', 'form_id', PDO::PARAM_INT);
    $idRes = $idStmt->execute();

    // 設定した日時で終了する場合
    date_default_timezone_set('Asia/Tokyo');
    $limitTime = new DateTime('2022-10-20 10:40'); // 終了する日時

	  if ($idRes) {
      $idData = $idStmt->fetchAll(PDO::FETCH_COLUMN);

		  foreach ($valData as $index => $valVal) {
        $id = $idData[$index]; //ID
		  }

		  if(end($idData)== 5 || new DateTime > $limitTime){ //申し込み人数、もしくは指定の日時になったら
			  wp_redirect("https://onebitious.net/cf7_num_limit/index.php/app_end/");
		  }
	  }
  }
}
add_action('wp_enqueue_scripts','limit_page_redirect');

▲29〜30行目に日付を取得するロジックを追加してます。
39行目、人数に至るか、指定日時になったらリダイレクトする処理に変更しました。

Pocket