WordPress を使うようになって、そのなんとも味気ないカレンダーの日曜、土曜、祭日に色をつけるためにとりあえず class を設定するのは、「wordpressのカレンダー」でやって、英語表示にするのは、「wordpressのカレンダーを英語化」で、文字列を置換することで、とりあえず実現していました。

ここのアクセスログなどを見ていると、やはり同じようにカレンダーをどうにかしたいと思っている人は多いようです。ふと、考えてみると、WordPress によって生成されたものをわざわざ置換などという面倒な事をせずとも、カレンダー作成関数を自作してしまえばいいのではないかと。そのほうが二度手間でない分、速度的にもよほど有利なのではないのかと。

こんなことを考えていた当時は、php の勉強のために、とにかくひたすらに自分で考えてプログラムを書こうと思っていたので、何も参考にすることなく、一から自分で考えて作っていったものです。自分のサイトの WordPress において吐き出されたカレンダーの HTML と、ほぼ同じ出力となるように。

機能的に欲しいと思ったことは、日本語か英語表示かの選択、週の始めが日曜か月曜かを指定することが出来るといったこと。もちろん、WordPress のカレンダーと同じく日付テンプレートへのリンクが必須なのは言うまでもなく。

Postcalendar built-in type ver 7.0

と、いうことで、あらためて付いている機能はというと。

  • 日曜、土曜、祭日及び独自の休日などのスタイル設定するための class がそれぞれにつきます
  • その独自の休日のスタイルを設定できる class は4種類
  • 日本語と英語表記が選択可能
  • 週の始めを日曜から始めるか月曜にするか設定可能
  • カレンダーの日付に表示できる投稿の post_type を指定できる
  • 月別アーカイブのリストも一緒に表示することが可能( プルダウン or 年別リスト )
  • カレンダーの表題とフッターに表示する文字列を指定することが可能

最初に作った時からずいぶんと時間が流れ、WordPressv 6.1 に、phpv 8.2 となったところで、このカレンダーを使ったプラグインも、2022年11月27日v 7.0 へとバージョンアップさせました。もう、最初のものとは全く違ったものになっていること。v 6.0 からも相当な部分をアップデートさせているので、このページも新しく書き直しました。

なお、プラグインにもしていますが、その詳細はこちらへ => 「プラグイン Holiday Class Post Calendar

補助的関数 ret_holidays() + ret_daynum()

ではでは、いよいよ本題のカレンダープログラム。
先に補助的なプログラムを二つ。休日データを返す関数とその月の1日の曜日から指定した曜日のその月においての日にちを配列にして返す関数。休日データは管理画面内の投稿カレンダーページ表示関数でも使うために別関数となってる。

ret_daynum関数について少し書いておくと。
その月の1日の曜日がわかれば、何日が何曜日かは簡単な計算でわかる。この関数は1日の曜日と知りたい曜日を指定することで、その月のその曜日の日にちをすべて配列にして返す関数。日曜日、土曜日、あとは曜日にて休日を指定されている場合に、この関数で日にちを取得して、key が日にちに対応している休日クラス配列に、その key(日にち)で クラスの設定をするということにしている。

<?php
    function ret_holidays() {
        //↓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';
        $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' );

        return array( $holidays_data, $alp_num );
    }

    // その月の1日の曜日から指定した曜日のその月においての日にちを配列にして返す関数
    // $wdaynum 1:日曜、2:月、3:火、4:水、5:木、6:金、7:土 求める日にちの曜日を指定
    // $fdwd : その月の1日の曜日 0:日1:月2:火3:水4:木5:金6:土
    // $dnum : その月の日数
    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;
    }
?>
PHP
CopyExpand

postcalendar() 表示年月設定 ~ キャッシュ処理

そして、本丸のカレンダー表示関数。
この始めの部分での最たる変更というのは、カレンダーの最も基本となる部分、日付の取得方法を変更していること。で、DateTime クラスを使う方法に変更してる。これによってサーバーのタイムゾーンに影響を受けることはなくなってる。その後につづくキャッシュファイルの部分はほぼ変更はなし。

