Page No.2

function ret_daynum()

そして、カレンダー表示の心臓となる関数へと。
と、ちょっとそのまえに、補助的な関数を一つ。その月の1日の曜日から、その月の指定した曜日の日にちを配列にて返す関数を。

<?php
	// ↓class続き

	// その月の1日の曜日から指定した曜日のその月においての日にちを配列にして返す関数
	// $wdaynum 1:日曜、2:月、3:火、4:水、5:木、6:金、7:土 求める日にちの曜日を指定
	// $fdwd : その月の1日の曜日 0:日1:月2:火3:水4:木5:金6:土
	// $dnum : その月の日数
	public function ret_daynum ( $wdaynum, $fdwd, $dnum  ) {

		$tmpnum = 0;
		$daynumary = array();
		$limitnum = $dnum - 6;

		if ( $wdaynum ) {

			$firstdaynum = ( ( int ) $wdaynum - $fdwd + 7 ) % 7;

			// 1日が月曜の場合(1 === $tmpwday['wday'])に日曜の1が指定してある場合、日曜の初日の日にちが0になってしまうことを避ける。
			$i = 0 === $firstdaynum ? 1 : 0;
			while ( $tmpnum < $limitnum ) {
				$tmpnum = $firstdaynum + 7 * $i;
				$daynumary[] = $tmpnum;
				++$i;
			};
		}
		return $daynumary;
	}
	// ↓class続く
?>
PHP
CopyExpand

キャッシュファイルの読み書きには、WordPress で用意されている WP_Filesystem を使います。php の関数、file()、とか file_put_contents() を使った方がよほど簡単には書けるのですが、それは WordPress で非推奨ということであるし、サーバーのいろいろな環境に対応する努力をしてくれるそうなので、その点において使用するメリットはあるのかもしれない。7行目から13行目あたりがその準備。

function holiday_class_post_calendar()

<?php
    // ↓class続き

	function holiday_class_post_calendar(){
		global $wpdb, $wp_query, $wp_rewrite;

		require_once( ABSPATH . 'wp-admin/includes/file.php' );

		$en_wp_file = false;
		if ( WP_Filesystem() ) {
			global $wp_filesystem;
			$en_wp_file = true;
		}

		$prm = $this->ret_option;
		$args = func_get_args();

        // テンプレートで関数に直接指定された引数を適用する
		if ( func_num_args() > 0 ) {
			$prm = array_merge( $prm, $args[0] );

			// テンプレートで関数に直接指定された引数にpost_typeがない場合に限り、
			// カスタム投稿のページの時に、グローバル変数から取得して適用            
			if ( ! isset( $args[0]['postype'] ) ) {
				$q_vars = $wp_query->query_vars;
				if ( isset( $q_vars['post_type'] ) and  $q_vars['post_type'] ) {
					$prm['postype'] = $q_vars['post_type'];
				}
			}
		}

		$cache_file = '';
        // オプション値を数値化して有効化。0b11111 -> 31 にあまり意味はない、とりあえず31までは有効な数字とする
        // 0 の場合キャシュは無効
		$en_cache = ( ( int ) $prm['en_cache'] & 0b11111 );

		if ( $en_cache ) {
            // キャッシュファイルを使用する設定の時はオプションで設定された数値を付加してファイル名を設定
			$cache_file = plugin_dir_path( __FILE__ ) . '/hcpcldr_cache_' . ( string ) $en_cache . '.php';
		}

		// 管理画面において server side render における処理では is_admin は決まって false を返すため使えない
        // そのため代りに下記のように REST_REQUEST を使う
		if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
			if ( $en_cache ) {
				if ( $en_wp_file ) {
					// 管理画面においてカレンダーを生成する場合は、block によるものであるから、その場合はキャッシュファイルを削除する。
					// これは widgets block に対応してのこと
					if ( $wp_filesystem->exists( $cache_file ) ) {
							$wp_filesystem->delete( $cache_file, false, 'f' );
					}
				}
			}
			$en_cache = 0;
		}

		++$this->call_count;

		$target_Ym = '';
		$tmp_month_no = '';

        // パーマリンク設定が基本ではなく、末尾のスラッシュが無い場合の接続文字のスラッシュを設定するための変数
		$trailslash = '';

        // url 末尾に付けるスラッシュ
		$slashstr = '/';

        // パーマリンク設定を取得
		$daylink = $wp_rewrite->get_day_permastruct();

		$timezone = 'Asia/Tokyo';

        // 現在日時を取得、DateTime クラスを使用する。基本となる現在日時は後に変更することはないので DateTimeImmutableを使う
		$nowdate = new  DateTimeImmutable( '', new DateTimeZone( $timezone ) );
		$basestamp = $nowdate->getTimestamp();

		$elem = array();

		//表示(初期化時は現在)する年月
		$target_Ym = $nowdate->format( 'Ym' );// eq. 202201
		// 現在の年月
		$elem['cmonth'] = $target_Ym;

		// m=で日付テンプレートに日付情報を送信している場合
		if ( is_date() ) {
			if ( $wp_query->get( 'm' ) ) {

				// 日付関係のテンプレートを開く時に付くurlのオプション:m=の値、強制的に年月を指定する時使用
				$tmp_month_no = $wp_query->get( 'm' );

				// 日付まで付いている場合は年月だけにそろえる
				$tmp_month_no = substr( $tmp_month_no, 0, 6 );

			// 数字ベース等デフォルトのm=ではなく、date/2014/12/04/page/2などで日付情報を送信している場合
			} elseif ( $wp_query->get( 'monthnum' ) ) {
				$tmp_month_no = ( string ) $wp_query->get( 'year' ) . sprintf( '%02d', $wp_query->get( 'monthnum' ) );
			}

			if ( $tmp_month_no ) {
                // 年月の文字列が有効な数値であるかチェック
				$tmpym = array( substr( $tmp_month_no, 0, 4 ), substr( $tmp_month_no, 4 ) );

				if ( checkdate( ( int ) $tmpym[1], 1, ( int ) $tmpym[0] ) ) {

					$target_Ym = $tmp_month_no;
					$curfull = $tmpym[0] . '/' . $tmpym[1] . '/01';
					$curnum = $tmpym[0] . $tmpym[1] . '01';
				}
			}
		} else {
			// 表示する月(初期化時は現在)の1日、曜日を得るのに必要
			$curfull = $nowdate->format( 'Y/m' ) . '/01';
			$curnum = $target_Ym . '01';
		}

		// $tarstampは実際に表示する月のタイムスタンプ
		$tardate = new  DateTimeImmutable( $curfull, new DateTimeZone( $timezone ) );
		$tarstamp = $tardate->getTimestamp();

	// ↓function holiday_class_post_calendar()続く
	// ↓class続く
