Page No.2

と、いうことで一度作ってしまったら、そんなに変更することもないであろう navi menu はキャシュ化してしまおう、というもくろみ。
そのもくろみとしては、

  • ページ読み込みの際に、キャッシュファイルがあれば、それをロードして表示。
  • 無ければ wp_nav_menu() を実行させて navi menu を生成。
  • その時、javascriptAjax にてキャッシュファイルを作るためのフラグとなる id=”make-cache” の input 要素も生成。
  • その id=”make-cache” の input type=”hidden” の要素が存在する場合、javascript のロードとともに Ajax にてキャッシュファイルを作成。
  • navi menu の内容が更新されたときは、taxonomy が保存されるときのフック、saved_term を使って対象のキャッシュファイルを削除する。

てな、具合でよかろうか。
キャッシュファイルが存在するときに、それをロードして表示するのは、header.php テンプレートにて。footer でもほぼ同じことをすることになるので、functions.php に関数化してもいいのだけれど。

<nav id="nav-a">
<?php
    // ACCLANG は自前の定数で言語指定、"ja" or "en" or "zh"
    $cache_file = $stylesheet_directory . '/cache/cache_nav_header-' . ACCLANG . '.php';

    if ( file_exists( $cache_file ) ) {
        echo '<!-- use cached data -->';
        include_once $cache_file;
    } else {
        $navi_loca = array(
            'theme_location' => 'header-navi-' . ACCLANG,
            // 'container' => false,
        );
        wp_nav_menu( $navi_loca );

      //  javascript で表示している言語がわかるように value に言語指定を仕込んでおく 
        echo '<input type="hidden" id="make-hnav-cache" value="' . ACCLANG . '">';
    }
?>
</nav>
PHP
CopyExpand

そして、キャッシュファイルが存在しないときに、id=”make-hnav-cache” の input 要素の存在をトリガーとして起動するキャッシュファイル作成の Ajaxjavascript。自分の場合、当たり前のように使う Ajax は関数にして持ち歩いている。あと、いちいち getElementById も打つのが面倒なので、それも関数にして持ち歩いている。と、いうことでその javascript

function ajax_callback( url, str, callback, ope, dir ) {

	if ( dir && url ) {
		const operation = 'undefined' === typeof ope ? 'POST' : ope,
			tmpstr = 'undefined' === typeof str ? null : str,
			tarurl = 'wp' === url ?  location.origin + '/wp/wp-admin/admin-ajax.php' : url,
			strsend = Array.isArray( tmpstr ) ? tmpstr.join( '&' ) : tmpstr;

		const req=new XMLHttpRequest();

		req.onreadystatechange = function() {
			let result = '';
	
			if (req.readyState == 4) { // 通信の完了時
				if (req.status == 200) { // 通信の成功時
					result = req.responseText;

					callback( result );
				
				} else {
					console.log( 'error : disabled send' + tarurl);
				}
			}
		}

		req.open( operation, tarurl, true );
		if ( 'POST' === operation ) {
			req.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded' );
		}
		req.send( strsend );

	} else {
		console.log( 'error : no data url' );
	}
}

// 指定された id の要素を返す関数。ただ、getElementById を打つのが面倒なだけ
function Gi( name ) {
	let ans = null;

	ans = document.getElementById( name );
	return ans;
}

window.addEventListener( 'load', () => {

	if ( null !== Gi( 'make-hnav-cache' ) ) {
		const tarlang = Gi( 'make-hnav-cache' ).value,
			parcls = 'menu-header-' + tarlang + '-container',// 親要素の class
			navpar = doc.getElementsByClassName( parcls )[0],// 親要素を取得
			navhtml = navpar.innerHTML,// 親要素の全ての子要素を取得->navi menu
			// action->Ajax を受ける php 側のフックにつける名称
			strsend = 'action=savenavcache&dataid=header-' + tarlang + '&data=' + navhtml;

		ajax_callback( 'wp', strsend, function( result ) {
			console.log( result );
		}, 'POST', 1 );
	}

	if ( null !== Gi( 'make-fnav-cache' ) ) {
		const tarlang = Gi( 'make-fnav-cache' ).value,
			parcls = 'menu-footer-' + tarlang + '-container',
			navpar = doc.getElementsByClassName( parcls )[0],
			navhtml = navpar.innerHTML,
			strsend = 'action=savenavcache&dataid=footer-' + tarlang + '&data=' + navhtml;

		ajax_callback( 'wp', strsend, function( result ) {
			console.log( result );
		}, 'POST', 1 );
	}
});// onload
JavaScript
CopyExpand

そして、Ajax で受ける側の phpWordPress の作法にしたがって functions.php に関数として書き、wp_ajax_ のフックを使って登録する。

<?php
    function savenavcache () {

        $dataid = isset( $_POST['dataid'] ) ? $_POST['dataid'] : '';
        $data = isset( $_POST['data'] ) ? $_POST['data'] : '';

        // post で送信された html はエスケープされているのでそれを元に戻す
        $data = str_replace( array( '\"', '\\\'', '\\\\' ), array( '"', '\'', '\\' ), $data );

        if ( $dataid and $data ) {

            $cache_file = get_stylesheet_directory() . '/cache/cache_nav_' . $dataid . '.php';

            $res = file_put_contents( $cache_file, $data, LOCK_EX );

            if ( $res ) {
                echo 'success save ' . $dataid . ' cache files.';
            } else {
                echo 'error:disable cache save:' . $dataid;
            }
        } else {
            echo 'error:no send data';
        }

        exit;
    }
    add_action( 'wp_ajax_savenavcache', 'savenavcache' );
    add_action( 'wp_ajax_nopriv_savenavcache', 'savenavcache' );
?>
PHP
CopyExpand

navi menu が変更され更新されたときは、キャッシュファイルも新しいものにバージョンアップしなければならない。前述してあるが、navi menu は一種の分類のように扱われているので、そのデータが更新され保存されるときは、term 同様に save_term action-hook が利用可能であり、そのフックを使って対象のキャッシュファイルが存在しているならば、それを消去する。キャッシュファイルが存在しなければ、その後ページにアクセスがあったときに、新しいキャッシュファイルが作成される。

<?php
    function update_nav_delete_cache( $term_id, $tt_id, $taxonomy ) {
        $term = get_term( $term_id, $taxonomy );

        $cache_file = get_stylesheet_directory() . '/cache/cache_nav_' . $term->name . '.php';

        if ( file_exists( $cache_file ) ) {
            unlink( $cache_file );
        }
    }
    add_action( 'saved_term', 'update_nav_delete_cache', 10, 3 );
?>
PHP
CopyExpand

以上である。
やはりキャッシュファイルの方が、軽く動いている感じがする。

Sanbanse Funabashi

Top

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