「MW WP FORM」を使用していると、datepickerのカスタマイズを依頼される時が稀にあります。

特に、日付や曜日を選択できないようにカスタマイズしないと業務に支障が出る場合には必須となるでしょう。

この記事では、「MW WP FORM」の日付・曜日の非選択化を説明していきます。

# この記事で解決すること

  • MW WP FORMのdatepickerとACFなどのカスタムフィールドを組み合わせて、「休みの曜日などの定休日」や「祝日」を設定し、選択できないようにする。
  • また、営業期間が限られている業種の場合、例えば10月1日~12月2日までしか選択できないようにできる。
  • datepickerの「休みの曜日」や「祝日」が管理画面から変更できる

 

前提

前提として、datepickerはjQueryのプラグインなので、php+js(jQuery)にて処理をしていきます。

実装方法を多少なりとも理解していただきたいので、フルコードは最後に記載します。

また、下記の作業は完了しているものとします。

  • 「MW WP FORM」でのdatepickerの設定
  • ACFなどのカスタムフィールドが実装できる環境(defaultでもいいかも…)

処理の順序

  1. 管理画面
    • 「MW WP FORM」でのdatepickerの設定見直し(必須ではない)
    • ACFでフィールド設定
  2. phpの処理
    • 処理をどこで行うかの決定
    • 日付取得の関数化(フォーマット)
    • 営業期間の処理(日付選択範囲の設定)
    • 定休日の処理(曜日)
    • 定休日の処理(日付)
  3. js(jQuery)の処理
    • 営業期間の設定
    • 定休日の処理(日付)
    • 定休日の処理(曜日)
  4. 実装

    管理画面

    「MW WP FORM」の設定見直し

    この項は必須ではありませんが、MW WP FORMのdatepickerの仕様の理解として説明しておきます。

    まず、私の場合は下記に設定しました。

    MWWPFORM内エディタ

    [mwform_datepicker name="カレンダー" size="30" js="dateFormat:'yy年Md日',firstDay:1"]

    特に確認してほしいのが、jsの部分です。

    この部分ではdatepickerの設定を記載しています。

    name remark
    dateFormat 日付のフォーマット
    firstDay 0: 日曜日始まり
    1: 月曜日始まり

    その他の詳しい仕様は下記URLのオプションタブで詳しく説明してくれています。

    ちなみに、この部分で期間指定しようとしたのですが動きませんでした。

    ACFでフィールド設定

    次にACFでのフィールド設定です。

    ACFをインストールすると管理画面のメニューの下の方に「カスタムフィールド」の項目が表示されますので、そちらの「新規追加」から新たにフィールドグループを追加してください。

    次にフィールド追加から、「営業開始日」「営業終了日」「定休日(曜日)」「定休日(日付)」を下記の内容に設定します。(サンプルなのでお好きなように)

    営業開始日

    項目名 設定値
    フィールドラベル 営業開始日
    フィールド名 range_start
    フィールドタイプ デイトピッカー
    表示フォーマット 任意
    返り値のフォーマット Custom: Y/n/j
    週の始まり 任意

    営業終了日

    項目名 設定値
    フィールドラベル 営業終了日
    フィールド名 range_end
    フィールドタイプ デイトピッカー
    表示フォーマット 任意
    返り値のフォーマット Custom: Y/n/j
    週の始まり 任意

    定休日(曜日)

    項目名 設定値
    フィールドラベル 定休日(曜日)
    フィールド名 holiday_date
    フィールドタイプ チェックボックス
    選択肢 1 : 月
    2 : 火
    3 : 水
    4 : 木
    5 : 金
    6 : 土
    0 : 日
    レイアウト 水平(の方が見やすいです)
    返り値 Value

    定休日(日付)

    日付はdatepickerの繰り返しフィールドでもいいのですが、繰り返しフィールドがPro版の機能なので、今回はテキストエリアにて説明します。

    項目名 設置値
    フィールドラベル 定休日(日付)
    フィールド名 holiday_day
    フィールドタイプ テキストエリア
    説明 形式(半角英数):2022-01-01
    ※改行で複数入力
    ※文字列の最後にスペースが入らないよう気をつける
    (って書いておいた方がトラブル少ないです)
    改行 何もしない

    位置

    また、フィールドの下に別ブロックで「位置」という項目がありますが、これはこのフィールドを表示させる箇所を指定するものとなります。

    今回は仮に「ページ」「等しい」「予約」としましょう。
    ※「予約」はこちらで設定しているフォームを設置したページのページ名ですので、任意のページを指定してください。
    尚、今回設定した「予約」のslugは「reserve」とします。

    ここまでで管理画面内の設定は完了となります。

    phpの処理

    処理をどこで行うかの決定

    さて、php側の処理ですが、、、
    どこでしましょうか。。。

    思いつく選択肢は3つです。

    • functions.php or custom_functions.phpに入れ込む
      jsが絡んでいるので、処理がかなり面倒
      日付を更新できなくていい場合は、jsだけなのでwp_enqueue_scriptsで対処できます
    • ページテンプレートpage-slug.phpを作って入れ込む
      私はこの方法で入れていますが、そもそもページテンプレートを作成していない人口の方が多そう
    • footer.phpに入れ込む
      よしこれだ!
      ※まとめたコードは最後に記載しますので、読んでいただけると嬉しいです!

    日付取得の関数化(フォーマット)

    今回はACFの返り値とは異なる日付フォーマットを多用しますので、わかりやすいように関数化しておきましょう。

    function returnDate($date) {
    
      // $date = "Y/n/j"
      $array = explode('/', $date); 
    
      // "Y,n-1,j"
      return "{$array[0]},{$array[1]}-1,{$array[2]}";
    
    }

    ACFで設定した値が「Y/n/j」なので、explodeを使用して「/」で分割し、配列にしています。

    {$array[1]}を-1しているのは、phpの仕様上です。

    営業期間の処理(日付選択範囲の設定)

    次に、上記の関数を元に営業期間(営業開始日と営業終了日)を変数に格納します。

    // reserve = 位置設定で指定したページのslug
    $start_text = returnDate(get_field('range_start', get_page_by_path("reserve")->ID));
    $end_text   = returnDate(get_field('range_end', get_page_by_path("reserve")->ID));

    get_field('フィールド名', ID)は、「ID」のページにある「フィールド名」の情報を取得してきます。

    今回はページIDを入れ込むのが面倒なので、get_page_by_path

    定休日の処理(曜日)

    定休日はjs側に値を送る必要があるので、処理しやすいようにjson形式にパースしておきます。

    // 定休日(曜日)の取得
    $holiday_date = get_field('holiday_date', get_page_by_path("reserve")->ID);
      
    // 返り値がString型なのでint型に変更
    foreach($holiday_date as $k => $v) { 
      $holiday_date[$k] = (int) $v;
    }
      
    // json形式にエンコード
    $holiday_date_object = json_encode($holiday_date);

    定休日の処理(日付)

    こちらもjs側に値を送る必要があるので、処理しやすいようにjson形式にパースしておきます。

    // 定休日(日付)の取得
    $holiday_day = get_field('holiday_day', get_page_by_path("reserve")->ID);
      
    // 改行で分割して配列に(ACFテキストエリアの性質上)
    $holiday_day_array = explode("\r\n", $holiday_day);
      
    // json形式にエンコード
    $holiday_day_object = json_encode($holiday_day_array);
    

    ACF内で改行で日付を登録してもらったのは、\r\nつまり改行で区切って配列化するためです。

    ここまででphp側の処理は完了です。

    js(jQuery)の処理

    今までの処理はあくまで下準備なので、上記を行ったからといって反映されるわけではありません。

    ここからはjs(jQuery)を使用して、今まで行った作業が無駄にならないように実装していきます。

    営業期間の設定

    jQuery(function($) {
      $('input[name="カレンダー"]').datepicker('option', 'minDate', new Date(<?php echo $start_text?>));
      $('input[name="カレンダー"]').datepicker('option', 'maxDate', new Date(<?php echo $end_text?>));

    datepickerのoptionにminDateとmaxDateを送るというコードです。

    "カレンダー"は最初にMW WP FORM内にて設定したname属性になります。

    [mwform_datepicker name="カレンダー" size="30" js="dateFormat:'yy年Md日',firstDay:1"]

    ちなみにoptionをObjectにしても動くんじゃないかと思いましたが無理でした…

    定休日の処理(日付)

    $('input[name="カレンダー"]').datepicker('option', 'beforeShowDay', function(date){
    
      // 定休日(曜日)の取得
      var holiday_day = <?php echo $holiday_day_object ?>;
    
      // 定休日(曜日)のjsonを回す
      for (var i = 0; i < holiday_day.length; i++) {
      
        // 協定世界時のミリ秒取得
        var holiday_time = Date.parse(holiday_day[i]);
      
        // 日付を初期化
        var holiday      = new Date();
      
        // 経過ミリ秒の取得
        holiday.setTime(holiday_time);
        
        // 各日付ブロックとの相違判定
        if (holiday.getYear() == date.getYear() && holiday.getMonth() == date.getMonth() && holiday.getDate() == date.getDate()) {
        return false;  // 全て一致で非選択の日付ブロックとする
        }
      }
    

    簡単に説明すると、「holiday_dateに格納された日付と、カレンダーの日付ブロックが一致すればfalse(非選択)」という意味です。

    定休日の処理(曜日)

        // 定休日(曜日)の取得
        var holiday_date = <?php echo $holiday_date_object ?>;
        
        // 曜日が一致すれば非選択とする
        return [!holiday_date.includes(date.getDay())];
      });
    });

    holidate.dateに各日付ブロックの曜日が含まれていればfalse(非選択)を返してくれます。

    注意しないといけないのは、datepickerの仕様上、falseではなく[false]を返さなければいけないということです。

    実装

    変数に格納できる部分は格納しているので、上述の内容よりもスッキリしていると思います。

    変更する箇所は1行目と4行目、35行目です。

    footer.php

    <?php if(is_page('位置設定で指定したページのslug')):
    
      // 初期設定
      $form_page_id = get_page_by_path("位置設定で指定したページのslug")->ID;
    
      // 日付取得の関数化(フォーマット)
      function returnDate($date) {
        $array = explode('/', $date);
        return "{$array[0]},{$array[1]}-1,{$array[2]}";
      }
    
      // 営業期間の処理(日付選択範囲の設定)
      $start_text = returnDate(get_field('range_start', $form_page_id));
      $end_text = returnDate(get_field('range_end', $form_page_id));
    
      // 定休日(曜日)の設定
      $holiday_date = get_field('holiday_date', $form_page_id);
      foreach($holiday_date as $k => $v) { 
        $holiday_date[$k] = (int) $v;
      }
      $holiday_date_object = json_encode($holiday_date);
    
      // 定休日の処理(日付)
      $holiday_day = get_field('holiday_day', $form_page_id);
      $holiday_day_array = explode("\r\n", $holiday_day);
      $holiday_day_object = json_encode($holiday_day_array);
    
    ?>
    
    <script>
      jQuery(function($) {
    
        // 営業期間の設定
        // 複数項目がある場合は $('input[name="カレンダー1"]', 'input[name="カレンダー2"]')
        var calendar = $('input[name="カレンダー"]');
        calendar.datepicker('option', 'minDate', new Date(<?php echo $start_text?>));
        calendar.datepicker('option', 'maxDate', new Date(<?php echo $end_text?>));
    
        // 定休日の処理(日付)
        calendar.datepicker('option', 'beforeShowDay', function(date){
          var holiday_day = <?php echo $holiday_day_object ?>;
          for (var i = 0; i < holiday_day.length; i++) {
            var holiday_time = Date.parse(holiday_day[i]);
            var holiday = new Date();
            holiday.setTime(holiday_time);
            if (holiday.getYear() == date.getYear() && holiday.getMonth() == date.getMonth() && holiday.getDate() == date.getDate()) {
              return false;
            }
          }
    
          // 定休日の処理(曜日)
          var holiday_date = <?php echo $holiday_date_object ?>;
          return [!holiday_date.includes(date.getDay())];
        });
      });
    </script>
    
    <?php endif; ?>

    最後に

    上記は基本latestのみの確認になるので、絶滅したIEはもちろん、古めのブラウザでは確認していません。

    ただ36行目、37行目をはじめ所々参考にできるところはあるのかなと思い記事にしました。

    みなさんもぜひ案件に沿ってカスタマイズしてみてください!