T.Sugiyama Official Blog

興味のあることを書いています。

【WordPress】カスタム投稿タイプでスケジュール表を作る

WordPress でカスタム投稿タイプを使ったので、メモ替わりにここに書いておきます。
普通の記事投稿画面では、タイトル、本文、サムネイル (画像)などが登録できるのですが、今回、ダンスレッスンのスケジュール表を作りたい!ということだったので、もっと簡単に登録できる画面が必要でした。

プラグインを使えば、使いやすい入力フォームでスケジュール表を作れるものもあるのですが、スケジュール表のデザイン、見た目の部分がなかなか思ったようにできず少し使い勝手が悪いなと思っていました。また、プラグインをカスタマイズするとなると、プラグインがアップデートされたときにどうなるんだろう?という心配もあったので、それならいっそのこと自分でそういうの作ろうと思い、調べてみました。
すると、出てきたワードが「カスタム投稿タイプ」。
これを使うと登録フォームをカスタマイズすることができるのだそうです。
そしてさらに、カスタム投稿タイプにカスタムフィールドを表示すれば、「名前」=>「値」を設定できて、
そうするとどうなるかというと、

「教室」=>「神戸」、
「講師」=>「◯◯先生」、
「レッスン」=>「HIP HOP初級」、
「曜日」=>「Mon」、
「開始時間」=>「20:00」、
「終了時間」=>「21:00」

というように、ラベルと情報を紐ずけられるのです。
そして、紐づけた情報によって、神戸教室だけのレッスンしか表示しない、この曜日のレッスンはここに表示する、開始時間が早い者順に表示する、などというように自由に情報を取ってこられるので、プラグインよりも自由なスケジュール表を作ることができるのです。
ただ、意気揚々と設定してから問題が!
試しに情報を登録したのですが、このカスタムフィールド、かなり使いにくい!

カスタムフィールド、かなり使いにくい...
カスタムフィールド、かなり使いにくい...
何が使いにくいかというと、いちいち毎回「名前」を入れないといけないのです。「値」は毎回でいいのですが、「名前」は毎回項目が決まっているのだから、いちいち入れるのはめんどくさい!
ということで辿り着いたのが、今回の方法です。
結論から言うと、↓ こう言う入力画面です。
入力フォームができました!
こういう入力画面を作りました
functions.php に ↓ こう言うコードを書きました。

/*
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
スケジュール
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
*/
//カスタム投稿タイプ(スケジュール)
  add_action( 'init', 'create_schedule' );
  function create_schedule() {
    $Supports = [
      'title',//名前
      'thumbnail',//顔写真
    ];
    register_post_type( 'schedule',
      array(
        'labels' => array(
          'name' => __( 'スケジュール' ),
          'singular_name' => __( 'Schedule' )
        ),
        'public' => true,
        'has_archive' => true,
        'menu_position' => 5,
        'supports' => $Supports
      )
    );
  }