?>
PHP
CopyExpand

パーマリンクの設定はグローバル変数の $wp_rewrite から取得しています。
$wp_rewrite->get_day_permastruct() で、たとえば /%year%/%monthnum%/%day%/ のような感じで得られます。基本の場合は空が返ります。
もう一つ、$wp_rewrite->use_trailing_slashes では、そのパーマリンク設定の場合、末尾にスラッシュ ‘/’ が付くか否かが判別できます。

キャッシュファイルの読み込み処理から、SQL による投稿データの所得処理まで。

<?php
	// ↓class続き
	// ↓holiday_class_post_calendar()続き

		// 本日の日にち
		$elem['today'] = $nowdate->format( 'd' );

		// 日付アーカイブが呼ばれているかの判断
		if ( $target_Ym !== $elem['cmonth'] ) {
			$now_day = '';
			$todayid = 0;
		} else {
			$now_day = $elem['today'];
			$todayid = ( int ) $elem['today'];
		}

		if ( '0' === $prm['en_grid'] ) {
			$torg = 'table';
		} else {
			$torg = 'grid';
		}

		if ( '1' === $prm['acvoptorlist'] ) {
			$arcvdrpdwnscpt = $this->footer_script();
		} else {
			$arcvdrpdwnscpt = '';
		}

        // ↓ここからcache file 読み込み処理
        // 日付と各表示設定からキャッシュファイルとして保存するカレンダーデータの特性となる文字列を作成
		// この文字列が等しい場合は、保存されたデータを使用する
		$info_calendar = $target_Ym . $now_day . '_l' . $prm['lang'] . 'w' . $prm['wf'] . 'm' . $prm['monthly'] . '_' . $torg . '_' . $prm['postype'] . '_o' . $prm['acvoptorlist'] . 'd' . $prm['daypostlink'] . '_';

		if ( $en_cache ) {
			if ( $en_wp_file ) {
				if ( $wp_filesystem->exists( $cache_file ) ) {

					$cache = explode( chr(1), $wp_filesystem->get_contents( $cache_file ) );

					if ( $info_calendar === trim( $cache[0] ) ) {
						$ret_cont = $cache[1];

                        // ほとんど無い事のように思えるが、仮に同一ページ内に複数のカレンダーが設置されている場合に、要素のidを固有のものとする処理
						if ( $this->call_count > 1 ) {
							$str_callcount = ( string ) $this->call_count;
							$chilbis = '"chlbis-' . $str_callcount . '-';
							$shwchl = '"shwchl-' . $str_callcount . '-';
							$calendarid = 'id="wp-calendar-' . $str_callcount . '"';
							$ret_cont = str_replace( array( '"chlbis-', '"shwchl-', 'id="wp-calendar"' ), array( $chilbis, $shwchl, $calendarid ), $ret_cont );
						}
						
						$ret_cont .= $arcvdrpdwnscpt . '<p style="font-size:0.8em;color:#E1E1A1;padding:0;margin:0;text-align:right;"><span id="cachemark">*</span></p>' . "\n";
						return $ret_cont;
					}	
				}	
			}
		}
		// ↑ここまでcache file 処理

		// パーマリンクが基本ではなくカスタム設定の場合
		if ( ! empty($daylink) ) {

			// パーマリンク設定によるurlに表示される年月の形式
			$dateform = 'Y/m';

			if ( ! $wp_rewrite->use_trailing_slashes ) {
				// パーマリンク設定が基本ではなく、末尾のスラッシュが無い場合、接続文字のスラッシュを設定
				$trailslash = '/';
				// ゆえに末尾のスラッシュは必要なし
				$slashstr = '';
			}
			// 基本となるリンクを置換するための年月表示
			$tmonthform = substr( $target_Ym, 0, 4 ) . '/' . substr( $target_Ym, 4 );
		} else {

			// パーマリンク設定によるurlに表示される年月の形式
			$dateform = 'Ym';
			$slashstr = '';

			$tmonthform = $target_Ym;
		}

		// 表示する年
		$tyear = substr( $target_Ym, 0, 4 );

		// 表示する月
		$tmonth = substr( $target_Ym, 4 );

		// 表示する月の前月
        // とりあえず表示月でDateTime オブジェクトを取得し、後で modify するためにImmutableではない
        // 次月でも必要なため clone で複製を作っておく
		$lastmonth = new  DateTime( $curfull, new DateTimeZone( $timezone ) );
		$nextmonth = clone $lastmonth;
		$lastmonth->modify( 'first day of last months' );
		$elem['pmonth'] = $lastmonth->format( $dateform );

		// 表示する月の次月
		if ( $target_Ym === $elem['cmonth'] ) {

			// 表示する月が現在の月ならば翌月へのリンクは無。
			$elem['nmonth'] = '';
		} else {

			// 表示する月の翌月
			$nextmonth->modify( 'first day of next months' );
			$elem['nmonth'] = $nextmonth->format( $dateform );	
		}

		// 表示する月の末日
		$elem['lddate'] = ( int ) $tardate->format( 't' );

		// 表示する月の1日の曜日 0:日, 1:月, 2:火, 3:水, 4:木, 5:金, 6:土
		$elem['fdwd'] = ( int ) $tardate->format( 'w' );

        // その日にちをkeyとして、休日指定のあるクラス名を登録する配列
        // 1からその月の末日の数字までをkeyとしたそれぞれ空の値の配列を作る
		$dateary = array_fill( 1,  $elem['lddate'], '' );

