カスタムフィールドの日付でイベントカレンダーを自作<プラグインなし>

つくってみた
つくってみた
この記事は約20分で読めます。

カスタムフィールドの日付に紐づいたカレンダーを作りたい。
WordPressのデフォルトカレンダーでは投稿の日付で表示されちゃって、イメージと違う。。
プラグインなしで、イベントカレンダーが作れるコードがあれば知りたい。

投稿の日付とは関係なく、カスタムフィールドと連携したカレンダーが作れます!
プラグインなし&PHPまるまるコピーでサクッと実装しちゃいましょう!

まずは完成形がこちらです。ドン!

動作を見る→https://lolinowa.com/?ym=202002#calendar

やっていることとしては、
★数日間のイベントにも対応した期間表示。
★同日開催の複数イベントにも対応した件数表示。
★リンク先は選択したその月orその日付のイベントアーカイブ(一覧ページ)へ遷移。
といったところです。

下記サイトで紹介されているコードを大変参考にさせていただきました。

イベント件数やタイトルが少なめなら、こちらで紹介されているように
日付リンク先はタイトル表示にしたり、直接記事ページに遷移してもいいかもしれませんね!

スポンサーリンク

【重要】事前準備は6つ

1.パーマリンク設定を数字ベースにする

アーカイブ用URL作成のため。

2.カテゴリーの用意

スラッグ名はあとで使います。

3.日付のフィールドタイプをテキストで作る

カスタムフィールドはAdvanced Custom Fields(以下ACF)を使いました。
ACFで付けた名前もあとで使います。

4.投稿作成時の日付入力ルールを決める

年月日間は”-“で区切り、数日間イベントは”/”で区切るルールとします。

例)【単発イベントの場合】2020-05-10→あとで ”-” で年月日を分けるため。(PHPコード内☆参照)
  【数日間イベントの場合】2020-03-15/2020-03-23→あとで “/” で前半後半の日付を分けるため。(PHPコード内☆参照)

5.archive.phpをカスタマイズ

archive.phpに下記コードを入れると、URLパラメータからサンプルのようにアーカイブページができます。★部分は自身の設定に合わせて変更してください。

月別アーカイブサンプル→https://lolinowa.com/archives/category/event?list=1079,1101,1050,1090,&calendar=202002
日別アーカイブサンプル→https://lolinowa.com/archives/category/event?list=1079,1101,&calendar=20200201

<?php if (is_category('event')): ?> //ここの条件分岐は臨機応変に変更してください。
//★イベントカテゴリーの表示内容ここから。'event'のところにカテゴリーのスラッグ名を入れる

<?php
		if( $_GET['list'] ){ //月別・日別アーカイブ表示内容
  $args = array(
	'post_type' => 'post',
    'category_name' => 'event', //★カテゴリーのスラッグ名
	'post__in' => explode(",",$_GET['list']), //記事idをGET値から取得
	'order' => 'DESC',
	'meta_key' => 'day', //★日付(ACFで設定した名前'day')をもとに記事の並べ替え
	'orderby' => 'meta_value'
  );
		}else{ //全ベントカテゴリーアーカイブ表示内容
	 $args = array(
	'post_type' => 'post',
    'category_name' => 'event', //★カテゴリーのスラッグ名
	'order' => 'DESC',
	'meta_key' => 'day', //★日付(ACFで設定した名前'day')をもとに記事の並べ替え
	'orderby' => 'meta_value'
  );
		}
  $the_query = new WP_Query($args);
		?>

//ここのhタグは臨機応変に変更してください。
<h2><?php if ($_GET['calendar']){ //年月日をGET値から取得してリストタイトル表示
  $y = substr($_GET['calendar'],0,4);
  $m = substr($_GET['calendar'],4,2);
  $d = substr($_GET['calendar'],6,2);
  $weekList = array("日", "月", "火", "水", "木", "金", "土");
  $datetime = new DateTime($_GET['calendar']); //曜日出力
  $w = (int)$datetime->format('w');
	 if (strlen($calendar) < 7) {
	   $date_title = $y . '年' . $m . '月';
	 }else{
		 $date_title = $y . '年' . $m . '月' . $d . '日' . '('.$weekList[$w].')';
	 }
	echo $date_title.'の'; } ?>イベント一覧</h2>

