概要
月送りが出来て、投稿日にリンクと祝日の表示がされるカレンダーを実装します。
下記のように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>