$sql=<<<HERE
SELECT ID,post_date,post_title FROM $wpdb->posts
WHERE post_type = %s
AND post_status = 'publish'
AND DATE_FORMAT(post_date, '%%Y%%m' ) =%s
ORDER BY post_date ASC
HERE;

		// SQLにてその年月に公開された投稿のデータ( ID,post_date,post_title )を取得
		$months = $wpdb->get_results( $wpdb->prepare( $sql, $prm['postype'], $target_Ym ) ); // $target_Ym →例:201409

		$ispost = array_fill( 0,  $elem['lddate'] + 1, array() );

		foreach ( $months as $val ) {

            // その月の投稿があった日付をkeyに、投稿ID、タイトルを配列にしていれる
			$tmpdate = ( int ) substr( $val->post_date, 8, 2 );
			$ispost[ $tmpdate ][] = array( $val->ID, $val->post_title );
		}
        // データが空の要素(日付)を配列から削除する
		$ispost = array_filter( $ispost );

    // ↓function holiday_class_post_calendar()続く
	// ↓class続く
?>
PHP
CopyExpand

この下で出てくる、休祭日のデータに関しては、なるベル文字数を少なくしようとして、数字をアルファベットで置き換えるということをやっています。そのほうが沢山のデータを持っていられると。
その変換するための配列が $alp_num です。たとえば 2016/08/11 であれば不必要な部分を取り除いて( 年の20と/ )160811 とし、年月日それぞれ二けたの数字を $alp_num 配列を使ってアルファベットで置き換え、この場合なら phk となります。

あと、オプションで設定されている各独自休日のデータ処理において、v7.0 ではその手法を刷新しています。指定されている日付データの桁数に幅があるために、いままではそれを if で判別させていたのを改めています。問題となるのは3桁と1桁の場合なので、それぞれあらかじめ4桁と2桁に揃えておく。そして年月日はフルで8桁なので、指定された日付部分をその8桁から置き換えるという手法です。断言はできないけれど、この手法のほうが速いと思う。

