Biz Calendarの祝日データを取得する

クライアントのホームページ制作を請け負うとき、特に指定されない限りワードプレスを使用しています。その中で使用する頻度の高いプラグインにBiz Calendarがあります。このプラグインを使うと休業日、イベント開催日を表示するカレンダーを サイドメニューに簡単に作成できます。しかし、2014年11月Google Calendar API v2のサービス終了に伴い祝日データが取得できなくなり、代替手段を模索していました。

  • 案1:祝日データを自前で作りBiz Calendarから参照する
  • 案2:祝日データを買い(4年分のデータが1,480円で買えます)Biz Calendarから参照する
  • 案3:祝日データを計算するプログラムを探し、Biz Calendarに組み込む

まず、案3の可能性を追究し、ダメそうなら案2という計画をたてました。案1はカレンダーから祝日を拾えばOKなのですが、その作業の単純さに耐えられない(単に忍耐力がないだけ)、かつ、拾い忘れる恐れがあるので没にしました。それで早速案3の下調べに取り掛かったところPHPで祝日を求めるという記事に計算で祝日を割り出す方法が紹介されていました。そのサンプルプログラム(ファイル名:getHoliday.php)は祝日法で制定された2016年開始の山の日(8月11日)もカバーしていたので期待が膨らみます。

問題はBiz Calendarとこのプログラムをどのように連携させるかです。サンプルプログラムの動作を解析して最後部にある以下のコードがヒントになると考えました。
// メイン・プログラム =======================================================
$youbi = array('日', '月', '火', '水', '木', '金', '土', '日');
$year = isset($_GET['year']) ? $_GET['year'] : date('Y');
$msg = '';

if ($year >= 1948 && $year <= 2099) {
	$msg = "<table>\n";
	for ($yyyy = $year; $yyyy < $year + 3; $yyyy++) {
		$cnt = 1;
		$msg .= sprintf("<tr><td class=\"index\" colspan=\"3\">%04d年</td></tr>\n", $yyyy);
		for ($month = 1; $month <= 12; $month++) {
			$day_of_month = getDaysInMonth($yyyy, $month);
			for ($day = 1; $day <= $day_of_month; $day++) {
				$name = getHoliday($yyyy, $month, $day, 'jp');
				$ww = getWeekNumber($yyyy, $month, $day);
				if ($name != FALSE) {
					$msg .= sprintf("<tr><td>%02d</td><td>%02d月%02d日(%s)</td><td>%s</td></tr>\n", $cnt, $month, $day, $youbi[$ww], $name);
					$cnt++;
				}
			}
		}
	}
	$msg .= "</table>\n";
} else if ($year == FALSE) {
} else {
	$msg = 'error > 指定できる西暦年は、1948年から2099年までです。';
}
この部分は指定された年($year)から3年間のすべての祝日を計算しhtml形式で表にしています。これに相当するのはBiz Calendar(VERSION 1.6.0)のメインルーチンであるbiz-calendar.phpのgetHolidays関数であると分かりました。159行目以降Google Calendar APIから祝日データを取り込みフォーマットをBiz Calendar仕様に変換してるのが分かります。
	public function getHolidays( $options ){
		if ( $this->hasCache( $options) ){
			return $options;
		}

		$year = date_i18n('Y');
		//1-3月は前年の祝日を取得する
		$mon = date_i18n('n');
		if ( $mon < 4){
			$year -= 1;
		}

		$url = sprintf(
				'http://www.google.com/calendar/feeds/%s/public/full-noattendees?start-min=%s&start-max=%s&max-results=%d&alt=json' ,
				'outid3el0qkcrsuf89fltf7a4qbacgt9@import.calendar.google.com' , // 'japanese@holiday.calendar.google.com' ,
				$year.'-04-01' ,  // 取得開始日
				($year + 1).'-03-31' ,  // 取得終了日
				50              // 最大取得数
		);

		$results = file_get_contents($url);
		if ( !isset($results) ){
			return $options;
		}
		$results = json_decode($results, true);
		$holidays = array();
		foreach ($results['feed']['entry'] as $val ) {
			$date  = $val['gd$when'][0]['startTime'];
			$title = $val['title']['$t'];
			$holidays[$date] = $title;
		}
		ksort($holidays);

		//キャッシュを更新する
		$options["holiday_cache"] = $holidays;
		$options["holiday_cache_date"] = date_i18n( "Y/m");
		update_option('bizcalendar_options', $options);
		return $options;
	}
