Page No.1

WordPress のカレンダーを自作した独自関数 postcalendar に、新たに手を加えていくつか手直しをしてプラグインにしたものです。
リンクの出力に get_month_link() で得られたリンクを基本にしたものに変更して各パーマリンク設定に対して汎用性をもたせ、オプションを管理画面で設定出来るようにしてあります。そして WordPress の公式プラグインディレクトリに登録するということも目的の一つでした。

最初にリリースしたのが、2016年の5月。この記事の更新は 2023年1月15日。WordPressv6.1に、php においては v8.2 となっていて、それに合わせてこのプラグインも v7.0 へとアップデートさせました。カレンダー本体のプログラム自体も、v6.0 からの変更においても、速度アップを図って相当な部分に及んでいます。それゆえに、このページもそれにあわせて新規投稿しました。
それでは、機能的な事はというと。

  • 日曜、土曜、祭日及び独自の休日などのスタイル設定をするための class がそれぞれにつきます
  • その独自の休日のスタイル設定できる class は4種類
  • 日本語と英語表記が選択可能
  • 週の始めを日曜とするか月曜にするか設定可能
  • カレンダーの日付に表示できる投稿の post_type を選択できます。ただし、その場合はそのカスタム投稿用のテンプレートが必要になると思う
  • 各設定は管理画面にて設定することができ、テンプレートに記述した関数に直接引数を渡すことで指定することも可能
  • 月別アーカイブのリストも一緒に表示することが出来ます( プルダウン or 年別リスト )
  • カレンダーの表題に表示する文字列を指定することが可能
  • カレンダーの下部に表示したい文字列を指定することも可能
  • デフォルトで設定されている日本の祝祭日ではなく、独自の祝祭日リストにすることも可能
  • 一応、基本的なスタイルシートが付属。設定でロードさせないことが可能
  • カレンダーの内容に変化が無いと思われる場合は、高速化のためにキャッシュファイルからデータを読み出して表示
  • Gutenberg Block Editor 用の custom widget block を装備
  • カレンダーのレイアウトにこれまでの tablecss grid 用の div による生成の選択が可能

と、いったところ。
Gutenberg Block Editor などどんどんアップデートされているように、なかなか気が付かないところもあるようで、なにかあればコメントなどいだたけるとありがたいのです。
それでは、以下、そのコードとなりますね。

オプションのロード処理 ~ フックの登録

プログラムの冒頭部分は、使いまわしてきたオプションのロードに関する処理から。使いまわしてきたのには違いないけれど、今回のバージョンアップにおいてはこの部分も更新してます。いままでのは、速度を重視するあまり、オプションの項目に変更があった場合のチェックとしてオプションの数の違いしかチェックしていなかった。当然、数は同じでも項目の変更がある場合もあるわけで、まぁ、その点はオプションの変更をするのは自分だけだから、ということで良しとしてたわけです。

そこのところ、速度を重視しつつも、よくよく考えて不足がないようにアップデートさせたのが、この v7.0 のものとなります。

<?php
//delete_option('hldycls_pcldr_options');//既存のオプション値を強制的にデフォルトに戻す時使用