//カスタムフィールド追加
  add_action('admin_menu','add_schedule_fields');
  function add_schedule_fields(){
    add_meta_box('custom-place_name', '教室', 'create_place_name', 'schedule', 'normal');
    add_meta_box('custom-instructor_name', '講師', 'create_instructor_name', 'schedule', 'normal');
    add_meta_box('custom-class_name', 'レッスン', 'create_class_name', 'schedule', 'normal');
    add_meta_box('custom-day_week', '曜日', 'create_day_week', 'schedule', 'normal');
    add_meta_box('custom-start_time', '開始時間', 'create_start_time', 'schedule', 'normal');
    add_meta_box('custom-finish_time', '終了時間', 'create_finish_time', 'schedule', 'normal');
  }
  function create_place_name() {
    $keyname = 'place_name';
    global $post;
    $get_value = get_post_meta($post->ID, $keyname, true);
    $data = ['神戸','伊丹'];
    wp_nonce_field('action-' . $keyname, 'nonce-' . $keyname);
    echo '<select name="'.$keyname.'" autofocus required=true>';
    echo '<option value="">-----</option>';
    foreach ($data as $d) {
      $selected = '';
      if ($d === $get_value) {
        $selected = 'selected';
      }
      echo '<option value="'.$d.'"'.$selected.'>'.$d.'</option>';
    }
    echo '</select>';
  }
  function create_instructor_name() {
    $keyname = 'instructor_name';
    global $post;
    $get_value = get_post_meta($post->ID, $keyname, true);
    wp_nonce_field('action-' . $keyname, 'nonce-' . $keyname);
    echo '<input name="'.$keyname.'"value="'.$get_value.'"autocomplete="off" required=true>';
  }
  function create_class_name() {
    $keyname = 'class_name';
    global $post;
    $get_value = get_post_meta($post->ID, $keyname, true);
    wp_nonce_field('action-' . $keyname, 'nonce-' . $keyname);
    echo '<input name="'.$keyname.'"value="'.$get_value.'"autocomplete="off" required=true>';
  }
  function create_day_week() {
    $keyname = 'day_week';
    global $post;
    $get_value = get_post_meta($post->ID, $keyname, true);
    $data = ['Mon','Tue','Wed','Thu','Fri','Sat','Sun'];
    wp_nonce_field('action-' . $keyname, 'nonce-' . $keyname);
    echo '<select name="'.$keyname.'" required=true>';
    echo '<option value="">-----</option>';
    foreach ($data as $d) {
      $selected = '';
      if ($d === $get_value) {
        $selected = 'selected';
      }
      echo '<option value="'.$d.'"'.$selected.'>'.$d.'</option>';
    }
    echo '</select>';
  }
  function create_start_time() {
    $keyname = 'start_time';
    global $post;
    $get_value = get_post_meta($post->ID, $keyname, true);
    $t = strtotime('00:00');
    for ($i=0; $i <5*12*24 ; $i+=10) { 
      $data[] = date('H:i',strtotime("+{$i} minutes",$t));
    }
    wp_nonce_field('action-' . $keyname, 'nonce-' . $keyname);
    echo '<select name="'.$keyname.'" required=true>';
    echo '<option value="">-----</option>';
    foreach ($data as $d) {
      $selected = '';
      if ($d === $get_value) {
        $selected = 'selected';
      }
      echo '<option value="'.$d.'"'.$selected.'>'.$d.'</option>';
    }
    echo '</select>';
  }
  function create_finish_time() {
    $keyname = 'finish_time';
    global $post;
    $get_value = get_post_meta($post->ID, $keyname, true);
    $t = strtotime('00:00');
    for ($i=0; $i <5*12*24 ; $i+=10) {
      $data[] = date('H:i',strtotime("+{$i} minutes",$t));
    }
    wp_nonce_field('action-' . $keyname, 'nonce-' . $keyname);
    echo '<select name="'.$keyname.'" required=true>';
    echo '<option value="">-----</option>';
    foreach ($data as $d) {
      $selected = '';
      if ($d === $get_value) {
        $selected = 'selected';
      }
      echo '<option value="'.$d.'"'.$selected.'>'.$d.'</option>';
    }
    echo '</select>';
  }

  add_action( 'save_post', 'save_schedule_fields' );
  function save_schedule_fields($post_id){
    $schedule_fields = ['place_name','instructor_name','class_name','day_week','start_time','finish_time'];
    foreach ($schedule_fields as $d) {
      if (isset($_POST['nonce-'.$d])&&$_POST['nonce-'.$d]) {
        if (check_admin_referer('action-'.$d, 'nonce-'.$d)) {
          if (isset($_POST[$d])&&$_POST[$d]) {
            update_post_meta($post_id,$d,$_POST[$d]);
          }else{
            delete_post_meta($post_id,$d,get_post_meta($post_id,$d,true));
          }
        }
      }
    }
  }

↑ functions.php に記述したコード
そうすると、管理画面の左端のメニューに、「スケジュール」が表示されます。

カスタム投稿タイプ「スケジュール」が表示されました!
カスタム投稿タイプ「スケジュール」が表示されました!
そして、「スケジュール」を開くと、入力フォームができています!
入力フォームができました!
入力フォームができました!
ここに入力した情報を表示ために、今回は page-scheduletable_kobe.php に下のコードを書きました。