<?php
	// ↓class続き
	// ↓function holiday_class_post_calendar()続き

    // アルファベットと数字を変換するための配列
		$alp_num = array( 'a'=>'01','b'=>'02','c'=>'03','d'=>'04','e'=>'05','f'=>'06','g'=>'07','h'=>'08','i'=>'09','j'=>'10','k'=>'11','l'=>'12','m'=>'13','n'=>'14','o'=>'15','p'=>'16','q'=>'17','r'=>'18','s'=>'19','t'=>'20','u'=>'21','v'=>'22','w'=>'23','x'=>'24','y'=>'25','z'=>'29','!'=>'30' );

		$holidays = array();

		if ( '' === $prm['myholidays'] ) {
			//↓2013~2025までの休日データ、ちなみに最後のykxは251124(2025/11/24のこと)を表す
			$holidays_data = 'maa,man,mbk,mct,mdz,mec,med,mef,mgo,mip,miw,mjn,mkd,mkw,mlw,naa,nam,nbk,ncu,ndz,nec,nee,nef,ngu,nio,niw,njm,nkc,nkx,nlw,oaa,oal,obk,ocu,odz,oed,oee,oef,ogt,oiu,oiv,oiw,ojl,okc,okw,olw,paa,pak,pbk,pcu,pdz,pec,ped,pee,pgr,phk,pis,piv,pjj,pkc,pkw,plw,qab,qai,qbk,qct,qdz,qec,qed,qee,qgq,qhk,qir,qiw,qji,qkc,qkw,qlw,raa,rah,rbl,rcu,rd!,rec,red,ree,rgp,rhk,riq,rix,rjh,rkc,rkw,rlx,saa,san,sbk,scu,sdz,sd!,sea,seb,sec,sed,sef,sgo,shl,sip,siw,sjn,sjv,skd,skw,taa,tam,tbk,tbx,tct,tdz,ted,tee,tef,tgw,tgx,thj,tiu,tiv,tkc,tkw,uaa,uak,ubk,ubw,uct,udz,uec,ued,uee,ugv,ugw,uhi,uit,uiw,ukc,ukw,vaa,vaj,vbk,vbw,vcu,vdz,vec,ved,vee,vgr,vhk,vis,viw,vjj,vkc,vkw,wab,wai,wbk,wbw,wcu,wdz,wec,wed,wee,wgq,whk,wir,wiw,wji,wkc,wkw,xaa,xah,xbl,xbw,xct,xdz,xec,xed,xef,xgo,xhl,xip,xiw,xjn,xkd,xkw,yaa,yam,ybk,ybx,yct,ydz,yec,yee,yef,ygu,yhk,yio,yiw,yjm,ykc,ykx';
			$holidays = explode( ',', $holidays_data );

            // 各休日データをひとつの配列 $holiday[] にまとめていく
            // アルファベット⇔数字変換用配列のキーと値をひっくり返した配列を作る
			$alp_num_flip = array_flip( $alp_num );

            // カレンダーを表示する年月をアルファベットに変換し、holidaysデータの年月を示す二文字とそれぞれ照合 
		    // 合致したら日を示すアルファベットを数字に変換し、$dateary配列のその日の番号にフラグを設定する
			$sameflg = 0;
			if ( $target_Ym ) {
				$alp_year = $alp_num_flip[ substr( $target_Ym, 2, 2 ) ];
				$alp_month = $alp_num_flip[ substr( $target_Ym, 4, 2 ) ];

				foreach ( $holidays as $val ) {
					if ( $alp_year === $val[0] ) {
						if ( $alp_month === $val[1] ) {
							$tmpnum = ( int ) $alp_num[ $val[2] ];

							if ( isset ( $dateary[ $tmpnum ] ) ) {

								$dateary[ $tmpnum ] = 'nitiyou';
							}
							$sameflg = 1;	
						}
					} else {
						if ( 1 === $sameflg ) {
							break;
						}
					}
				}
			}

			$alp_num = null;
			$holidays_data = null;

		} else {
            // オプションで独自の祝日データが設定されている場合
            // 日付指定は1ケタ、2ケタ、3ケタ、4ケタ、6ケタ限定。ex:3,101,1224,200607
			$holidays = explode( ',', $prm['myholidays'] );
			foreach ( $holidays as $val ) {

				if ( ( int ) $val > 0 ) {
					$tmpnum = 0;

                    // v7.0 においてより高速化を図って刷新
                    // 日付指定の桁数に幅があるため、以前はその桁数を if で振り分けていたのを廃止
                    // 3桁以下で日付を指定してある場合、3桁の場合は4桁に、1桁の場合は2桁にそろえておく
                    // 年月日フルで8桁なので、指定日付の桁分だけ8桁から置き換える
					if ( isset ( $val[2] ) ) {
						$tmpval = sprintf( '%04d', $val );
					} else {// 2ケタないし1ケタの場合
						$tmpval = sprintf( '%02d', $val );
					}
					$strlenval = strlen( $tmpval );

					$fulldate = substr( $curnum, 0, ( 8 - $strlenval ) ) . $tmpval;
					$tmpnum = ( int ) substr( $fulldate, 6 );

					if ( $fulldate ) {
						if ( $target_Ym === substr ( $fulldate, 0, 6 ) ) {
							$tmpnum = ( int ) substr( $fulldate, 6, 2 );
							if ( isset( $dateary[ $tmpnum ] ) ) {
								$dateary[ $tmpnum ] = 'nitiyou';
							}
						}
					}
				}
			}
		}

		// 設定されている祝祭日リストに追加、または無視する日付の処理。無視する日付には語尾に'-'を付加する。
		// 3,105,0322-,1108-,20200606
		if ( $prm['adddeldays'] ) {
			$adddel = array();
			if ( is_array( $prm['adddeldays'] ) ) {
				$adddel = $prm['adddeldays'];
			} else {
				$adddel = explode( ',', $prm['adddeldays'] );
			}

			if ( $adddel ) {
				foreach ( $adddel as $val ) {
					$negflg = false;

					if ( '-' === $val[-1] ) {
						$strlenval = strlen( $val );
						$negflg = true;
						$tmpval = substr ( $val, 0, ( $strlenval - 1 ) );
					} else {
						$tmpval = $val;
					}

					if ( isset ( $tmpval[2] ) ) {
						$tmpval = sprintf( '%04d', $tmpval );
					} else {// 2ケタないし1ケタの場合
						$tmpval = sprintf( '%02d', $tmpval );
					}

					$strlenval = strlen( $tmpval );

					$fulldate = substr( $curnum, 0, ( 8 - $strlenval ) ) . $tmpval;

					if ( $fulldate ) {
						if ( $target_Ym === substr ( $fulldate, 0, 6 ) ) {
							$tmpnum = ( int ) substr( $fulldate, 6, 2 );
							if ( isset( $dateary[ $tmpnum ] ) ) {
								if ( $negflg ) {
									if ( $dateary[ $tmpnum ] ) {
										$dateary[ $tmpnum ] = '';
									}
								} else {
									$dateary[ $tmpnum ] = 'nitiyou';
								}
							}
						}
					}
				}
			}
		}

		// 表示月の日曜日の日にちを求める
		$sunnum = $this->ret_daynum( 1, $elem['fdwd'], $elem['lddate'] );
		foreach ( $sunnum as $val ) {
			$dateary[ $val ] = 'nitiyou';
		}

		// 表示月の土曜日の日にちを求める
		$satnum = $this->ret_daynum( 7, $elem['fdwd'], $elem['lddate'] );
		foreach ( $satnum as $val ) {
			if ( isset ( $dateary[ $val ] ) ) {
				$dateary[ $val ] .= ' doyou';
			}
		}
		
        // 独自休日を曜日で指定されている場合の処理、1:日曜~7:土曜
        if ( $prm['closewd'] ) {
            if ( is_array( $prm['closewd'] ) ) {
				$tmpwd = $prm['closewd'];
			} else {
				$tmpwd = explode( ',', $prm['closewd'] );
			}
			// 指定された各曜日のその月の初めの日にちを、その月の1日の曜日から割り出し、その月の指定されたすべての曜日の日にちに対してクラスを指定する
			foreach( $tmpwd as $val ) {
				$wdnum = $this->ret_daynum( $val, $elem['fdwd'], $elem['lddate'] );
				foreach ( $wdnum as $num ) {
					$dateary[ $num ] .= ' closewd';
				}
			}
		}
	
		// 指定された独自休日。配列でなければ配列にする。毎月同じ休日等の場合は日にちで指定可。
		// 例:array('3','10','202','0928','20140911','20140919')
		$closel = array();
		if ( $prm['closel'] ) {
			if ( is_array( $prm['closel'] ) ) {
				$closel = $prm['closel'];
			} else {
				$closel = explode( ',', $prm['closel'] );
			}

			if ( $closel ) {
				foreach ( $closel as $val ) {
					if ( $val ) {
						if ( isset ( $val[2] ) ) {
							$tmpval = sprintf( '%04d', $val );
						} else {// 2ケタないし1ケタの場合
							$tmpval = sprintf( '%02d', $val );
						}
			
						$tmpnum = 0;
						$strlenval = strlen( $tmpval );

						$fulldate = substr( $curnum, 0, ( 8 - $strlenval ) ) . $tmpval;

						if ( $fulldate ) {
							if ( $target_Ym === substr ( $fulldate, 0, 6 ) ) {
								$tmpnum = ( int ) substr( $fulldate, 6, 2 );

								if ( isset ( $dateary[ $tmpnum ] ) ) {
									$dateary[ $tmpnum ] .= ' closedy';
								}		
							}
						}
					}
				}
			}
		}

		// 独自休日とは別の特別な日を配列にして指定、4ケタか3ケタ または8ケタ、8ケタの場合はclassがlanniversaryになりまた別のスタイル指定が可能。
		//日付の後に:に続けて文字列を指定することで、マウスオン時にtitleに表示させたることも可能、例:array('903','0130:My birth','204','20170829:site open!')
		$anniver = array();
		if ( $prm['anniver'] ) {
			if ( is_array( $prm['anniver'] ) ) {
				$anniver = $prm['anniver'];
			} else {
				$anniver = explode( ',', $prm['anniver'] );
			}

			if ( $anniver ) {
				foreach ( $anniver as $val ) {
					$classname = ' anniversary';
					$tmpnum = 0;
					$annielem = array();
					$fulldate = '';
	
					$annielem = explode( ':', $val );
					if ( isset( $annielem[1] ) and $annielem[1] ) {
						$annielem[1] = esc_html( $annielem[1] );
					} else {
						$annielem[1] = 'anniversary';
					}

					$tmpval = sprintf( '%04d', $annielem[0] );
					$strlenval = strlen( $tmpval );

					if ( 8 === $strlenval ) {
						$fulldate = $annielem[0];
						$classname = ' lanniversary';
					} else{
						$fulldate = substr( $curnum, 0, ( 8 - $strlenval ) ) . $tmpval;		
					}

					if ( $fulldate ) {
						if ( $target_Ym === substr ( $fulldate, 0, 6 ) ) {
							$tmpnum = ( int ) substr( $fulldate, 6, 2 );
							if ( isset ( $dateary[ $tmpnum ] ) ) {
								$dateary[ $tmpnum ] .= $classname . '" title="' . $annielem[1];
							}
						}
					}
				}
			}
		}

		if ( isset ( $dateary[ $todayid ] ) ) { 
			$dateary[ $todayid ] .= '" id="today';
		}

    // ↓function holiday_class_post_calendar()続く
	// ↓class続く