// クラスが定義済みか調べる
if ( ! class_exists( 'hldycls_post_calendar' ) ) {

    class hldycls_post_calendar {
    
        private $current;// データベースにすでに保存されているオプション値
        private $default;// デフォルトのオプション値
        private $ret_option;// 実際に使用する現在の有効なオプション値
        private $option_name;// オプションの名前
        private $version;
        private $call_count;// 同一ページ内でカレンダー生成関数が呼び出された回数
        private $call_bl_count;// 同一ページ内でカレンダーのブロックが呼び出された回数
        private $call_fs_flg;// 月別アーカイブ用のjavascriptをダブって出力させないためのフラグ
        private $styleflg;// デフォルトのスタイル設定それぞれのロードの設定のフラグを入れておく変数
    
    
        public function __construct() {
            $this->option_name = 'hldycls_pcldr_options';
            $this->version = '7.0';
            $this->call_count = 0;
            $this->call_bl_count = 0;
            $this->call_fs_flg = false;
            $this->styleflg =array();
            $this->load_option();
        }
    
        private function load_option() {
    
            // オプションのデフォルト値設定
            $this->default = array(
                'lang' => 'e', //日本語か英語表示かの指定 'j'か'e'、デフォルトは'e'で英語。
                'wf' => 's', // 週の始めを日曜か月曜かの指定 's'か'm'、デフォルトは's'で日曜。
                'capt' => '', // 表題のcaptionに表示する文字列。
                'footer' => '', // 下部に表示する文字列。
                'closewd' => '', // 独自休日を曜日で指定する場合。毎週水曜日だとか。1が日曜、7が土曜で1~7までの数字で指定。複数ももちろん可でその場合は配列で指定。一つの時は配列でなくてもOK。
                'closel' => '', // 独自休日を日にちで指定。年月日8ケタ、月日4ケタないし3ケタ、日にち2ケタ以下で指定。日にちだけなら毎月に設定され、月日なら毎年。
                'anniver' => '', // それらとは別に特別な日を設定するときはanniverを使用し、これは毎年の事と考えて4ケタもしくは3ケタのみ使用可
                'monthly' => '1', // 月別アーカイブのリストも表示させたい場合は1を指定。'0'で非表示。デフォルトは1で表示。
                'postype' => 'post', // カレンダーに表示させる投稿の投稿タイプ、デフォルトは'post'。
                'loadstyle' => '1', //カレンダー用のデフォルトスタイルシートのロード。デフォルトは'1'でロードする、'0'でロードしない。
                'acvheader' => '', //月別アーカイブリストのヘッダー文字指定。
                'acvoptorlist'=>'1',//月別アーカイブリスト表示がプルダウンかリストか、デフォルトは'1'でプルダウン、'0'でリスト表示。
                'loadacvlststyle' => '1', //月別アーカイブのリスト表示用のデフォルトスタイルシートのロード。デフォルトは'1'でロードする、'0'でロードしない。
                'daypostlink' => '0',// 投稿がある日にオンマウスで表示させるのはツールチップかその投稿へのリンクか。デフォルトは'0'でツールチップ、'1'で投稿へのリンク。
                'dplinkstyle' => '0',// 投稿がある日にオンマウスで表示させる投稿へのリンクのデフォルトのスタイルをヘッダーに排出する。デフォルトは'0'で排出しない、'1'で排出する。
                'parentstyle' => '',// 親div id="wp-calendar" にインラインで書き出すスタイル
                'colorstyle' => '',// 日土休日それぞれのスタイル設定。基本パターンは'曜日-文字色-背景色'。例、日曜なら'n-white-#ff0000'でそれぞれの指定は,で区切ってつなげる。n:日、d:土、w:closewd、l:closel、a:anniver、v:lanniver。
                'myholidays' => '',// デフォルトで設定されている日本の祝祭日ではなく、独自の祝祭日だけを表示する場合にその日付を','で区切ったリストにして入力。デフォルトは空文字。
                'adddeldays' => '',// デフォルトで設定されている祝祭日リストに加える、または削除する日付。
                'en_cache' => '1',// cache設定。'0'でdisable。ここで指定した数字がキャッシュファイル名の末尾に付加される。テンプレートにおいて引数でこのオプション値と違う数値を指定することで別のキャッシュファイルを設定できる。
                'en_gutenblock' => '0',// gutenberg block editor での custom widget block の登録、1:enable、0:disable
                'en_grid' => '0',// '0':table、'1':grid -> grid default style: display:grid;grid-template-columns:repeat( 7, 1fr );text-align:center;',
            );
            $this->current = get_option( $this->option_name );
    
            if ( false === $this->current ) {//初使用の時などオプションが設定されていない時
    
                update_option( $this->option_name, $this->default );//デフォルトでオプション設定
                $this->ret_option = $this->default;
            } else {
    
                // すでに保存してあるオプション値が存在する場合
                // デフォルトと既存値で共通のキーだけからなる配列を array_intersect_key() で取得し、
                // それら3つのそれぞれの要素の数が同じならば、オプション項目に変更は無い
                $deff = array_intersect_key( $this->default, $this->current );
                $countary = array( count ( $this->default ) , count ( $this->current ) , count ( $deff ) );
    
                if ( 1 !== count ( array_unique( $countary ) ) ) {
                    foreach ( $this->current as $key => $val ) {
                        // デフォルトオプションに存在するキーの要素だけ保存されている値で上書き。
                        if ( isset ( $this->default[ $key ] ) ) {
                            $this->default[ $key ] = $val;
                        }
                    }
                    update_option( $this->option_name, $this->default );
                    $this->ret_option = $this->default;
    
                } else {
                    $this->ret_option = $this->current;
                }
            }
    
            $stylebit = 0;// bit flg 0b00000
            $styleary = array();
    
            // 下の foreach で key の値でビットを左シフトした後、flg と bit or させる
            // if 文をなるべくシンプルにするために bit を使うため
            $styleary[] = $this->ret_option['monthly'];// 0b0001
            $styleary[] = $this->ret_option['loadacvlststyle'];// 0b0010
            $styleary[] = $this->ret_option['daypostlink'];// 0b0100
            $styleary[] = $this->ret_option['dplinkstyle'];// 0b1000
    
            foreach ( $styleary as $key => $val ) {
                $tmp = ( int ) $val << $key;
                $stylebit = $stylebit | $tmp;
            }
    
            $this->styleflg['daypostlink'] = 0b1100 === ( $stylebit & 0b1100 );// 日付オンマウスで投稿へのリンクを表示で、デフォルトスタイルを書き出す
            $this->styleflg['montharv'] = 0b11 === ( $stylebit & 0b11);// true:月別アーカイブを表示し、スタイルシートをロード
    
            if ( '1' === $this->ret_option['loadstyle'] ) {
                add_action( 'wp_enqueue_scripts', array( $this, 'hldycls_pcldr_style' ) );
            }
    
            // bit を使わない場合の if 文はこうなる -> if ( ( '1' === $this->ret_option['daypostlink'] and '1' === $this->ret_option['dplinkstyle'] ) or ( '1' === $this->ret_option['monthly'] and '0' === $this->ret_option['acvoptorlist'] and '1' === $this->ret_option['loadacvlststyle'] ) ){
            if ( $this->styleflg['daypostlink'] or $this->styleflg['montharv'] ) {
                //↓サイト読み込み時に投稿へのリンクのためのスタイルを書き出すためにwp_headに登録
                add_action( 'wp_head', array( $this, 'hldycls_pcldr_daylink_style' ) );
            }
    
            if ( $this->ret_option['colorstyle'] ) {
                //↓サイト読み込み時に投稿へのリンクのためのスタイルを書き出すためにwp_headに登録
                add_action( 'wp_head', array( $this, 'hldycls_pcldr_color_style' ) );
                // 管理画面における block 用のスタイルの書き出しの登録
                add_action( 'admin_head-post.php', array( $this, 'hldycls_pcldr_color_style' ) );
                add_action( 'admin_head-widgets.php', array( $this, 'hldycls_pcldr_color_style' ) );
            }
   
            // 投稿が公開された時に、キャッシュファイルを消去する関数をアクションフックに登録
            add_action( 'publish_post', array( $this, 'save_del_cache' ) );
    
            if ( '1' === $this->ret_option['en_gutenblock'] ) {
                //Gutenberg用custom blockを登録するための関数の登録
                add_action( 'init', array( $this, 'gb_register_block' ) );
            }
        }// ここまでload_option()
	// ↓class続く
?>
PHP
CopyExpand

Gutenberg Block Editor 用の block の登録

そして、Gutenberg custom block の登録、スタイルの読み込みの登録などが続き・・・。
このブロック登録の部分はほとんど変更していない。register_block_type において api version = 2 の指定をしたぐらい。だけれど、server side render のブロックにおいてはあまり関係ないのかもしれない。

<?php
	// ↓class続き
	// block を登録するためのjs ファイルとそのblock 用のスタイルシートの登録、そしてphp においてのblock のregister( 登録 )
	public function gb_register_block() {
		if ( ! function_exists( 'register_block_type' ) ) {
			// Gutenberg が有効でない場合は何もしない
			return;
		}

		wp_register_script(
			'hldycls-pcldr-01',
			plugins_url( 'hldycls_gb.js', __FILE__ ),
			array( 'wp-blocks', 'wp-block-editor', 'wp-element', 'wp-components', 'wp-server-side-render' ),
			filemtime( plugin_dir_path( __FILE__ ) . 'hldycls_gb.js' )
		);

        wp_register_style(
            'hldycls-editor-style',
            plugins_url( 'hldycls_pcldr_gb.css', __FILE__ ),
            array( 'wp-edit-blocks' ),
            filemtime( plugin_dir_path( __FILE__ ) . 'hldycls_pcldr_gb.css' )
        );

		// namespace /block-name , namespace: spcific unique, both only use lowercase alphanumeric characters or dashes
		register_block_type( 'hldycls-pcldr/post-calendar',			
			array(
				'api_version' => 2,
				'editor_script' => 'hldycls-pcldr-01',
				'editor_style' => 'hldycls-editor-style',
				'render_callback' => array( $this, 'hldyclspcldr_render_callback' ),
				'attributes' => array(
					'prtwidth' => array( 'type' => 'string', 'default' => '100%' ),
					'lang' => array( 'type' => 'string' ),
					'wf' => array( 'type' => 'string' ),
					'capt' => array( 'type' => 'string' ),
					'footer' => array( 'type' => 'string' ),
					'closewd' => array( 'type' => 'string' ),
					'closel' => array( 'type' => 'string' ),
					'anniver' => array( 'type' => 'string' ),
					'monthly' => array( 'type' => 'string' ),
					'postype' => array( 'type' => 'string' ),
					'acvheader' => array( 'type' => 'string' ),
					'acvoptorlist' => array( 'type' => 'string' ),
					'daypostlink' => array( 'type' => 'string' ),
					'myholidays' => array( 'type' => 'string' ),
					'adddeldays' => array( 'type' => 'string' ),
					'en_cache' => array( 'type' => 'string' ),
				)
			)
		);
	}
	
    // server side render によるblock なので、server 側からカレンダーのデータを取得するcallback 関数
	public function hldyclspcldr_render_callback( $attributes ){
		$params = $this->ret_option;

		++$this->call_bl_count;
		if ( 1 === $this->call_bl_count ) {
			$idnum = '';
		} else {
			$idnum = '-' . ( string ) $this->call_bl_count;
		}

		foreach ( $attributes as $key => $val ) {
			if ( null !== $val ) {
				$params[ $key ] = $val;
			}
		}

		$prtwidth = '';
		if ( isset( $params['prtwidth'] ) ) {
			$prtwidth = ' style="width:' . esc_attr( $params['prtwidth'] ) . ';"';
		}
		$calendar = $this->holiday_class_post_calendar( $params );
		$ret_cont = '<div id="hldyclspcldr' . $idnum . '"' . $prtwidth . '>' . $calendar . '</div>'; 

		return $ret_cont;
	}
?>
PHP
CopyExpand

スタイル設定などの登録

<?php
	// ↓class続き

	// サイト読み込み時にオプション指定のスタイルシートを登録する関数。
	// テンプレートに直接記述してスタイルシートを登録することも可。
	public function hldycls_pcldr_style() {
		if ( '1' === $this->ret_option['en_grid'] ) {
			wp_enqueue_style( 'hldycls_pcldr_style', plugins_url( 'hldycls_pcldr_grid.css', __FILE__ ), false, date( 'YmdHis', filemtime(plugin_dir_path( __FILE__ ) . 'hldycls_pcldr_grid.css' ) ) );
		} else {
			wp_enqueue_style( 'hldycls_pcldr_style', plugins_url( 'hldycls_pcldr.css', __FILE__ ), false, date( 'YmdHis', filemtime(plugin_dir_path( __FILE__ ) . 'hldycls_pcldr.css' ) ) );
		}
	}

	/*
	投稿がある日にオンマウスでの表示で、投稿へのリンクを選択している場合、
	月別アーカイブでリスト表示を選択している場合、
	サイト読み込み時にそのスタイルをヘッダーに書き出す関数。
	*/
	public function hldycls_pcldr_daylink_style() {

		if ( $this->styleflg['daypostlink'] ) {
?>
	<!-- plugin Holiday Class Post Calendar day-post links style -->
	<style type="text/css">
		.daychildren{display:block;position:absolute;width:150px;top:15px;right:-10px;padding:2px;text-align:left;font-size:1.1em;visibility:hidden;opacity:0;background-color:#ffffff;border-radius:3px;z-index:10;}
		.daychildren a{color:#0000ff;border-bottom:dotted 1px red;}
		.daychildren:before{content:"";display:block;position:absolute;top:-20px;left:50%;width:0px;height:0px;border-top: 10px solid transparent;border-right: 0px solid;border-bottom: 10px solid #ffffff;border-left: 20px solid transparent;}
		<?php if ( '1' === $this->ret_option['en_grid'] ) : ?>
		[data-post]{position:relative;}
		[data-post]:hover > .daychildren{animation:openlink 0.4s;animation-delay:0.5s;animation-fill-mode:both;}
		<?php else : ?>
		:is( div, table )[id*="wp-calendar"] :is( tbody td, th ){position:relative;text-align:center;}
		:is( div, table )[id*="wp-calendar"] td:hover > .daychildren{animation:openlink 0.4s;animation-delay:0.5s;animation-fill-mode:both;}
		<?php endif; ?>
		@keyframes openlink{from{ visibility:hidden; opacity: 0;}5% { visibility:visible; opacity: 0; }to{ visibility:visible;opacity:1;}}
		.daychildrenmark:before{content:"♦";}
	</style>
<?php
		}
		if ( $this->styleflg['montharv'] ) {
?>
            <!-- plugin Holiday Class Post Calendar archive-list links style -->
            <style type="text/css" id="acvlststyle">
                .mlchildren{display:none;}
                .arcyear > input{display:none;}
                .arcyear:hover{cursor:pointer;color:#fe56aa;}
                input[name*="chlbis-"]:checked ~ .mlchildren{display:block;}
                .mlchildren li a:hover{color:#fe56aa;}
            </style>
<?php
		}
	}

	// 日曜、土曜、各休日の文字色と背景色のスタイル設定ををヘッダーに書き出す関数。
	public function hldycls_pcldr_color_style() {
		$colorstyle = array();
		$styleoption = wp_check_invalid_utf8( $this->ret_option['colorstyle'] );
		$pattern = '/[&<>\'"}{]/';
		$styleoption = preg_replace( $pattern, '', $styleoption );
		$classname = array( 't'=>'today', 'n'=>'nitiyou', 'd'=>'doyou', 'w'=>'closewd', 'l'=>'closedy', 'a'=>'anniversary', 'v'=>'lanniversary' );
		$colorstyle = explode ( '_', $styleoption );
		if ( '0' === $this->ret_option['en_grid'] ) {
			$parent = 'table ';
		} else {
			$parent = '.cal-body ';
		}
		$stylestr = array();
		foreach ( $colorstyle as $val ) {
			$eachcolor = explode( '^', $val );
			if ( 5 === count( $eachcolor ) ) {
				if ( isset ( $classname[ $eachcolor[0] ] ) ) {
					if ( 't' === $eachcolor[0] ) {
						$stylestr[] = '#';
					} else {
						$stylestr[] = $parent . '.';
					}
					$stylestr[] = $classname[ $eachcolor[0] ] . '{';
					if ( $eachcolor[1] ) {
						$stylestr[] = 'color:' . $eachcolor[1] . ';';
					}
					if ( $eachcolor[2] ) {
						$stylestr[] = 'background-color:' . $eachcolor[2] . ';';
					}
					if ( $eachcolor[3] ) {
						$stylestr[] = 'border:solid 1px ' . $eachcolor[3] . ';';
					}
					if ( $eachcolor[4] ) {
						$stylestr[] = 'border-radius:' . $eachcolor[4] . ';';
					}
					$stylestr[] = '}';
				}
			}
		}
		if ( $stylestr ) {
			echo "<!--plugin Holiday Class Post Calendar holiday style-->\n<style type=\"text/css\">\n" . implode ( '', $stylestr ) . "</style>\n";
		}
	}

    // 月別アーカイブにプルダウンを選択している場合に必要となる javascript を返す。
	public function footer_script() {
		if ( $this->call_count > 0 && ! $this->call_fs_flg ) {

			$this->call_fs_flg = true;

			// Content Policy Security が設定してある場合、nonce が設定してあるなら inline script を作動させるためには、その値が必要
			// headers_list() は応答header のリストで配列になっており key はただの数字
			$cps = headers_list();
			$cpsnonce = '';
			foreach ( $cps as $val ) {
				if ( false !== strpos( $val, 'Content-Security-Policy' ) ) {
					$pattern = '/\'nonce-([0-9a-fA-F].*?)\'/';
					if ( preg_match ( $pattern, $val, $matches ) ) {
						$cpsnonce = ' nonce="' . $matches[1] . '"';
					}
					break;
				}
			}
			return PHP_EOL . '<!--plugin Holiday Class Post Calendar monthly archive pulldown script --><script' . $cpsnonce . '>window.addEventListener("load", function() {const doc=document;for(let i=0;i<5;++i){const target ="archive-dropdown"+(i?"-"+i:"");if(null!==doc.getElementById(target)){const arcvdrpdwn=doc.getElementById(target);arcvdrpdwn.onchange=function(){doc.location.href=arcvdrpdwn.options[arcvdrpdwn.selectedIndex].value;}}}})</script>' . PHP_EOL;
		}
	}
	// ↓class続く
?>
PHP
CopyExpand

管理画面にオプション設定ページを表示するための処理など

管理画面にオプション設定ページを表示するために登録する処理が続きます。これらも使いまわしている自分にとってはお馴染みの処理となります。管理画面のオプション設定ページに実際に表示させるための html は、必要の無い時に少しでも処理が軽くなるのではないかと思い別ファイルにしています。

<?php
	// ↓class続き

	//↓ここから管理画面のメニューにオプション設定ページを登録する処理
	public function hldycls_pcldr_add_menu() {
		add_options_page( 'Holiday-class Post Calendar Option', 'Holiday-class Post Calendar Option', 'administrator', 'hldycls_pcldr_plugin_options', array( $this, 'hldycls_pcldr_page_output' ) );
		add_action( 'admin_init', array( $this, 'register_hldycls_pcldr_settings' ) );
	}
	 
	public function register_hldycls_pcldr_settings() {
		register_setting( 'hldycls_pcldr-settings-group', $this->option_name );
	}
	
	public function hldycls_pcldr_page_output() {
?>
	<div class="wrap">
		<h2>Holiday-Class Post Calendar v<?php echo $this->version; ?> option</h2>
		<h3>《 Option Config 》</h3>
		<form method="post" action="options.php">
<?php
				settings_fields( 'hldycls_pcldr-settings-group' );
				do_settings_sections( 'hldycls_pcldr-settings-group' );

                // 管理画面のオプション設定ページに実際に表示させる部分は別ファイルにあり、そのファイルの読み込み
				include_once 'explain.php';
	}
	//↑ここまで
	// ↓class続く
?>
PHP
CopyExpand

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=73673

Sanbanse Funabashi

Top

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