<?php $url = $_SERVER['REQUEST_URI']; //イベントがない場合表示内容
	 if(strstr($url,'list=&calendar')):
	 echo '<p>イベントはまだありません。</p>';
	 elseif($the_query->have_posts()): //イベントがある場合の表示内容。ループ開始
  while ($the_query->have_posts()): $the_query->the_post(); ?>
<!--表示する内容ここから-->

             //このエリアに表示したい内容のコードを書く

<!--表示する内容ここまで-->
	<?php endwhile; ?> //ループ終了
 <?php wp_reset_postdata(); ?>
    <?php endif; ?>

<?php endif; ?>//★イベントカテゴリーの表示内容ここまで

6.calendar.phpを用意

空のままでOK。

calendar.phpを作る目的は、見やすさのためです。
カレンダーを設置したいページに直接書いてもいいけどゴチャゴチャして見づらくなるので、calendar.phpの中にカレンダーを組み立てていきます。

PHPコード

手順1:↑で作ったcalendar.phpにコードをコピペ!

★部分は自身の設定に合わせて適宜変更してください。

<?php 

date_default_timezone_set('Asia/Tokyo');

//前月と次月を表示する際は、GETで値を受け取る
if (isset($_GET['ym'])) {
	$page_ym = $_GET['ym'];

}else{
	$page_ym = date('Ym');
}


//形式チェック
$timestamp = strtotime($page_ym . "01"); // yyyymmddの書式にする


if ($timestamp === false) {
	$timestamp = time();
}


//今日の日付
$today = date('Ymd',time());
$thismonth = date('n', $timestamp);
$thisyear = date('Y', $timestamp);


//HTML表示用の日付
$html_title = date('Y年 n月',$timestamp);

//前月と次月を取得  mktime(hour, minute, second, month, day, year)
$prev = date('Ym', mktime(0, 0, 0, date('m', $timestamp)-1, 1 , date("Y", $timestamp)));
$next = date('Ym', mktime(0, 0, 0, date('m', $timestamp)+1, 1, date("Y", $timestamp)));

//対象月は何日あるか
$day_count = date('t', $timestamp);

//1日は何曜日か 0:日 1:月 .... 6:土
$youbi = date('w', mktime(0, 0, 0,date('m', $timestamp), 1, date("Y", $timestamp)));

//曜日を月曜始まりに変更 
$youbi = ($youbi == 0) ? 6 : $youbi - 1;

function mycalendar_fillevents($databuf, $startday, $endday, $countid, $url) {

	$curday = $startday;
	for ($i = 0; $i < (int)$endday - (int)$startday + 1; $i++) {
		$curday = $startday + $i; // カレンダーの日付
			// 同日に複数イベントが入った場合のID
	if (is_array($databuf[$curday])) {
        $countid = count($databuf[$curday]);
		
	}else{
		$countid = 0;
	}
		$databuf[$curday][$countid]["url"] = $url;
	}
	return $databuf;
}

//
// extract event list
//
$args = array(
	'post_type'  => 'post',
	'category_name' => 'event', //★カテゴリーのスラッグ名'event'
	'meta_key'   => 'day', //★ACFで設定した名前'day'
	'orderby'    => 'meta_value',
	'order'      => 'ASC',
	'posts_per_page' => -1
	);

// The Query
$the_query = new WP_Query( $args );

// this buffer will be 3dim array
$databuf = array();

