投稿に日付欄を追加してjQuery UIのDatepickerでカレンダーから入力する

jQuery UI ThemeRoller
「臨時休業のお知らせなどを投稿する時に、休業期間を指定すると営業日カレンダーに反映される」という案件の場合、WordPress では期間(日付)の管理にカスタムフィールドを使うことになるでしょう。でもこのカスタムフィールドは見栄えがアレだしクライアント様にお使いいただくには気が引ける。そんな時はオリジナルなメタボックスを追加すれば解決です。
そんなようなプラグインはいくつもありますが、この程度なら functions.php にちゃちゃっと書く方が自由で快適。ついでに日付なら「2010/01/28」なんて書式を気にせず簡単入力できるように jQuery UI の Datepicker を使いましょう。 さらに、投稿は「臨時休業のお知らせ」だけじゃないので、当該カテゴリ選択時のみメタボックスを表示するようにするとユーザビリティとしてはドヤ顔できるレベルかと思われます。
「営業日カレンダーに反映される」はまた別の記事でご紹介しますぜ。俺って太っ腹。いやいや腹筋割れてますってば。

jQuery UI を拾ってくる

まずは ThemeRoller でお好みのテーマを作成するか選択します。手っ取り早くWordPress の管理画面に合わせるなら Gallery タブにある「Smoothness」が良さそうです。

「Smooothness」の下の[Download]ボタンをクリックするとモジュールの選択画面になります。

  • UI Core
  • Datepicker

の2つをチェックして、サイドバーのバージョンで 1.7.2 を選択(デフォルトで選択されてます)します(UI Core は WordPress 2.9.1 に同梱されてますがバージョンが 1.7.1 なので念のため)。下の黒い[Download]ボタンをクリックすればダウンロードが始まります。多分 jquery-ui-1.7.2.custom.zip がダウンロードされるので解凍してください。

必要な jQuery UI モジュールをアップロードする

以下のファイルを js, css はテーマフォルダ直下、png 画像はテーマフォルダ/images にアップロードします。

  • jquery-ui-1.7.2.custom/js/jquery-ui-1.7.2.custom.min.js
  • jquery-ui-1.7.2.custom/development-bundle/ui/i18n/ui.datepicker-ja.js
  • jquery-ui-1.7.2.custom/css/smoothness/jquery-ui-1.7.2.custom.css
  • jquery-ui-1.7.2.custom/css/smoothness/images/ui-*.png

js, css のファイル名の「-1.7.2.custom」部分はウザかったら削除しても OK です。その場合は以降のファイル名を適宜読み替えてください。さらに管理画面で Datepicker を使うためのスクリプトを自分で用意しないといけないので admin-script.js とかなんとかテキトウに js ファイルを作って(中身は後ほど説明します)テーマフォルダにアップロードします。

CSS をヘッダ、SCRIPT をフッタに配置する

なんでかって?スクリプトは後回しにした方がページ表示のパフォーマンスが良くなるからさ。って言われてるからさ。 functions.php に以下を追加します。

function my_styles(){
  wp_enqueue_style('my-jquery-ui', get_bloginfo('template_url') . '/jquery-ui-1.7.2.custom.css', array(), '1.7.2', 'all');
}
add_action('admin_print_styles', 'my_styles');

function my_scripts(){
  wp_enqueue_script('my-jquery-ui', get_bloginfo('template_url') . '/jquery-ui-1.7.2.custom.min.js', array('jquery'), '1.7.2', true);
  wp_enqueue_script('my-jquery-localize', get_bloginfo('template_url') . '/ui.datepicker-ja.js', array('my-jquery-ui'), '1.7.2', true);
  wp_enqueue_script('my-admin-script', get_bloginfo('template_url') . '/admin-script.js', array('my-jquery-ui'), false, true);
}
add_action('admin_print_scripts', 'my_scripts');

この wp_enqueue_style, wp_enqueue_script の書き方は admin_head アクションとかで LINKタグを直接書いたりするよりもオススメなはずなので覚えておきましょう。

日付入力メタボックスを追加する

これもパターン通りの書き方なので、怪しいプラグインを使ってハマるより覚えておいた方が幸せになれます。functions.php に以下を追加すると、、

