WordPressで月送りのカレンダーを実装(祝日対応)

  • Updated: 2023.06.15
  • Published: 2023.06.15
  • 1,103views

概要

月送りが出来て、投稿日にリンクと祝日の表示がされるカレンダーを実装します。

下記のようにAPIにしてHTML書き出しにしています。

https://ilr.jp/api/calendar.php

祝日部分はGoogle Calendar APIを使用します。

事前にGoogleプラットホームでGoogle Calendar APIが使用できるAPIキーを取得する必要があります。

PHP

<?php
require'../wp/wp-load.php';

class MyCalendarClass{

	private string $year;
	private string $month;
	private int $monthN;
	private array $postArray = [];
	private array $MonthArray = [];
	private array $holidayArray = [];
	private int $nextMonth;
	private string|int $nextYear;
	private string $nextLink;
	private string $lastLink;

	public function __construct(){
		foreach ($_GET as $key => $query){
			if($key === 'year'){
				$year = $query;
			}
			if($key === 'month'){
				$month = $query;
			}
		}
		if( isset( $year, $month ) ):
			$this->year = htmlspecialchars($year, ENT_QUOTES, "utf-8");
			$this->month = sprintf('%02d', htmlspecialchars($month, ENT_QUOTES, "utf-8"));
			$this->monthN = (int) htmlspecialchars($month, ENT_QUOTES, "utf-8");
		else:
			$this->year = date('Y');
			$this->month = date('m');
			$this->monthN = (int) date('n');
		endif;

		$this->getMonthPosts();
		$this->getHolidays();
		$this->getLastMonth();
		$this->getThisMonth();
		$this->getNextMonth();
    }

	private function getMonthPosts(): void {
		$args = array(
			'post_type' => array('tech'),
			'numberposts' => -1,
			'post_status' => 'publish',
			'year' => $this->year,
			'monthnum' => $this->monthN,
		);

		$my_query = new WP_Query($args);
		while ($my_query->have_posts()):$my_query->the_post();
			$id = get_the_ID();
			$this->postArray[] = array(
				"year" => get_the_date('Y', $id),
				"month" => get_the_date('n', $id),
				"date" => get_the_date('j', $id),
				'link' => get_the_permalink(),
				'dateStr' => get_the_date('Y-m-d', $id),
			);
		endwhile;

		// 投稿データをリセット
		wp_reset_postdata();
	}

	private function getHolidays(): void {
		define( "GOOGLE_API_KEY", '【APIキー】' );

		if ( false === ( $holidayArray = get_transient( 'google_holiday' ) ) ) {
			// 去年から来年の祝日を取得
			$start_month = mktime(0,0,0,1,1,(int) date('Y') - 1);
			$end_month = mktime(0,0,0,1,0,(int) date('Y') + 2);

			// APIリクエスト先のURL
			$url = sprintf(
				"https://www.googleapis.com/calendar/v3/calendars/%s/events?key=%s&timeMin=%s&timeMax=%s&orderBy=startTime&singleEvents=true",
				'japanese__ja@holiday.calendar.google.com',
				GOOGLE_API_KEY,
				date('Y-m-d', $start_month).'T00:00:00Z',
				date('Y-m-d', $end_month).'T00:00:00Z'
			);

			// curlの設定
			$ch = curl_init();
			curl_setopt($ch, CURLOPT_URL, $url);
			curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
			curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

			// リクエスト処理
			$responce = curl_exec($ch);
			curl_close($ch);

			// JSONを変換
			try {
				$result = json_decode( $responce, true, 512, JSON_THROW_ON_ERROR );
				// 祝日一覧を取得
				$holidays = $result['items'];

				foreach ($holidays as $holiday):
					$holidayArray[] = array(
						'name' => $holiday["summary"],
						'dateStr' => $holiday["start"]["date"],
					);
				endforeach;

				// transient APIに保存
				set_transient( 'google_holiday', $holidayArray, 24 * HOUR_IN_SECONDS );
			} catch ( JsonException $e ) {
			}

		}

		$this->holidayArray = $holidayArray;

	}

	private function getMonthDate($y , $m , $d, $c): array {
		$date = $y . '-'. $m . '-' . sprintf('%02d', $d) . ' 00:00:00';
		$time = strtotime($date);
		$year = date('Y', $time);
		$month = date('n', $time);
		$date = date('j', $time);
		$dateStr = date('Y-m-d', $time);

		$todayDateStr = date('Y-m-d');

		$dateData = array(
			"year" => $year,
			"month" => $month,
			"date" => $date,
			"day" => date('w', $time),
			"dateStr" => $dateStr,
			"current" => $c,
		);
		if($dateStr === $todayDateStr){
			$dateData['today'] = true;
		}else{
			$dateData['today'] = false;
		}
		foreach ($this->postArray as $post){
			if($post['dateStr'] === $dateStr){
				$dateData['link'] = $post['link'];
			}
		}
		$dateData['holiday'] = false;
		$dateData['holidayName'] = '';
		foreach ($this->holidayArray as $post){
			if($post['dateStr'] === $dateStr){
				$dateData['holiday'] = true;
				$dateData['holidayName'] = $post['name'];
			}
		}
		return $dateData;
	}