// The Loop
if ( $the_query->have_posts() ) {
	
	while ( $the_query->have_posts() ) {
		$the_query->the_post();
		$url = get_the_ID(); //あとでurlに記事idぶっこみアーカイブページへリンクさせるため

		global $post, $id;

		// ★ACFで設定した名前'day'を取得
		$day_meta = (post_custom('day'));
		// ☆'/'で数日間イベントを分割。前半が日付1、後半が日付2になる。
		$datearray = explode('/', $day_meta);
		
		$startymd = explode('-', $datearray[0]);
		$startyear = $startymd[0];
		$startmonth = $startymd[1];
		$startday = $startymd[2];
		$theday = new DateTime();
		$theday->setDate((int)$startyear, (int)$startmonth, (int)$startday);
		$startym = $theday->format('Ym');
		
		// $startymが現在の表示年月より大きい場合は、残りのイベントも全て同条件で
		// 現在のカレンダーの表示範囲外なのでloopを出る
		if ($startym > $page_ym) {
			break;
		}
			
		if (count($datearray) == 1 && $startym == $page_ym) {
			// 1日のみのイベントなので、現在のカレンダーの年月に合致した場合のみデータベースにFILLする
			// single day event. yyyy/mm/dd
			// year and month matched. fill the event to the buffer.
			$databuf = mycalendar_fillevents($databuf, $startday, $startday, $countid, $url);
			
		} else if (count($datearray) > 1) {
			// 複数日イベント
			// multiple days event.
			// date format is yyyy/mm/dd-dd or yyyy/mm/dd-mm/dd or yyyy/mm/dd-yyyy/mm/dd
			// $dataarray[0] = yyyy/mm/dd
			// $dataarray[1] could be dd, mm/dd, yyyy/mm/dd
			//☆'-'で年月日を分割。
			$endymd = explode('-', $datearray[1]);
			$endymdcounts = count($endymd);
			
			// try simple case first.
			if ($endymdcounts == 1) {
				// イベント開始日と終了日が同じ月。現在の表示カレンダーの年月のものだけFILLする
				// the event will be held within a month.
				// date format is yyyy/mm/dd-dd.
				if ($page_ym != $startym) {
					// month doesn't match through event period. go to next post.
					continue;
				}
				$endday = $endymd[0];
				$databuf = mycalendar_fillevents($databuf, $startday, $endday, $countid, $url);
				
			} else {
				// イベント終了日が開始日と同じ年月にない場合は、イベント期間中のうち表示中のカレンダーの年月のみFILLする
				// the event will be held through at least two different months.
				// date format is yyyy/mm/dd-mm/dd or yyyy/mm/dd-yyyy/mm/dd.
				$endyear = $startyear;
				$endmonth = $startmonth;
				$endday = $startday;
				if ($endymdcounts == 2) {
					$endmonth = $endymd[0];
					$endday = $endymd[1];
				} else if ($endymdcounts == 3) {
					$endyear = $endymd[0];
					$endmonth = $endymd[1];
					$endday = $endymd[2];	
				}
								
				$theday->setDate((int)$endyear, (int)$endmonth, (int)$endday);
				$endym =  $theday->format('Ym');
				
				if ($page_ym > $endym) {
					// イベント終了日が現在の表示年月より前の場合はこのイベントをスキップ(妥協)
					// current calendar is out of bound of this event. go to next post.
					continue;
				} 
				
				$curym = $startym;
				$curyear = $startyear;
				$curmonth = $startmonth;
				// 開始日付は1日かイベント開始日のどちらか
				$curday = ($page_ym == $startym) ? $startday : 1;
				
				// 開始年月から終了年月までループ
				while ($curym <= $page_ym) {
					
					if ($page_ym == $curym) {
						// OK, fill calendar for this month.
						// update start day and end day.
						$startday = $curday;
						$last_day = $day_count;
						// 開始日付は月の最後の日かイベント終了日のどちらか
						$endday = ($curym == $endym) ? $endday : $last_day;
						$databuf = mycalendar_fillevents($databuf, $startday, $endday, $countid, $url);
					} 
					
					//次月を取得
					if ($curmonth == 12) {
						//次の月は翌年1月
						$curyear += 1;
						$curmonth = 1;
					} else {
						$curmonth += 1;
					}
					$theday->setDate((int)$curyear, (int)$curmonth, (int)$curday);
					$curym = $theday->format('Ym');
				}
			}
		}
	}
}

/* Restore original Post Data */
wp_reset_postdata();

//カレンダー作成準備
$weeks = array();
$week = '';
$lists = array();
$list = '';

//空白を追加
//例) 1日が水曜日だった場合、カレンダーの月曜日から火曜日に空白を入れる
$week .= str_repeat('<td></td>', $youbi);