<?php
    function postcalendar(){
        //関数中でデータベースを使う時のお約束の$wpdbとurlクエリの値を得るための$wp_query
        global $wpdb, $wp_query;
        $version = '7.0';

        //パラメータの初期化
        $param = array (
            'lang' => 'e',
            'wf' => 's',
            'capt' => '',
            'closewd' => '',
            'closel' => '',
            'anniver' => '',
            'monthly' => '1',
            'link' => 'j',
            'arctype' => '1',
            'posttype' => 'post',
            'footer' => '',
            'daypostlink' => '0',
            'en_cache' => '1',
        );

        $args = func_get_args();
		//引数の指定ありの判断は引数の個数を返すfunc_num_args()で。
		//指定されている引数でパラメータを上書き

        if ( func_num_args() > 0 ) {
            $param = array_merge( $param, $args[0] );

            // 引数にて post_type の指定がない場合は、そのページの post_type を確認する
            if ( ! isset( $args[0]['posttype'] ) ) {

                $q_vars = $wp_query->query_vars;
                if ( isset( $q_vars['post_type'] ) and  $q_vars['post_type'] ) {
                    $param['posttype'] = $q_vars['post_type'];
                }
            }
        }

        // post_type が 'post' ではない場合は、link 先の url に付加するパラメータを作る
        $posttypepara = '';
        if ( 'post' !== $param['posttype'] ) {
            $posttypepara = '&post_type=' . $param['posttype'];
        }

        // アクセスされたブラウザの言語設定が日本語ではない場合、link 先の url に付加する英語指定のパラメータを作る
        $urlpara = '';
        if ( 'j' !== $param['link'] ) {
            $urlpara = '&lang=en';
        }

        $urlstr = home_url();

        $timezone = 'Asia/Tokyo';

        $tmp_month_no='';

        //  v7.0 での最たる変更点、日付の取得に DateTimeクラスを使用する方法に変更
        $nowdate = new  DateTimeImmutable( '', new DateTimeZone( $timezone ) );
        $basestamp = $nowdate->getTimestamp();
        $target_Ym = $nowdate->format( 'Ym' );// 実際に表示する年月、eq. 202201

        $future = '';// 現在の年月より未来である月のカレンダーを表示する場合の特別なパラメータがfm。eg. 202112
        if ( isset( $_GET['fm'] ) ) {
            $future = $_GET['fm'];
        }

        $elem = array();
        $elem['today'] = $nowdate->format( 'd' );//本日の日にち
        $elem['cmonth'] = $target_Ym;//現在の年月

        // ページが日付テンプレートを要求されている場合
        if ( $wp_query->get('m') !== '' or '' !== $future ) {

            if ( $wp_query->get('m') !== '' ) {// 過去

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

            } elseif ( '' !== $future ){// 未来の年月
                $tmpcur = $elem['cmonth'];

                if ( ( int ) $future > ( int ) $tmpcur ) {
                    $tmp_month_no = $future;
                } else {
                    $tmp_month_no = $tmpcur;
                    $future = '';
                }
            }

            // 現在ではない表示する年月の基本データの設定
            if ( $tmp_month_no ) {
                $tmpym = array( substr( $tmp_month_no, 0, 4 ), substr( $tmp_month_no, 4, 2 ) );

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

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

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

        // 表示させる月が現在とは違う場合、今日の日付設定の消去
        if ( $target_Ym !== $elem['cmonth'] ) {
            $now_day = '';
            $todayid = 0;
        } else {
            $now_day = $elem['today'];
            $todayid = ( int ) $elem['today'];
        }

        // Content Security Policy 対応用の javascript
        // 月別アーカイブに select タグを使用している場合、onchange でリンク先へ遷移させるための javascript に nonce を付加する
        // このスクリプトはキャッシュに含めてはいけないため
        // 定数CSPNONCE というのは functions.php で定義してあるページ読み込みの際に作成されるランダムな mb5 文字列で下行の如く生成
        // define( 'CPSNONCE', md5( uniqid( mt_rand(), TRUE ) ) );
        $arcvdrpdwnscpt = "\n" . '<script nonce="' . CPSNONCE . '">if ( null !== document.getElementById("archive-dropdown")) { const arcvdrpdwn = document.getElementById("archive-dropdown"); arcvdrpdwn.onchange = () => { document.location.href=arcvdrpdwn.options[arcvdrpdwn.selectedIndex].value; }}</script>' . "\n";

        // キャッシュファイルがある場合は、そのファイルを読み込んで表示させ、関数を終了させる
        // キャッシュファイルがそのページで使用できるものか判別するための識別文字列を生成
        $info_calendar = $target_Ym . $now_day . '_l' . $param['lang'] . 'w' . $param['wf'] . 'm' . $param['monthly'] . '_' . $param['posttype'] . '_k' . $param['link'] . 'o' . $param['arctype'] . 'd' . $param['daypostlink'] . '_';

        // 0b11111 -> 31 にあまり意味はない、31までは有効な数字、キャッシュファイル番号の有効化
        $en_cache = ( ( int ) $param['en_cache'] & 0b11111 );

        if ( $en_cache ) {
            $cache_file = './wp-content/themes/first/cache/hcpcldr_cache_' . ( string )$en_cache . '.php';

            if ( file_exists( $cache_file ) ) {
                $cache = file ( $cache_file );
                $caldata = array_shift( $cache );

                // キャッシュデータの1行目には表示している年月、表示設定などの略した文字列があり、それが一致している場合はキャッシュを表示する
                if ( $info_calendar === trim( $caldata ) ) {
                    echo "\n<!--<p>Holiday-class Post Calendar built-in v" . $version . "_future by cache " . $nowdate->format( 'Y/m/j H:i' ) . " : " . $info_calendar . "</p>-->\n";
                    echo implode( '', $cache );
                    // 月別アーカイブ用のjavascript とキャッシュを使用している事を表示する要素を出力
                    echo $arcvdrpdwnscpt . '<p style="font-size:0.7em;color:#00ff7f;padding:0;margin:0;text-align:right;" title="use cache data">♣</p>';

                    return;
                }
            }
        }

        // function 続く↓
?>
PHP
CopyExpand

postcalendar() 前後月設定 ~ 投稿データ取得

続いての部分。ここでの変更点は、その日付に投稿があった場合の、その投稿データの保持の仕方となる。以前のは、まずその日に投稿データがあるかを調べ、あれば文字列連結にてデータを蓄えていた。これを文字列連結ではなく、配列として蓄えていく方法に変更した。これによりすでにデータがあるかをチェックする必要はなくなり、後でその配列データを一気に implode で連結して一つの文字列とする。この手法のほうがより高速である。そのために投稿を蓄えておく配列において、その月の全日付をキーとする空の要素を含む配列をあらかじめ作っておいて、データを入れた後で空の要素を array_filter で削除するということをやってる。それにより、データの有無ではなく、要素の有無を isset でチェックすることができる。

<?php
        // function 続き

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

        // 表示する月の前月
        $lastmonth = new  DateTime( $curfull, new DateTimeZone( $timezone ) );
        $nextmonth = clone $lastmonth;
        $lastmonth->modify( 'first day of last months' );

        $elem['pmonth'] = $lastmonth->format( 'Ym' );

        if ( ( int ) $target_Ym !== ( int ) $elem['cmonth'] ) {
            $todayid = 0;
        }

        if ( ( int ) $target_Ym >= ( int ) $elem['cmonth'] ){

            //表示する月が現在の月ならば翌月へのリンクは翌月のカレンダーを表示するためだけの特別なurlパラメータ。
            $fmstr = 'fm=';
        } else {
            $fmstr = '';
        }
        $nextmonth->modify( 'first day of next months' );
        $elem['nmonth'] = $fmstr . $nextmonth->format( 'Ym' );// 表示する月の翌月

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

        // 日付をキーとする配列をつくる、class、id を入れておくため
        $dateary = array_fill( 1,  $elem['lddate'], '' );
        // 同じ日に複数の投稿があった場合のタイトルを一つにまとめてしまう。
        $ispost = array_fill( 0,  $elem['lddate'] + 1, array() );

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

        // その月の土曜日の日にちを求める
        $satnum = ret_daynum( 7, $elem['fdwd'], $elem['lddate'] );
        foreach ( $satnum as $val ) {
            $dateary[ $val ] = 'doyou';
        }

        if ( '' === $future ) {

            // SQL を発行してその月に投稿された日付とタイトル、ID を取得
$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;

            $months = $wpdb->get_results( $wpdb->prepare( $sql, $param['posttype'], $target_Ym ) ); // $target_Ym →例:201409

            foreach ( $months as $val ) {
                $tmpdate = ( int ) substr( $val->post_date, 8, 2 );
                $ispost[ $tmpdate ][] = array( ( string ) $val->ID, $val->post_title );
            }
        }
        // データ(投稿)のない日付の要素を削除してしまう
        $ispost = array_filter( $ispost );

        // デフォルトの休日データの取得
        $holidays_data = ret_holidays();
        $holidays = explode( ',', $holidays_data[0] );

        // アルファベット⇔数字変換用配列のキーと値をひっくり返した配列を作る
        $alp_num_flip = array_flip( $holidays_data[1] );

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

        if ( $taralp ) {
            foreach ( $holidays as $val ) {
                if ( $val[0] . $val[1] === $taralp ) {
                    $tmpnum = ( int ) $holidays_data[1][ $val[2] ];
                    if ( isset ( $dateary[ $tmpnum ] ) ) {
                        $dateary[ $tmpnum ] = 'nitiyou';
                    }
                    $sameflg = 1;
                } else {
                    if ( 1 === $sameflg ) {
                        break;
                    }
                }
            }
        }
        $alp_num_flip = null;
        $holidays_data = null;

        // function 続く↓
?>
PHP
CopyExpand

postcalendar() オプション指定休日データ処理

オプションで設定されている休日データの処理が続く。ここもその休日データを適用する部分において刷新してる。指定できる日付データの桁数に幅があるために、その有効化においてそれらの桁数において if により判別させていたのを、あらかじめ桁数をそろえておいて、表示する年月の基本となる8桁の日付データからその分を置き換えるという手法に変えてる。

<?php
        // function 続き

        // option や引数で指定されたそれぞれの独自休日の処理
        // 独自休日を曜日で指定、1:日曜~7:土曜
        if ( $param['closewd'] ) {
            if ( is_array( $param['closewd'] ) ) {// オプション値が配列で設定されている場合
                $tmpwd = $param['closewd'];
            } else {// オプション値が文字列の場合
                $tmpwd = explode( ',', $param['closewd'] );
            }
            // 指定された各曜日のその月の初めの日にちを、その月の1日の曜日から割り出し、その月の指定されたすべての曜日の日にちに対してクラスを指定する
            foreach( $tmpwd as $val ) {
                $wdnum = ret_daynum( $val, $elem['fdwd'], $elem['lddate'] );
                foreach ( $wdnum as $num ) {
                    $dateary[ $num ] .= ' closewd';
                }
            }
        }

        // 独自休日を配列にして指定。毎月同じ休日等の場合は日にちで指定可、例:array('3','10','202','0928','20140911','20140919')
        $closel = array();
        if ( $param['closel'] ) {
            if ( is_array( $param['closel'] ) ) {
                $closel = $param['closel'];
            } else {
                $closel = explode( ',', $param['closel'] );
            }

            if ( $closel ) {
                foreach ( $closel as $val ) {

                    if ( $val ) {
                        // v7.0 においてより高速化を図って刷新
                        // 3桁以下で日付を指定してある場合、3桁の場合は4桁に、2桁以下の場合は2桁にそろえる
						if ( isset ( $val[2] ) ) {
							$tmpval = sprintf( '%04d', $val );
						} else {// 2ケタないし1ケタの場合
							$tmpval = sprintf( '%02d', $val );
						}
    
                        $tmpnum = 0;
                        $strlenval = strlen( $tmpval );

                        // 年月日フルで8桁なので、指定日付の桁分だけ8桁から置き換える
                        $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ケタにて指定した場合は、class名を別のlanniversaryにする
		// 例:array('903','0130','204','20170829')
        // 日付に':'をつけて title として表示させる文字列を指定することも可能
        $anniver = array();
        if ( $param['anniver'] ) {
            if ( is_array( $param['anniver'] ) ) {
                $anniver = $param['anniver'];
            } else {
                $anniver = explode( ',', $param['anniver'] );
            }

            if ( $anniver ) {
                foreach ( $anniver as $val ) {
                    $classname = ' anniversary';
                    $annielem = array();
                    $fulldate = '';
                    $tmpnum = 0;

                    $annielem = explode( ':', $val );
                    if ( isset( $annielem[1] ) and $annielem[1] ) {
                        $annielem[1] = esc_html( $annielem[1] );
                    } else {
                        $annielem[1] = 'anniversary';
                    }
    
                    // 3桁のものを4桁にそろえる
                    $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 ( '+' === $annielem[1] ) {
                        $classname = 'nitiyou';
                        $annielem[1] = 'holiday';
                    }

                    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 続く↓
?>
PHP
CopyExpand

postcalendar() html生成 本体部分

そしてカレンダー本体生成部分となる。
この部分の大きな変更は、生成する html の蓄積方法。これまでは生成していくカレンダーの html を文字列連結で蓄えていったのを、配列に蓄えていって最後に implode で一括して一つの文字列にするという手法に変えてる。これに関しては、実際にベンチでどちらが速いかを計測してみた結果による。文字列連結の回数が少なければほとんど差はないが、それが多くなればなるほど、配列 + implode のほうが高速となった。

<?php
        // function 続き
        // いよいよカレンダー本体の生成へと

        echo "\n" . '<!--<p>Post Calendar original built-in v' . $version . '_future ' . $nowdate->format( 'Y/m/j H:i' ) . ' : ' . $info_calendar . "</p>-->\n";

        // v6 まではカレンダーの html を文字列結合で作成していったが、
        // v7 では配列に蓄えて最後に implode で一つの文字列に結合する方法に変更
        // その方が高速である
        $tmpstrary = array();

        $tmpstrary[] = '<div id="wp-calendar" style="font-size:0.7em;text-align:center;">' . "\n";
        $showwd = array();
        $showsm = array();
        $addcapt = '';

        // captionに付加して表示する文字列の指定がある場合
        if ( $param['capt'] ) {
            $addcapt = '<br>' . esc_html( $param['capt'] );
        }

        // 日本語表記の場合
        if ( 'j' === $param['lang'] ) {
            $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 id="cal-ym">' . $tyear . ', ' . $nengo . $heisei . '年' . ( string ) ( ( int ) $tmonth ) . '月' . $addcapt . '</p>' . "\n";
            if ( 's' === $param['wf'] ) {
                $showwd = array( '日', '月', '火', '水', '木', '金', '土' );
                $rowstart = $elem['fdwd'] + 1;
            } else {
                $showwd = array( '月', '火', '水', '木', '金', '土', '日' );
                if ( 0 === $elem['fdwd'] ) {
                    $rowstart = $elem['fdwd'] + 7;
                } else {
                    $rowstart = $elem['fdwd'];
                }
            }
            $dycls = array( '日' => ' class="nitiyou"  id="delcache" data-cache="1"', '月' => '', '火' => '', '水' => '', '木' => '', '金' =>'', '土' => ' class="doyou"' );
            $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 id="cal-ym">' . $fullengm[ ( ( int ) $tmonth - 1 ) ] . ' ' . $tyear . $addcapt . '</p>' . "\n";
            if ( 's' === $param['wf'] ) {
                $showwd = array( 'Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa' );
                $rowstart = $elem['fdwd'] + 1;
            } else {
                $showwd = array( 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su' );
                if ( 0 === $elem['fdwd'] ) {
                    $rowstart = $elem['fdwd'] + 7;
                } else {
                    $rowstart = $elem['fdwd'];
                }
            }
            $dycls = array( 'Su' => ' class="nitiyou"  id="delcache" data-cache="1"', 'Mo' => '', 'Tu' => '', 'We' => '', 'Th' => '', 'Fr' =>'', 'Sa' => ' class="doyou"' );
            $showsm = array( 'Dec', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec', 'Jan' );
        }

        // css grid の設定はインラインで。
        $tmpstrary[] = '<div id="cal-wd" style="display:grid;grid-template-columns:repeat( 7, 1fr );">';

        foreach ( $showwd as $val ) {
            // 曜日のタイトル行の表示、html のタグは div でも何でもよかったが、字数の少なさから b タグにしただけ
            $tmpstrary[] = '<b' . $dycls[ $val ] . ' title="' . $val . '">' . $val . '</b>';
        }

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

        // grid の設定はこれだけと後は、下の1日の曜日で offset させる grid-columun-start だけ
        $tmpstrary[] = '<div id="cal-body" style="display:grid;grid-template-columns:repeat( 7, 1fr );">';

        foreach ( $dateary as $i => $val ) {

            // 1日の要素には曜日による offset のための grid-column-start の設定を付加する
            if ( 1 === $i ) {
                $rowstart = ' style="grid-column-start:' . ( string ) $rowstart . ';"';
            } else {
                $rowstart = '';
            }
    
            $tmpclnd = '';
            $hdclsstr = '';

            // 値があるということは休日か土曜のclass が存在する
            if ( $val ) {
                $hdclsstr = ' class="' . trim( $val ) . '"';
            }
            $tmpstrary[] = '<div' . $hdclsstr . $rowstart;

            // その日に投稿が存在する場合
            if ( isset( $ispost[ $i ] ) ) {
                $linkday = $target_Ym . sprintf( '%02d', $i );

                $postdatalink = array();

                if ( '1' === $param['daypostlink'] ) {
                    foreach ( $ispost[ $i ] as $value ) {

                        if ( 'post' !== $param['posttype'] ) {
                            $postdatalink[] = '♦<a href="' . get_post_permalink ( $value[0] ) . '">' . $value[1] . '</a>';
                        } else {
                            $postdatalink[] = '♦<a href="https://strix.main.jp?p=' . $value[0] . '">' . $value[1] . '</a>';
                        }
                    }

                    $tmpstrary[] = ' data-post="y"><a href="' . $urlstr . '?m=' . $linkday . $posttypepara . $urlpara . '">' . $i . '</a><span class="daychildren">' . implode( '<br>', $postdatalink ) . '</span></div>';
                } else {
                    foreach ( $ispost[ $i ] as $value ) {

                        $postdatalink[] = $value[1];
                    }
                    $tmpstrary[] = '><a href="' . $urlstr . '?m=' . $linkday . $posttypepara . $urlpara . '" title="' . implode( ',', $postdatalink ) . '">' . $i . '</a></div>';
                }
            } else {
                $tmpstrary[] = '>' . $i . '</div>';
            }
        }
        
        $tmpstrary[] = '</div>' . "\n";
        // function 続く↓
?>
PHP
CopyExpand

postcalendar() html生成 footer部分

<?php
        // function 続き

        // 下部に追加表示する文字列 :
        // 複数も可。その場合は,(半角カンマ)で区切って指定。それぞれに色等を指定するためのclassを付加する場合は:で区切って指定。
        // 例:毎週金はお休み,毎月3日は特売日:hclred,営業11時-20時:hclblue
        $footer = '';

        if ( $param['footer'] ) {
            $footerary = explode( ',', $param['footer'] );
            if ( $footerary ) {
                foreach ( $footerary as $val ) {
                    $footerstr = array();
                    if ( false !== strpos( $val, ':' ) ) {
                        $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] = '';
                        }
                    } else {
                        if ( $val ) {
                            $footerstr[0] = esc_html( $val );
                        } else {
                            $footerstr[0] = '';
                        }
                        $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>';
            }
        } else {
            $footer .= '<div class="cal-btmstr"><p>Holiday-Class Post Calendar built-in type v' . $version . '</p></div>';
        }

        $tmpstrary[] = $footer;

        if ( false !== strpos( $elem['nmonth'], 'fm=' ) ) {
            $nextmstr = '<a href="' . $urlstr . '?' . $elem['nmonth'] . $posttypepara . $urlpara . '">' . $showsm[ ( ( int ) $tmonth + 1 ) ] . ' »</a>';
        } else {
            $nextmstr='<a href="'.$urlstr.'?m='.$elem['nmonth'] . $posttypepara . $urlpara . '">'.$showsm[ ( ( int ) $tmonth + 1 ) ].' »</a>';
        }
        $tmpstrary[] = '<div id="cal-footer" style="display:grid;grid-template-columns:1fr 1fr;"><div id="cal-prev"><a href="' . $urlstr . '?m=' . $elem['pmonth'] . $posttypepara . $urlpara . '">« ' . $showsm[ ( ( int ) $tmonth - 1 ) ] . '</a></div><div id="cal-next">' . $nextmstr . '</div></div>' . "\n";

        $tmpstrary[] = '</div>' . "\n";
        // function 続く↓
?>
PHP
CopyExpand

postcalendar() 月別アーカイブ生成 ~ キャッシュ保存

そして月別アーカイブ表示の部分。この部分はほぼ変わっていない。
プルダウン表示と、月別リストを表示させる形式とで選択できるようにしてあるのは今まで通り。リストの方はリストを格納していて、その表示においては、formcheckboxcheck の有無によって、css により兄弟要素の uldisplayblocknone を操作することで css だけで実現させてる。この部分においては Javascript は使用していない。逆に言えば、css の設定がないと表示が著しく崩れてしまう。

<?php
        // function 続き

        // 月別アーカイブの表示
        if ( '1' === $param['monthly'] ) {
            $sql = "SELECT YEAR(post_date) as year, MONTH(post_date) as month, count(ID) as ct FROM $wpdb->posts WHERE post_type=%s AND post_status='publish' GROUP BY YEAR(post_date), MONTH(post_date) ORDER BY post_date DESC";

            $monthlys = $wpdb->get_results( $wpdb->prepare( $sql, $param['posttype'] ) );

            $tmpstrary[] ='<h2 class="widgettitle">by months</h2>'."\n";

            // プルダウン表示
            if ( '1' === $param['arctype'] ) {
                $tmpstrary[] ='<select name="archive-dropdown" id="archive-dropdown"><option value="">month list</option>'. "\n";
                foreach($monthlys as $val){
                    $tmpstrary[] = '<option value="' . $urlstr . '?m=' . $val->year . sprintf( "%02s", $val->month ) . $posttypepara . $urlpara.'">'.$val->year.'/'.$val->month.'  ('.$val->ct.')</option>'."\n";
                }
                $tmpstrary[] ='</select>'."\n";

            // 年別リスト表示
            } else {
                $prevyear = '1999';
                $tmpstrary[] = '<ul id="monthlylist">';
                $ulflg = 0;
                $chkcnt = 1;
                $nen = '';
                $tuki = '';
                $arcvdrpdwnscpt = '';

                if ( $monthlys ) {
                    foreach($monthlys as $val){
                        if ( $val->year !== $prevyear ) {
                            if ( 1 === $ulflg ) {
                                $tmpstrary[] = '</ul></li>' . "\n";
                            }
                            $tmpstrary[] = '<li class="arcyear"><label for="chlbis-' . $chkcnt . '" class="chlshwlbl" id="shwchl-' . $chkcnt . '">' . $val->year . $nen . '</label><input type="checkbox" name="chlbis-' . $chkcnt . '" id="chlbis-' . $chkcnt . '"><ul class="mlchildren">' . "\n";
                            $ulflg = 1;
                            ++$chkcnt;
                        }
                        $tmpstrary[] = '<li><a href="' . $urlstr . '?m=' . $val->year . sprintf( "%02s", $val->month ) . $posttypepara . $urlpara . '">' . $val->month . $tuki . ' ( ' . $val->ct . ' )</a></li>' . "\n";
                        $prevyear = $val->year;
                    }
                    if ( $ulflg ) {
                        $tmpstrary[] = '</ul></li></ul>';
                    }
                }
            }
        }

        // カレンダーを表示。プルダウン表示の場合はスクリプトを付加する
        $clnd = implode( '', $tmpstrary );
        echo $clnd . $arcvdrpdwnscpt;

        // キャッシュファイルの保存
        if ( $en_cache ) {
            $clnd = $info_calendar . "\n<!-- cache data -->\n" . $clnd;
            file_put_contents( $cache_file, $clnd, LOCK_EX );
        }
    }// function 終わり
?>
PHP
CopyExpand

HTML 出力

そして生成される HTML はこうなります。改行、字下げしてあります。

<!--<p>Holiday-class Post Calendar built-in v7.0_future by cache 2023/01/15 12:21 : 20230115_lewsm1_post_kjo1d1_</p>-->
<!-- cache data -->
<div id="wp-calendar" style="font-size:0.7em;text-align:center;">
	<p id="cal-ym"> January 2023<br>bird photo post since Oct. 2011</p>
	<div id="cal-wd" style="display:grid;grid-template-columns:repeat( 7, 1fr );">
		<b class="nitiyou"  id="delcache" data-cache="1" title="Su">Su</b>
		<b title="Mo">Mo</b>
		<b title="Tu">Tu</b>
		<b title="We">We</b>
		<b title="Th">Th</b>
		<b title="Fr">Fr</b>
		<b class="doyou" title="Sa">Sa</b>
	</div>
	<div id="cal-body" style="display:grid;grid-template-columns:repeat( 7, 1fr );">
		<div class="nitiyou" style="grid-column-start:1;">1</div>
		<div class="nitiyou">2</div>
		<div data-post="y">
			<a href="https://strix.main.jp?m=20230103">3</a>
			<span class="daychildren"><a href="https://strix.main.jp?p=173772">Daurian Redstart</a>
			</span>
		</div>
		<div data-post="y">
			<a href="https://strix.main.jp?m=20230104">4</a>
			<span class="daychildren"><a href="https://strix.main.jp?p=173781">Brambling</a>
			</span>
		</div>
		<div data-post="y">
			<a href="https://strix.main.jp?m=20230105">5</a>
			<span class="daychildren"><a href="https://strix.main.jp?p=173803">Varied Tit</a>
			</span>
		</div>
		<div data-post="y">
			<a href="https://strix.main.jp?m=20230106">6</a>
			<span class="daychildren"><a href="https://strix.main.jp?p=173788">Long-tailed Tit</a>
			</span>
		</div>
		<div class="doyou">7</div>
		<div class="nitiyou">8</div>
		<div class="nitiyou">9</div>
		<div>10</div>
		<div data-post="y">
			<a href="https://strix.main.jp?m=20230111">11</a>
			<span class="daychildren"><a href="https://strix.main.jp?p=173836">Willow Tit</a>
			</span>
		</div>
		<div data-post="y">
			<a href="https://strix.main.jp?m=20230112">12</a>
			<span class="daychildren"><a href="https://strix.main.jp?p=173843">Grey-capped Greenfinch</a>
			</span>
		</div>
		<div data-post="y">
			<a href="https://strix.main.jp?m=20230113">13</a>
			<span class="daychildren"><a href="https://strix.main.jp?p=173852">Rustic Bunting</a>
			</span>
		</div>
		<div class="doyou">14</div>
		<div class="nitiyou" id="today">15</div><div>16</div><div>17</div><div>18</div><div>19</div><div>20</div><div class="doyou">21</div>
		<div class="nitiyou">22</div><div>23</div><div>24</div><div>25</div><div>26</div><div>27</div><div class="doyou">28</div>
		<div class="nitiyou">29</div><div class="anniversary" title="birth">30</div><div>31</div>
	</div>
	<div class="cal-btmstr">
		<p>Holiday-Class Post Calendar built-in type v7.0</p>
	</div>
	<div id="cal-footer" style="display:grid;grid-template-columns:1fr 1fr;">
		<div id="cal-prev">
			<a href="https://strix.main.jp?m=202212">« Dec</a>
		</div>
		<div id="cal-next">
			<a href="https://strix.main.jp?fm=202302">Feb »</a>
		</div>
	</div>
</div>
<h2 class="widgettitle">by months</h2>
<select name="archive-dropdown" id="archive-dropdown">
	<option value="">month list</option>
	<option value="https://strix.main.jp?m=202301">2023/1  (7)</option>
	<option value="https://strix.main.jp?m=202212">2022/12  (18)</option>
	<option value="https://strix.main.jp?m=202211">2022/11  (18)</option>
	- 省略 -
	<option value="https://strix.main.jp?m=201110">2011/10  (31)</option>
</select>

<script nonce="984f9d7f3a3535b09334721d9572c531">if ( null !== document.getElementById("archive-dropdown")) { const arcvdrpdwn = document.getElementById("archive-dropdown"); arcvdrpdwn.onchange = () => { document.location.href=arcvdrpdwn.options[arcvdrpdwn.selectedIndex].value; }}</script>
<p style="font-size:0.7em;color:#00ff7f;padding:0;margin:0;text-align:right;" title="use cache data"></p>
HTML
CopyExpand

Talking

  • wordpress 初心者 より:

    明けまして、おめでとうございます。

    今、wordpressでカレンダーを配置しようと考えてます。
    ここの、「Holiday Class Post Calendar plugin」というのを使って、
    自分のブログに貼り、うまくいけばと思ってました。
    でも、なぜか日付が本来の時刻、月日とずれてて遅れています。
    これは、一体何でしょうか?

    wordpressは初心者で、詳しくないですが、
    原因が何なのか分からないので、
    解決策などをいろいろと教えていただけると、とても幸いです。

    よろしくお願いいたします。

    • admin より:

      wordpress 初心者さん、明けましておめでとうございます。
      ご質問の件ですが、時間がずれるのはサーバーが使用している時間によるのではないでしょうか。9時間ずれませんか。
      「wordpress 時刻がずれる」などで検索すると色々と情報が出てきます。
      であれば、私のカレンダーだけではなく投稿した時間などすべてにおいてずれて表示されると思います。
      私の場合も同様でしたのでfunctions.phpに、
      「date_default_timezone_set( ‘Asia/Tokyo’ );」
      を記述することで回避していました。
      しかしそれも随分と前のことでしたので、今、改めて検索して調べてみると、その方法は止めた方が良いと言っているところもありますね。
      設定のタイムゾーンを東京にするだけで直ると書いているところもありますので、一度、確認してみてはいかがでしょうか。

      実のところ、あまりその辺りは考えていませんでしたが、それでうまくいかない方は多いのかもしれませんね。ちょっと考えてみた方が良いのかもしれません。

    • admin より:

      wordpress 初心者さん、こんにちは。
      実際に色々と試してみたところ、タイムゾーンを東京にセットしていれば投稿においての時間は正常になっているようです。
      しかし、カレンダーにおける時間は9時間ずれているので、プラグインの内部でこの時間差を修正するようにコードを変更しました。
      今、テストしていますので明日にはアップロードできるかと思います。
      自分では気づかなかったことを教えてくださったのかもしれませんね。ありがとうございました。

      • wordpress 初心者 より:

        こんばんは。

        昨晩、ファイルをダウンロードして、早速、前のファイルと差し替えてみました。
        カレンダーの現在日時は以前みたいに、
        functions.phpにdate_default_timezone_set( ‘Asia/Tokyo’ );を設定しなくても、夜の0:00を回ってから、ちゃんと切り替わる事が確認できました。
        これで、ブログにもきちんとしたカレンダーが設定できます。

        本当に助かりました。
        また、不具合あった時は、よろしくお願いいたします。

        ありがとうございました。

      • admin より:

        こんにちは。
        v2.3には、あらかじめdata_default_timezoneをsetしてある場合にバグが出てしまいます。v2.4をお使いください。簡単なケアレスミスをしてしまいました。
        それにしてもこの件においては全く頭にありませんでしたね。
        また、なにかお気づきのことなどありましたら教えてください。

Leave a Reply!

JavaScript is necessary to send a comment.
You can edit and delete your comment if you input a edit key.
Edit key is necessary for attesting you when you edit and delete it.
The tag of HTML cannot be used in comment.
When you comment for the first time, it is displayed after the approval of the administrator.
Because I cannot speak English so much, it takes time to answer.
Required fields are marked *.

※Please enter more than 5 characters only alphabets.
※Edit or delete are possible for 2000 days after approval.

*

♠Simplistic Comment User Editable v4.0

♠When visitors leave comments on the site this site collect the data shown in the comments form, and also the visitor’s IP address and browser user agent string to help spam detection.
♠This site does not use cookie when visitors leave comments and commenter edit comment.
♠This site uses Akismet to reduce spam. Learn how your comment data is processed.

Comments feed

Trackback URL : https://strix.main.jp/wp-trackback.php?p=47126

Sanbanse Funabashi

Top

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