?>
PHP
CopyExpand

と、いうことでやっとというかカレンダーの html 生成へと向かいます。html の組成としては css grid を前提とする div を骨格とするものと、従来通りの table を使用するものが選択可能。

前後の月や投稿があった日の日付アーカイブへのリンクを取得する方法は、以前はその都度 get_month_link()get_day_link() を呼び出していました。しかし、日付けアーカイブへのリンクはいたってシンプルで毎回関数を使用することもないのではと。そこで、一度だけ get_month_link() で基本となる月アーカイブへのリンクを取得しておいて、必要なときに月アーカイブの場合は年月の文字列を変換すること、日アーカイブの場合は日付を付加するという簡単な方法を採用しています。

<?php
	// ↓class続き
	// ↓function holiday_class_post_calendar()続き

    	// 基本とする月アーカイブへのリンク
        // 例:localhost/wp/2016/12/ or localhost/wp/?m=201612
		$baselink = get_month_link( $tyear, $tmonth );
		$en_grid = 'table';

        // table or grid 指定の初期設定
		$elem_grid = array(
			'0' => 'table',
			'1' => ' style="display:grid;grid-template-columns:repeat( 7, 1fr );text-align:center;"',// grid のデフォルトスタイル設定
			'2' => '',
		);

		if ( $prm['en_grid'] ) {

			if ( isset ( $elem_grid[ $prm['en_grid'] ] ) ) {
				$en_grid = $elem_grid[ $prm['en_grid'] ];
			} else {
				$en_grid = ' style="' . esc_attr( $prm['en_grid'] ) . '"';
			}
		}

        // HTML出力開始
		if ( 'table' === $en_grid ) {
            // table 表示指定の場合は、table 表示用の別ファイルを読み込む
            include 'table_layout.php';
		} else {
			$tmpstrary =array();

			$tmpstrary[] =  "\n<!-- Holiday-class Post Calendar Plugin grid version v" . $this->version . " " . $nowdate->format( 'Y/m/j H:i' ) . " -->\n";
			$parentstyle = '';
			if ( '' !== $prm['parentstyle'] ) {
				$parentstyle = ' style="' . esc_attr( $prm['parentstyle'] ) . '"';
			}
			$tmpstrary[] = '<div id="wp-calendar"' . $parentstyle . '>' . "\n";
			$showwd=array();
			$showsm=array();
			$addcapt = '';
		
			if ( $prm['capt'] ) {
				$addcapt = '<br>' . esc_html( $prm['capt'] );
			}
		
			if ( 'j' === $prm['lang'] ) {
				$heisei = '';
				$nengo = '';		

				$syubundate = new  DateTimeImmutable( '2019-05-01', new DateTimeZone( $timezone ) );
				$syubun = $syubundate->getTimestamp();

				if ( $tarstamp < $syubun ) {

					$heisei = ( string ) ( ( int ) $tardate->format( 'y' ) + 12 );
					$nengo = '平成';
				} else {

					$heisei = ( string ) ( ( int ) $tardate->format( 'y' ) - 18 );
					if ( '1' === $heisei ) {
						$heisei = '元';
					}
					$nengo = '令和';
				}
				$tmpstrary[] = '<p class="cal-ym">' . $tyear . ', ' . $nengo . $heisei . '年' . ( string)( ( int )$tmonth ) . '月' . $addcapt . '</p>' . "\n";

				$showwd = array( [ '日', ' class="nitiyou"' ], [ '月', '' ], [ '火', '' ], [ '水', '' ], [ '木', '' ], [ '金', '' ], [ '土', ' class="doyou"'], [ '日', ' class="nitiyou"' ] );
				$showsm = array( '12月', '1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月', '1月' );
			}else{
				$fullengm = array( ' January', ' February', ' March', ' April', ' May', ' June', ' July', ' August', ' September', ' October', ' November', ' December' );
				$tmpstrary[] ='<p class="cal-ym">' . $fullengm[ ( ( int ) $tmonth - 1 ) ] . ' ' . $tyear . $addcapt . '</p>' . "\n";

				$showwd = array( [ 'Su', ' class="nitiyou"' ], [ 'Mo', '' ], [ 'Tu', '' ], [ 'We', '' ], [ 'Th', '' ], [ 'Fr', '' ], [ 'Sa', ' class="doyou"' ], [ 'Su', ' class="nitiyou"'] );
				$showsm = array( 'Dec', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec', 'Jan' );
			}

            // $rowstart は1日の曜日によって、grid-column-start でオフセットさせるための数値
			if ( 's' === $prm['wf'] ) {
				unset ( $showwd[7] );
				$rowstart = $elem['fdwd'] + 1;
			} else {
				unset ( $showwd[0] );
				if ( 0 === $elem['fdwd'] ) {
					$rowstart = $elem['fdwd'] + 7;
				} else {
					$rowstart = $elem['fdwd'];
				}
			}

			$tmpstrary[] = '<div class="cal-wd"' . $en_grid . '>';
		
			foreach ( $showwd as $val ) {
				$tmpstrary[] = '<b' . $val[1] . ' title="' . $val[0] . '">' . $val[0] . '</b>';
			}
		
			$tmpstrary[] = '</div>' . "\n";
			$nextmstr = ' ';
				
			$tmpstrary[] = '<div class="cal-body"' . $en_grid . '">';
		
			$dateary[1] .= ' gettan" style="grid-column-start:' . ( string ) $rowstart . ';';// gettan -> 月旦の意

			foreach ( $dateary as $i => $val ) {
		
				$tmpclnd = '';
				$hdclsstr = '';
		
				if ( $val ) { 
					$hdclsstr = ' class="' . trim( $val ) . '"';
				}
				$tmpstrary[] = '<div' . $hdclsstr;

                // その日にちに投稿がある場合
                if ( isset( $ispost[ $i ] ) ) {

                    // 基本とする月アーカイブへのリンクに日付データを付加することで日ページへのリンクを作成
                    $dayurl = $baselink . $trailslash . sprintf( '%02s',  $i ) . $slashstr;

                    // post_type にカスタム投稿を指定してある場合に
    				// そのurlパラメータを付加する
					if ( 'post' !== $prm['postype'] ) {
						$dayurl = esc_url( add_query_arg( 'post_type', $prm['postype'], $dayurl ) );
					}

					$linkday = $target_Ym . sprintf( '%02d', $i );
		
					$postdatalink = array();
				
					if ( '1' === $prm['daypostlink'] ) {
						foreach ( $ispost[ $i ] as $value ) {

							if ( 'post' !== $prm['postype'] ) {

								$postdatalink[] = '<span class="daychildrenmark"><a href="' . get_post_permalink( $value[0] ) . '">' . $value[1] . '</a></span>';
							} else {
								$postdatalink[] = '<span class="daychildrenmark"><a href="' . get_permalink( $value[0] ) . '">' . $value[1] . '</a></span>';
							}
						}
		
						$tmpstrary[] = ' data-post="y"><a href="' . $dayurl . '">' . $i . '</a><span class="daychildren">' . implode( '<br>', $postdatalink ) . '</span></div>';
					} else {
						foreach ( $ispost[ $i ] as $value ) {

							$postdatalink[] = $value[1];
						}
						$tmpstrary[] = '><a href="' . $dayurl . '" title="' . implode( ',', $postdatalink ) . '">' . $i . '</a></div>';
					}
				} else {
					$tmpstrary[] = '>' . $i . '</div>';
				}
			}
			
			$tmpstrary[] = '</div>' . "\n";
		
			// 下部に追加表示する文字列
			// 複数も可。その場合は,(半角カンマ)で区切って指定。それぞれに色等を指定するためのidを付加する場合は:で区切って指定。例:毎週金はお休み,毎月3日は特売日:hclred,営業11時-20時:hclblue
			$footer = '';
		
			if ( $prm['footer'] ) {
				$footerary = explode( ',', $prm['footer'] );
				foreach ( $footerary as $val ) {
					$footerstr = array();
					$footerstr = explode( ':', $val );
					if ( isset( $footerstr[0] ) and $footerstr[0] ) {
						$footerstr[0] = esc_html( $footerstr[0] );
					} else {
						$footerstr[0] = '';
					}
					if ( isset( $footerstr[1] ) and $footerstr[1] ) {
						$footerstr[1] = esc_attr( $footerstr[1] );
					} else {
						$footerstr[1] = '';
					}
					if ( $footerstr[0] ) {
						$tdclass = '';
						if ( $footerstr[1] ) {
							$tdclass = ' id="' . $footerstr[1] . '"';
						}
						$footer .= '<p ' . $tdclass . '>' . $footerstr[0] . '</p>';
					}
				}
				$footer = '<div class="cal-btmstr">' . $footer . '</div>';
			}
		
			$tmpstrary[] = $footer;

			if ( '' !== $elem['nmonth'] ) {

                // 基本とする月アーカイブへのリンクから文字列置換で次月へのリンクを得る
				$monurl = str_replace( $tmonthform, $elem['nmonth'], $baselink );

                // post_type にカスタム投稿を指定してある場合に
                // そのurlパラメータを付加する
				if ( 'post' !== $prm['postype'] ) {
					$monurl = esc_url( add_query_arg( 'post_type', $prm['postype'], $monurl ) );
				}
				$nextmstr = '<a href="' . $monurl . '">' . $showsm[ ( ( int ) $tmonth + 1 ) ] . ' »</a>';
			}

            // 基本とする月アーカイブへのリンクから文字列置換で前月へのリンクを得る
			$monurl = str_replace( $tmonthform, $elem['pmonth'], $baselink );

			if ( 'post' !== $prm['postype'] ) {
				$monurl = esc_url( add_query_arg( 'post_type', $prm['postype'], $monurl ) );
			}
			$tmpstrary[] = '<div class="cal-footer" style="display:grid;grid-template-columns:1fr 1fr;"><div id="lclprevm"><a href="' . $monurl . '">« ' . $showsm[ ( ( int ) $tmonth - 1 ) ] . '</a></div><div id="hclnextm">' . $nextmstr . '</div></div>' . "\n";

			$tmpstrary[] = '</div>' . "\n";
		}

	// ↓function holiday_class_post_calendar()続く
	// ↓class続く
?>
PHP
CopyExpand

そして月別アーカイブの表示へと。ここはほとんど変わっていない。
月別アーカイブの年別リストは、月リスト部分を年リストの子要素として通常は非表示として格納し、年をクリックした時に非表示となっているその年の月リストを表示したいという目的で作ったものです。こうすることで長くなってしまうリストを短く表示させたいという意図です。そのためにそれ専用のスタイルシートも付属させています。

月別アーカイブリストのデータは wp_get_archives() にて得られたものを、年の文字列を抜き出して、精製してとまわりくどい面倒な事をやってリストにしています。
この部分はこの関数を使わずに SQL にて必要なデータだけを取得してリストにした方がはるかに効率的のように思います。実際に自分のサイトにおいては SQL でやっていますが、カスタム投稿で使う場合はリンク出力にもうひと手間必要になると思います。

<?php
	// ↓class続き
	// ↓function holiday_class_post_calendar()続き

    	// 月別アーカイブの表示
        if ( '1' === $prm['monthly'] ) {
            $acvstr = 'Monthly Archives';
            $smstr = 'Select Month';
            $nen = '';
            $tuki = '';

            if ( '' !== $prm['acvheader'] ){
                $acvstr = esc_html( $prm['acvheader'] );
            } elseif( 'j' === $prm['lang'] ) {
                $acvstr = '月別アーカイブ';
                $smstr = '月を選択';
            }
            $tmpstrary[] = '<h2 class="widgettitle monacvlst">' . $acvstr . '</h2>' . "\n";
            $post_type = $prm['postype'];

            if ( 1 === ( int ) $prm['acvoptorlist'] ) {

				// プルダウン表示部分
                if ( $this->call_count > 1 ) {
                    $curif = '-' . ( string ) $this->call_count;
                } else {
                    $curif = '';
                }
                $tmpstrary[] = '<select name="archive-dropdown" id="archive-dropdown' . $curif . '"><option value="">' . $smstr . '</option>' . "\n";

                $monthlisttmp = wp_get_archives( "type=monthly&format=option&show_post_count=1&echo=0&post_type=$post_type" );

                if ( $monthlisttmp ) {// 管理画面において wp_get_archives は値が得られない
                    $tmpstrary[] = str_replace( array( '月', '年' ), array( '', '/' ), $monthlisttmp );
                } else {
                    $tmpstrary[] = '<option>month-list</option>';
                }
                $tmpstrary[] = '</select>' . "\n";

            } else {
				// 年別リスト表示部分
                $monthlisttmp = wp_get_archives( array(
                    'type' => 'monthly',
                    'format' => 'custom',
                    'show_post_count' => true,
                    'after' => '!',
                    'echo' => false,
                    'post_type' => $post_type,
                )  );

                $tarstr = '/20';
                $addnum = 1;

                if ( $monthlisttmp ) {
                    $mlary = explode( '!', $monthlisttmp );
                    $closeul = '';
                    if ( false !== strpos( $mlary[0], '?m=' ) ) {
                        $tarstr = 'm=2';
                        $addnum = 2;
                    }
                } else {
                    $mlary = array();
                    $closeul = '<li>month-list</li></ul>';
                }

                $prevyear = '1999';
                $curryear = '';
                $tmpstrary[] = '<ul class="monthlylist">' . $closeul;
                $ulflg = 0;
                $chkcnt = 1;

                foreach ( $mlary as $val ) {
                    if ( strlen( $val ) > 10 ) {
                        $mltmp = str_replace( array( '年', '月', '\'' ), array( '_', '', '"' ), trim( $val ) );
                        $curryear = substr( $mltmp, strrpos( $mltmp, $tarstr ) + $addnum, 4 );

                        if ( $curryear !== $prevyear ) {
                            if ( 1 === $ulflg ) {
                                $tmpstrary[] = '</ul></li>' . "\n";
                            }
                            $tmpstrary[] = '<li class="arcyear"><label for="chlbis-' . $chkcnt . '" class="chlshwlbl" id="shwchl-' . $chkcnt . '">' . $curryear . $nen . '</label><input type="checkbox" name="chlbis-' . $chkcnt . '" id="chlbis-' . $chkcnt . '"><ul class="mlchildren">' . "\n";
                            $ulflg = 1;
                            ++$chkcnt;
                        }
                        $tmpstrary[] = '<li>' . str_replace( array( $curryear . '_', ' ' . $curryear . '<' ), array( ' ', ' <' ), $mltmp ) . '</li>' . "\n";

                        $prevyear = $curryear;
                    }
                }
                if ( $ulflg ) {
                    $tmpstrary[] = '</ul></li></ul>';
                }
            }
        }
        $clnd = implode( '', $tmpstrary );
        $ret_cont = $clnd;

		// キャッシュファイル保存処理
        if ( $en_cache ) {
            if ( $en_wp_file ) {
                $clnd = $info_calendar . chr(1) . "\n<!-- cache data -->\n" . $clnd;
                $wp_filesystem->put_contents( $cache_file, $clnd );
            }
        }

		// ほとんど無い事のように思えるが、仮に同一ページ内に複数のカレンダーが設置されている場合に、要素のidを固有のものとする処理
        if ( $this->call_count > 1 ) {
            $str_callcount = ( string ) $this->call_count;
            $chilbis = '"chlbis-' . $str_callcount . '-';
            $shwchl = '"shwchl-' . $str_callcount . '-';
            $calendarid = 'id="wp-calendar-' . $str_callcount . '"';
            $ret_cont = str_replace( array( '"chlbis-', '"shwchl-', 'id="wp-calendar"' ), array( $chilbis, $shwchl, $calendarid ), $ret_cont );
        }

        return $ret_cont . $arcvdrpdwnscpt;

    }// ↑holiday_class_post_calendar()ここまで

	// 投稿が公開された時に、キャッシュファイルを削除する関数
	// キャッシュファイルを設定する数値に制限はないけれど、見て分かる通り、削除するのは5番まで
    public function save_del_cache() {// publish_post hook
        
        require_once( ABSPATH . 'wp-admin/includes/file.php' );

        if ( WP_Filesystem() ) {
            global $wp_filesystem;

            for ( $i = 1; $i < 6; ++$i ) {
                $target_file = plugin_dir_path( __FILE__ ) . '/hcpcldr_cache_' . ( string ) $i . '.php';
        
                if ( $wp_filesystem->exists( $target_file ) ) {
                    $wp_filesystem->delete ( $target_file, false, 'f' );
                }	
            }	
        }
    }
}// end class
?>
PHP
CopyExpand