//カレンダーへの出力
for ($day=1; $day <= $day_count; $day++, $youbi++){
	
	if (array_key_exists($day, $databuf)) {
		$week .= '<td>' . $day . '<br><span class="marker"><a href=/archives/category/event?list='; //★アーカイブ用URL。'event'のところにカテゴリーのスラッグ名を入れる
		$total_event = count($databuf[$day]);
		for ($i = 0; $i < $total_event; $i++) { 
			$list = $databuf[$day][$i]['url'] . ','; //日別アーカイブ用
			
			$lists[] = $list; //月別アーカイブ用
	        $arr_list = array_unique($lists, SORT_REGULAR);
			$event_list = implode('',$arr_list);

			$week .= $list;
		}   $week .= '&calendar='. $page_ym . str_pad($day, 2, '0', STR_PAD_LEFT) . '>' . $total_event . '</span></a>'; //イベント件数表示
		
	} else {
		$week .= '<td>'. $day ;
	}
	$week .= '</td>';

	//曜日が日曜日、または全ての日付のtdの作成が終わったら
	if($youbi % 7 == 6 OR $day == $day_count){

		//全ての日付のtdの作成が終わったら、残りに空白を追加
		if($day == $day_count){
			$week .= str_repeat('<td></td>', 6 - ($youbi % 7));
		}

		//1週間分のtdをまとめた$weekを$weeks配列に入れる。
		$weeks[] = '<tr>'.$week.'</tr>';
		
		//新しい週を作成するために$weekを空にする。
		$week = '';

	}

}

?>
//★見出しhタグは臨機応変に変更して
<div class="tablecalendar">
	<h4><a href="?ym=<?php echo $prev;?>#calendar" class="prev">≪</a>&nbsp;&nbsp;<a href="/archives/category/event?list=<?php echo $event_list ;?>&calendar=<?php echo $page_ym ;?>"><?php echo $html_title;?></a>&nbsp;&nbsp;<a href="?ym=<?php echo $next;?>#calendar" class="next">≫</a></h4>
		<table id="wp-calendar">
			<thead>
			<tr>
				<th>月</th>
				<th>火</th>
				<th>水</th>
				<th>木</th>
				<th>金</th>
				<th>土</th>
				<th>日</th>
			</tr>
			</thead>
			<tbody>
	 	<?php
		 	//カレンダー表示
		 	foreach ($weeks as $week){
				echo $week;
			}
		?>
			</tbody>
		</table>
	</div>

手順2:出来上がったcalendar.phpを表示したいページに載せるだけ!

ちなみに私は、フォルダに整理したcalendar.phpをindex.phpに
<?php get_template_part(‘~~~’); ?>を使って、下記画像のように表示しています。

CSSコードもどうぞ

PHPと同じようにhタグは場合によって変更してください。

/*月別アーカイブリンク*/
.tablecalendar h4{
	text-align:center;
	font-size:1.2em;
	color:white;
}

.tablecalendar h4 a{
	color:white;
}

.tablecalendar h4 a:hover{
	opacity:0.5;
}

/*カレンダー枠*/
.tablecalendar{
	background-color:#cc9cd6;
	border-radius:15px;
}

/*カレンダー中身*/
#wp-calendar td, #wp-calendar th{
text-align:center;
}

#wp-calendar th{
	color:#cc9cd6;
}

#wp-calendar small{
	font-size:80%;
}

#wp-calendar{
	border:solid 5px #cc9cd6;
}

#wp-calendar tr, #wp-calendar td, #wp-calendar th{
border:solid 3px #cc9cd6;
}

#wp-calendar{
	background-color:white;
	border-color:#cc9cd6;
	width:100% !important;
}

#wp-calendar td{
	height:4em;
}

/*日別アーカイブリンク*/
.marker{
    font-size:1.2rem;
	background: linear-gradient(transparent 50%, pink 50%);
}

以上になります!

なよいちゃん
なよいちゃん

ちょっと色々組み合わせてざっと紹介したので、お腹いっぱいですね。
追々内容を分割する予定です。。

この記事が気に入ったら、サポートをしてみませんか?
\ ワンコインからのAmazonギフト /

この記事への質問・コメントはこちら

タイトルとURLをコピーしました