<?php
/*
Template Name: スケジュールテーブル(神戸)
*/
$days = ['mon','tue','wed','thu','fri','sat','sun'];
foreach ($days as $d) {
  $$d = [ 'post_type'=>'schedule',
          'meta_query' => [
            ['key' => 'place_name', 'value' => '神戸'],
            ['key' => 'day_week', 'value' => ucwords(strtolower($d))],
            'time_clause' => ['key' => 'start_time']
          ],
          'orderby' => ['time_clause' => 'ASC']
        ];
}
$i=0;
get_header();
?>
  <div id="primary" class="content-area">
    <main id="main" class="site-main mx-auto">
      <div id="schedule-title">
        <div class="page-title">
          <h1>SCHEDULE-KOBE</h1>
          <h2>神戸校スケジュール</h2>
        </div>
      </div>
      <div class="container">
      <?php custom_breadcrumb(); ?>
        <div class="row mx-auto my-md-4">
        <?php
          foreach($days as $day):
            $day = new WP_Query($$day);
        ?>
          <div class="day-col mx-auto text-center">
            <h2 class="text-light p-1 mb-3"><?= ucwords(strtolower($days[$i])); $i++; ?></h2>
            <?php
              if ($day->have_posts()): while($day->have_posts()): $day->the_post();
                $instructor_name = get_post_meta($day->post->ID, 'instructor_name', true);
                $class_name = get_post_meta($day->post->ID, 'class_name', true);
                $start_time = get_post_meta($day->post->ID, 'start_time', true);
                $finish_time = get_post_meta($day->post->ID, 'finish_time', true);
            ?>
            <div class="container my-3 border">
              <div class="row">
                <?php if (has_post_thumbnail()): ?><!-- サムネイル画像があれば表示する -->
                <div class="schedule-thumbnail p-0 col-4 col-md-12 mx-auto"><?php the_post_thumbnail(); ?></div><!-- /schedule-thumbnail -->
                <?php else: ?><!-- 画像がなければNo Imageと表示する -->
                <div class="bg-light border p-0 col-4 col-md-12"><span class="d-block schedule-thumbnail">No Image</span></div>
                <?php endif; ?>
                <div class="schedule-contents p-0 col-8 col-md-12 mx-auto">
                  <h3 class="my-2 my-md-1 h6 small font-weight-bold">
                    <?= ($instructor_name!=="")?esc_html($instructor_name):'no name'; ?>
                  </h3>
                  <p class="my-0 mx-3 mx-md-0 p-1 font-weight-bold bg-secondary text-white"><?= ($class_name!=="")?esc_html($class_name):'undefined lesson'; ?></p>
                  <p class="py-2 m-0">
                    <span><?= ($start_time!=="")?esc_html($start_time):'--:--'; ?></span>
                    <span>-</span>
                    <span><?= ($finish_time!=="")?esc_html($finish_time):'--:--'; ?></span>
                  </p>
                </div><!-- /schedule-contents -->
              </div><!-- /row -->
            </div><!-- /container -->
            <?php endwhile; ?>
            <?php else: ?>
              <div class="p-5 p-md-1"><span>レッスンはありません</span></div>

            <?php endif; ?>
          </div>
        <?php endforeach; ?>
        </div><!-- /row -->
      </div><!-- /container -->
    </main><!-- #main -->
  </div><!-- #primary -->
<?php
// get_sidebar();
get_footer();

↑ page-scheduletable_kobe.php に記述したコード
試しにこのフォームから登録してみると、こう。

スケジュールの登録
スケジュールの登録
ちゃんと教室や曜日なども選択できるようになっています。
そしてそれが表示されるページがこう。
スケジュールの表示
スケジュールの表示
サムネイル画像が登録されないと「No Image」と表示されるようにしています。
この方法を使うことによって、WordPress の投稿画面をもっと簡単に、めんどくさくないようにすることができ、もっと自由に思い通りのシステムが作れると思います。