そして、これが最後の部分。起動に関して。

<?php
    if ( ! isset ( $hldycls_post_calendar_start ) ) {

        $hldycls_post_calendar_start = new hldycls_post_calendar();

	    // ↓管理画面のメニューにオプション設定ページを登録する処理
        if ( is_admin() ) {
            add_action( 'admin_menu', array( $hldycls_post_calendar_start, 'hldycls_pcldr_add_menu' ) );
        }

        // ↓カレンダーを表示するメインとなる関数
        if ( ! function_exists( 'holiday_calendar_echo' ) ) {
            function holiday_calendar_echo() {
                global $hldycls_post_calendar_start;

                $rargs = array();
                $args = func_get_args();
                if ( func_num_args() > 0 ) {
                    $rargs = $args[0];
                }
                $ret = $hldycls_post_calendar_start->holiday_class_post_calendar( $rargs );
                echo $ret;
            }
        }

        if ( ! function_exists( 'hldyclspc_getarchives_where' ) ) {
            // 月別アーカイブリストを得るwp_get_archives()においてpost_typeを指定するためのフック
            add_filter( 'getarchives_where', 'hldyclspc_getarchives_where', 10, 2 );

            function hldyclspc_getarchives_where( $where, $r ) {
                if ( isset( $r['post_type'] ) ) {
                    $where = str_replace( '\'post\'', '\'' . $r['post_type'] . '\'', $where );
                }
                return $where;
            }
        }
    }
} // if class
?>
PHP
CopyExpand

以上でプラグインのメインファイル、holiday_class_post_calendar.php は終わり。

Sanbanse Funabashi
2011.01.01 sunrise

Top

スクロールさせるか画像をクリックすると元に戻ります。