この関数のGoogle Calendar APIから祝日データを取り込んでいる部分を先ほどのgetHoliday.phpに置き換え、そのフォーマットをBiz Calendar仕様に変換すればよいわけです。試行錯誤の結果、Biz CalendarのVERSION 1.6.0を以下の手順で変更すれば動作することが分かりました。まず、biz-calendar.phpの冒頭部でgetHoliday.php(念のため冒頭と末尾のhtml出力部分は削除した方がベター)をインクルードします。
include_once ( dirname(__FILE__) . "/admin-ui.php" );
include_once ( dirname(__FILE__) . "/getHoliday.php.php" );
new BizCalendarPlugin();
そして、getHolidays関数を以下の様に書き換えます。後は、getHoliday.phpをbiz-calendar.phpと同じディレクトリに配置すればOKです。
	public function getHolidays( $options ){
		if ( $this->hasCache( $options) ){
			return $options;
		}
		$year = date_i18n('Y');
		//1-3月は前年の祝日を取得する
		$mon = date_i18n('n');
		if ( $mon < 4){
			$year -= 1;
		}

		$holidays = array();

		// メイン・プログラム =======================================================
		$youbi = array('日', '月', '火', '水', '木', '金', '土', '日');
		
		if ($year >= 1948 && $year <= 2099) {
			for ($yyyy = $year; $yyyy < $year + 2; $yyyy++) { // 2年分
				for ($month = 1; $month <= 12; $month++) {
					$day_of_month = getDaysInMonth($yyyy, $month);
					for ($day = 1; $day <= $day_of_month; $day++) {
						$name = getHoliday($yyyy, $month, $day, 'jp');
						$ww = getWeekNumber($yyyy, $month, $day);
						if ($name != FALSE) {
							$date = sprintf("%04d-%02d-%02d", $yyyy, $month, $day);
							$holidays[$date] = $name;
						}
					}
				}
			}
		} else if ($year == FALSE) {
			return $options;
		} else {
			return $options;
		}
		
		ksort($holidays);

		//キャッシュを更新する
		$options["holiday_cache"] = $holidays;
		$options["holiday_cache_date"] = date_i18n( "Y/m");
		update_option('bizcalendar_options', $options);
		return $options;
	}		
今回のカスタマイズを施した実例が当方のクライアントの1つであるアルタオート様のHPのサイドバーに設置されていますので確認いただけます。この方法で気になるのは以下の3点です。
  1. 西暦1948年から2099年までしか対応していない
  2. 春分の日と秋分の日が極稀にズレる
  3. 祝日法が改定されたときに祝日を追加・削除できるか
1はシステムの耐用年数(=陳腐化)が10年スパンということ、世紀末にはもっと大きな問題が起こるであろうことを考えると気になりません。2はそもそも春分の日と秋分の日が前年の2月位に閣議決定されるものですからこの方法以外でも同じなので無視できます(もちろん対応は必要ですが)。3はgetHoliday.phpの構成からすると自身で対応できそうです。祝日の指定の仕方は、固定タイプ(例:元日=1月1日)と移動タイプ(例:成人の日=1月第2月曜日)があります。それぞれのタイプについて以下の様な形式でコード化されているのでその部分をひねってやれば十分いけそうです。
function getFixedHoliday($year, $month, $day, $lang) {
//固定祝日
static $fixed_holiday = array(
//    月  日  開始年 終了年  名称
array( 1,  1, 1949, 9999, '元日',         "New Year's Day"),
array( 1, 15, 1949, 1999, '成人の日',     'Coming of Age Day'),
array( 2, 11, 1967, 9999, '建国記念の日', 'National Foundation Day'),
array( 4, 29, 1949, 1989, '天皇誕生日',   "The Emperor's Birthday"),
array( 4, 29, 1990, 2006, 'みどりの日',   'Greenery Day'),
array( 4, 29, 2007, 9999, '昭和の日',     'Showa Day'),
function getMovableHoliday2($year, $month, $day, $lang) {
//移動祝日(ハッピーマンデー法)
static $movable_holiday = array(
//    月  曜日番号 第N曜日 開始年  終了年  名称
array( 1, 1, 2, 2000, 9999, '成人の日', 'Coming of Age Day'),
array( 7, 1, 3, 2003, 9999, '海の日',   'Marine Day'),
array( 9, 1, 3, 2003, 9999, '敬老の日', 'Respect for the Aged Day'),
array(10, 1, 2, 2000, 9999, '体育の日', 'Health and Sports Day')
);

	$name = FALSE;
	foreach ($movable_holiday as $val) {
		if ($month == $val[0] && $day == getWeeksOfMonth($year, $month, $val[1], $val[2])) {
			if ($year >= $val[3] && $year <= $val[4]) {
				$name = preg_match("/JP/i", $lang) == 1 ? $val[5] : $val[6];
				break;
			}
		}
	}
	return $name;
}

ホームページに掲載するカレンダーであれば当日を起点として前後数ヶ月分の祝日データがあれば事足りるでしょうからこのgetHoliday.phpの出力を数年分配列データ(リテラル表現)に格納し、それをbiz-calendar.phpから参照する方式の方がベターだと思います。


コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

ブログに戻る