	private function getLastMonth(): void {
		// 先月
		$lastTime = strtotime($this->year . '-'. $this->month. '-00 00:00:00');
		$Y = date('Y', $lastTime);
		$m = date('m', $lastTime);
		$n = date('n', $lastTime);
		$w = date('w', $lastTime);
		$j = date('j', $lastTime);

		$this->lastLink = '?year=' . $Y . '&month=' . $n;

		if((int) $w !== 6):
			for($i = $j - $w; $i <= $j; $i++){
				$this->MonthArray[] = $this->getMonthDate($this->year,$m,$i,'prev');
			}
		endif;

		$this->nextMonth = $this->monthN + 1;
		$this->nextYear = $this->year;
		if($this->nextMonth > 12):
			$this->nextMonth = 1;
			$this->nextYear = (int) $this->year + 1;
		endif;
	}

	private function getThisMonth(): void {
		// 今月
		$lastDayStr = $this->nextYear . '-'. sprintf('%02d', $this->nextMonth) . '-00 00:00:00';
		$lastDay = date('j', strtotime($lastDayStr));

		for($i = 1; $i <= $lastDay; $i++){
			$this->MonthArray[] = $this->getMonthDate($this->year,$this->month,$i,'current');
		}
	}

	private function getNextMonth(): void {
		// 来月
		$nextTime = strtotime($this->nextYear . '-'. sprintf('%02d', $this->nextMonth) . '-01 00:00:00');
		$Y = date('Y', $nextTime);
		$m = date('m', $nextTime);
		$n = date('n', $nextTime);
		$w = date('w', $nextTime);

		$loop = 1 + (6 - $w);
		$this->nextLink = '?year=' . $Y . '&month=' . $n;
		if((int) $w !== 0):
			for($i = 1; $i <= $loop; $i++){
				$this->MonthArray[] = $this->getMonthDate($this->nextYear,$m,$i,'next');
			}
		endif;
	}

	public function getTitle($format): string {
		$dateStr = strtotime($this->year . '-'. $this->month . '-01 00:00:00');
		return date($format, $dateStr);
	}
	public function getDate(): array {
		return array_chunk($this->MonthArray, 7);
	}
	public function current(): string {
		return '?year=' . date('Y') . '&month=' . date('n');
	}
	public function prev(): string {
		return $this->lastLink;
	}
	public function next(): string {
		return $this->nextLink;
	}
}

$calendar = new MyCalendarClass();

/// カレンダー表示
$dayArray = ['日','月','火','水','木','金','土'];

header("Content-Type: text/html; charset=utf-8");

echo '<div class="myCalendor">';

echo '<div class="header">';
echo '<div class="prev"><a href="/api/calendar.php' . $calendar->prev() . '">先月</a></div>';
echo '<div class="title"><a href="/api/calendar.php' . $calendar->current() . '">'. $calendar->getTitle('Y年n月') .'</a></div>';
echo '<div class="next"><a href="/api/calendar.php' . $calendar->next() . '">来月</a></div>';
echo '</div>';

echo '<table>';
echo '<tr>';
foreach ($dayArray as $key => $it):
	echo '<td data-day="' . $key . '"><span>' . $it . '</span></td>';
endforeach;
echo '</tr>';
foreach ($calendar->getDate() as $item):
	echo '<tr>';
	foreach ($item as $it):
		if($it['today']){
			$class = ' class="today"';
		}else {
			$class = '';
		}
		if($it['holiday']){
			$holiday = ' data-holiday';
		}else {
			$holiday = '';
		}
		echo '<td' . $class . ' data-day="' . $it['day'] . '" data-current="' . $it['current'] . '"' . $holiday . '>';
		if(isset($it['link'])){
			echo '<a href="'. $it['link'] . '">';
			echo $it['date'];
			echo '</a>';
		}else{
			echo '<span>';
			echo $it['date'];
			echo '</span>';
		}
		echo '</td>';
	endforeach;
	echo '</tr>';
endforeach;
echo '</table>';
echo '</div>';

JavaScript

document.addEventListener("DOMContentLoaded", function(){
  async function getCalendar(url){
    function onclick(e){
      getCalendar(e.currentTarget.getAttribute('href'));
      e.preventDefault();
    }
    try{
      await fetch(url)
        .then(res => res.text())
        .then(text => new DOMParser().parseFromString(text, "text/html"))
        .then(doc => {
          let $content = doc.querySelector('.myCalendor');
          let $main = document.querySelector('[data-calendar]');
          $main.innerHTML = '';
          $main.appendChild($content);

          let $prev = $content.querySelector('.prev a');
          let $next = $content.querySelector('.next a');
          let $current = $content.querySelector('.title a');

          $current.addEventListener('click',onclick,false);
          $prev.addEventListener('click',onclick,false);
          $next.addEventListener('click',onclick,false);
        });

    }catch (e) {
      console.log(e);
    }
  }
  if(document.querySelectorAll('[data-calendar]').length > 0){
    getCalendar('/api/calendar.php');
  }
});

HTML

<div data-calendar></div>

関連記事

人気の投稿

最新の投稿

タグ

月別アーカイブ

Contact

WEB制作の依頼など気軽にお問い合わせください。

お問い合わせ