function my_meta_date_box(){
  add_meta_box('my_meta_date', '臨時休業設定', 'my_meta_date_html', 'post', 'normal', 'high');
}
function my_meta_date_html($post, $box){
  echo '<input type="hidden" name="my_meta_nonce" id="my_meta_nonce" value="'.wp_create_nonce('my_meta_date').'" />';
  echo '<label for="date_start">開始日</label>';
  echo '<input class="datepicker" type="text" name="date_start" value="'. get_post_meta($post->ID, 'date_start', true) .'" size="25" />';
  echo '<a class="clear_date" href="#date_start">クリア</a>';
  echo '<span>&nbsp;&nbsp;&nbsp;&nbsp;〜&nbsp;&nbsp;&nbsp;&nbsp;</span><label for="date_end">終了日</label>';
  echo '<input class="datepicker" type="text" name="date_end" value="'. get_post_meta($post->ID, 'date_end', true) .'" size="25" />';
  echo '<a class="clear_date" href="#date_end">クリア</a>';
}
function my_meta_date_update($post_id){
  if(!wp_verify_nonce( $_POST['my_meta_nonce'], 'my_meta_date'))
    return $post_id;

  if(defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) 
    return $post_id;

  if('post' == $_POST['post_type']){
    if(!current_user_can('edit_post', $post_id))
      return $post_id;
  }else{
    return $post_id;
  }

  $date_start = $_POST['date_start'];
  if($date_start == '') $date_start = $_POST['date_end'];
  if($date_start == '') 
    delete_post_meta($post_id, 'date_start');
  else
    update_post_meta($post_id, 'date_start', $date_start);
	
  $date_end = $_POST['date_end'];
  if($date_end == '') $date_end = $date_start;
  if($date_end == '')
    delete_post_meta($post_id, 'date_end');
  else
    update_post_meta($post_id, 'date_end', $date_end);
}
add_action('admin_menu', 'my_meta_date_box');
add_action('save_post', 'my_meta_date_update');

こんな感じのメタボックスが投稿ページに表示されます。

開始日、終了日のどちらか一方のみ入力されていた場合は、他方に同じ日付を設定してます。両方とも未入力ならメタデータを削除しています。人にはできるだけ親切に接するようにしましょうね。さらにちゃんとするなら、日付値は手入力もできるので書式チェックをすると良いでしょう。

カレンダーで日付入力

日付入力欄をクリックすると Datepicker が表示されるようにします。ついでに入力値をクリアするリンクも付けます。テキトウに名付けた admin-script.js に以下を記述。

jQuery(document).ready(function($){
  // clear date inputbox
  $('.clear_date').click(function(){$(this).prev().val(''); return false;});
  // datepicker
  if($.fn.datepicker){
    $('.datepicker').datepicker($.datepicker.regional['ja']);
  }
});

日付欄をクリックするとカレンダーが表示されるようになりました。あー、「年」の表示が抜けてますね。ui.datepicker-ja.js の月値を設定しているところに「年」を追加しましょう。

monthNames: ['年 1月','年 2月','年 3月','年 4月','年 5月','年 6月',
'年 7月','年 8月','年 年 9月','年 10月','年 11月','年 12月'],
monthNamesShort: ['年 1月','年 2月','年 3月','年 4月','年 5月','年 6月',
'年 7月','年 8月','年 年 9月','年 10月','年 11月','年 12月'],

これで OK です。Datepicker は他にも色々オプションがあります。詳しい使い方は FUNCTIONAL DEMO: Datepicker 辺りを参考にしてください。

臨時休業カテゴリーのときだけ日付欄を表示する

さて、カスタムフィールドやメタボックス系プラグンがイマヒトツなのは、どの投稿でもソレが表示されてしまうことです。関係ない入力欄が表示されているとクライアントは混乱しますし、要らぬ問い合わせの元にもなります。今回の場合なら「臨時休業」カテゴリーのときだけ日付欄を表示したいですよね。先ほどの admin-script.js の最後行 });の直前に以下を挿入してください。

  function my_meta_box_display(){
    var cats = $('input:checked', '#categorydiv .tabs-panel:visible') || []; 
    var vals = [];
    cats.each(function(){
      vals.push($(this).val());
    });
	
    var $metabox = $('#my_meta_date');
    if(jQuery.inArray('1', vals) != -1)  //  メタボックスを表示したいカテゴリーID(例:1)
      $metabox.stop()
        .slideDown('fast', function(){$(this).css('backgroundColor', '#bbffbb').animate({backgroundColor: '#ffffff'})});
    else
      $metabox.stop()
        .css('backgroundColor', '#ffbbbb')
        .animate({backgroundColor: '#ffffff'}, {complete: function(){$(this).slideUp('fast');}});	  
  }
  // click on category
  $(':checkbox', '#categorydiv').click(function(){
    my_meta_box_display();  
  });
  // initial
  my_meta_box_display();

新規投稿、投稿の編集、カテゴリーのチェック動作すべてに対応しています。表示/非表示の切り替え時に余計なアニメーションをさせていますので、不要なら show, hide にでも変えればいいさグスン。

最後に、 messy な[カスタムフィールド]は[表示オプション]で非表示にしちゃいましょう。いちいち手動で設定するのがメンドウなら 管理画面をカスタマイズする を参考にして、投稿画面をスッキリさせると吉。

動作確認バージョン
  • WordPress 2.9.1
  • jQuery UI 1.7.2

27 Comments

  • BLOG POST: 投稿に日付欄を追加してjQuery http://bit.ly/aQXXHP

  • なるほど – 投稿に日付欄を追加してjQuery UIのDatepickerでカレンダーから入力する http://bit.ly/91Ubjx

  • 投稿に日付欄を追加してjQuery UIのDatepickerでカレンダーから入力するhttp://bit.ly/9qCBI6

  • そう そう

    ありがとうございます!
    add_meta_boxの使い方勉強になりました。今後も使わせていただきます!

  • 投稿に日付欄を追加してjQuery UIのDatepickerでカレンダーから入力する  |  wpxtreme http://htn.to/pvUHJJ

  • kz kz

    お役に立てて良かったです◎今年も WordPress をガシガシ使いましょう!

  • これ、何かに使えそうなのでふぁぼ:wpxtreme 投稿に日付欄を追加してjQuery UIのDatepickerでカレンダーから入力する http://bit.ly/eJJg5r

  • kazuma kazuma

    イベントスケジュールとして活用したく、検索していたところ貴サイトに辿り着きました。

    今回、カテゴリーではなくカスタム投稿タイプ’event’を作り、そこでこちらで紹介されている機能を実装したいのですが、どうもうまく動きません。

    [日付入力メタボックスを追加する]項のソースのうち、2行目と20行目の’post’を’event’に変更しなければならないとは思うのですが、入力画面ではカスタムフィールド値として保存されていても、投稿一覧画面でカスタムフィールド値として表示されません。

    お忙しいところ誠に申し訳ございませんが、何卒ご指南いただきますようよろしくお願いいたします。

  • kazuma kazuma

    先程投稿したものです。

    すいません、こちらのチェックミスでちゃんとメタ値を吐き出していました。

    おかげさまで思い通りのカスタマイズができました。

    今後も参考にさせていただきます。

    ありがとうございました。

    • kz kz

      無事解決したようで良かったです◎
      WordPress でイベントをもっと楽&ステキに扱えるといいですよね!

  • はまちゃん はまちゃん

    はじめまして、
    add_meta_boxの使い方とっても参考になりました。

    一つお聞きしたいことがあるのですが、
    日付入力欄を複数設置して、
    各日付入力欄の横にセレクトボックスをそれぞれ設置しています。

    クリアをクリックした際、同じ行のセレクトボックスも一緒に
    クリア(選択を解除)したいのですが、うまくいきません。

    テキストボックス、セレクトボックスとも
    neme属性は配列で指定しています。

    どうぞよろしくお願い申し上げます。

    • kz kz

      セレクトボックスは「クリア」はできないので「未選択」とかなんとかを作ってそれを選択させます。
      <option value=”0″ selected=”selected”>— 未選択 —</option>
      な状態にしてあげればOK。
      そういう話でなくて、ってことでしたら「ちゃうよー!」ってお知らせください◎

    • はまちゃん はまちゃん

      お忙しい中、お返事ありがとうございます。

      えーっと、”カレンダーで日付入力”の個所で
      admin-script.js ファイルの中で jquery を利用して
      テキスト入力欄をクリアしていると思いますが、
      —————————————————————————-
      // clear date inputbox
      $(‘.clear_date’).click(function(){$(this).prev().val(”); return false;});
      —————————————————————————-
      ↑この部分???

      ここで一緒に同じ行(配列)のセレクトボックスを
      初期値に戻したいのですが。。。。

      可能でしょうか?

      説明が下手ですみません。m(__)m

      どうぞよろしくお願い申し上げます。

    • kz kz

      もちろん可能です◎
      「同じ行(配列)のセレクトボックス」だとアレなので、クリアのAタグから対応するセレクトボックスまでのDOM的な構成をお知らせただくと具体的にコードが書けます。
      現状だと、、
      $(‘.clear_date’).click(function(){
      $(this).prev().val(”);
      $(this).なんとか選択したいoptionまでたどり着く.attr(‘selected’, ‘selected’);
      return false;
      });
      が精一杯。

  • はまちゃん はまちゃん

    追記です。
    カスタム投稿タイプは
    「Custom Post Type UI」プラグインを使って作成しています。

    どうぞよろしくお願い申し上げます。

    • kz kz

      $(this).prev().val(”);
      の次の行に以下を追加すれば OK◎
      $(this).siblings(‘select’).find(‘option:first’).attr(‘selected’, ‘selected’);

    • はまちゃん はまちゃん

      ありがとうございました。

      admin-script.js の内容を下記のようにしましたが、
      セレクトボックスは無反応でした。
      —————————————————————————
      jQuery(document).ready(function($){
      // clear date inputbox
      $(‘.clear_date’).click(function(){$(this).prev().val(”); return false;});
      $(this).siblings(‘select’).find(‘option:first’).attr(‘selected’,'selected’);
      // datepicker
      if($.fn.datepicker){
      $(‘.datepicker’).datepicker($.datepicker.regional['ja']);
      }

      });
      —————————————————————————

      お手数をおかけして申し訳ありません。

    • kz kz

      「次の行」がアレでしたね。以下でOKです。
      $(‘.clear_date’).click(function(){
      $(this).prev().val(”);
      $(this).siblings(‘select’).find(‘option:first’).attr(‘selected’,’selected’);  
      return false;
      });

    • はまちゃん はまちゃん

      本当にありがとうございました。
      ばっちりクリアされました。
      おかげさまで思い通りのカスタマイズができて
      とても感謝しています。
      今後も参考に勉強させていただきますので、
      よろしくお願いいたします。

  • 投稿に日付欄を追加してjQuery UIのDatepickerでカレンダーから入力する  |  wpxtreme: http://bit.ly/icPeUS

  • jt jt

    素晴らしい記事でした!もう少しリクエストがあるのですが、
    ・カレンダーに投稿日を反映するのではなく、開始日〜終了日を反映させたい。
    ・開始日、終了日のどちらかしか入力されてなくてもそのままでいてほしい。
    (1日しか無い場合にも○○〜○○と表示されてしまう)
    ・日付表示を2011/05/12から2011年05月12日[木]としたい

    特に期間をカレンダーに反映させるのは必須で、なんとか試行錯誤しましたが
    わかりませんでした。

    お時間あるときにご教授よろしくお願いします。

    • kz kz

      >開始日、終了日のどちらかしか入力されてなくてもそのまま
      以下でOK!

      $date_start = $_POST['date_start'];
      if($date_start == ”)
      delete_post_meta($post_id, ‘date_start’);
      else
      update_post_meta($post_id, ‘date_start’, $date_start);

      $date_end = $_POST['date_end'];
      if($date_end == ”)
      delete_post_meta($post_id, ‘date_end’);
      else
      update_post_meta($post_id, ‘date_end’, $date_end);

    • jt jt

      ありがとうございます。出来ました!
      言われてみるとなるほどって感じですね。
      助かりました。

  • jt jt

    日付の表示方法はui.datepicker-ja.jsを書き換えてできました!

    ・範囲をカレンダーに反映の件が難解です。
    (カレンダーはデフォルトのカレンダーです。)
    よろしくお願いします。

  • 投稿に日付欄を追加してjQuery UIのDatepickerでカレンダーから入力する  |  wpxtreme http://htn.to/gNchuy