wordpressプラグインでレンダリングを妨げるリソースの除外

wordpressに限らず、ウェブサイトであればcssやjavascriptを使っているのが普通です。また、これらの読み込みコードをHTMLのHEADタグ内に記述しているケースもよくあります。レンダリングを妨げるリソースとは基本的にcssやjavascriptのことを言います。

そもそもレンダリングとは?

数値データやソースコードなど、人間には分かりにくい情報をプログラムやソフトを用いて人間に分かりやすい形に変換し、可視化すること、或いはその時に行われる計算処理のことを言います。

「レンダリングを妨げるリソースの除外」という表現が使われる場合、一般にはHTMLコードをブラウザなどに表示させる処理に対してレンダリングと呼んでいます。

従来、レンダリングといえば何らかの表現や描画を指していました。次第にコンピュータグラフィックスの領域でもレンダリングという言葉が使われるようになり、今ではソースコードからブラウザに画像や文字などを表示させるケースでよく使われています。

リソースとは

本来は資源のことですが、wordpressをはじめとするウェブページでは一般にプログラムのことを指します。動作させるにあたって、必要な要素と考えるのが分かりやすいです。「レンダリングを妨げるリソースの除外」という観点だと、cssやjavascriptのことを指します。

wordpressでなぜレンダリングを妨げられるのか

これもwordpressに限ったことではありませんが、HTMLのHEADタグ内にcssやjavascriptが記述されていると、ブラウザはこれらのファイルを最初から最後まで読み込まないと、次の処理に移行できません。つまり、BODYタグに向かってレンダリングができないため、本文の表示に時間がかかって空白状態が一時的に発生するわけです。これがレンダリングを妨げる原因となっています。

かつてのwordpressでは、HEADタグ内にcssやjavascriptの読み込みコードが多かったように記憶しています。最近ではあえてjavascriptをBODYの閉じタグ付近に移動させているテーマも散見されますが。しかし、現在でもwordpressのシステム関連のアップデートによって使うことのないコードが増えていたりします。

wordpressのプラグイン化で対応

まず、適当な名前をつけたphpファイルに以下のコードを記述します。Plugin Nameのrendering_block_wordpressも適当で構いません。ただし、この記述がないとwordpressにプラグインとして認識されませんので注意して下さい。

<?php
/*
Plugin Name: rendering_block_wordpress
*/
?>

次に下のコードを上のファイルのphpタグ内に記述します。そして、このwordpressプラグインファイルは更に適当な名前をつけたフォルダに入れ、「wp-content/plugins/」のディレクトリへFTPなどでアップロードして下さい。

wordpressの管理画面からプラグインを有効化すると、HEADタグ内にあるcssとjavascriptの読み込みコードが丸ごと下に移動します。また、プラグイン化しなくてもwordpressテーマの「functions.php」に記述しても動作します。ただ、マルチサイトで子サイトごとにテーマを変えてるケースだと、プラグイン化したほうが管理が楽です。

このコードは、wordpressの「init」アクションを使っていますが、「after_setup_theme」でも同様の結果となります。「init」アクションより先に行わなければならない処理では「after_setup_theme」を使います。

また、このコードはページとして出力される前にHTMLの開始タグから終了タグの間で処理を行っています。そのため、wordpressが用意している「the_content」フックなどで再度処理しようとしてもできません。処理する場合は、下のOutputCallback関数内で完了させます。

wordpressの記事がきちんと表示されない場合、レンダリングの妨げになっていても下に移動させてはいけないcssやjqueryなどがあるということになります。その時は下に移動させたものをwordpressのテーマヘッダーからHEAD内に一つずつ入れてきちんと表示されるかどうか確認し、特定できたらforeach内でif文による条件分岐で処理して下さい。判定方法はURLの一部、もしくは全部を指定してもキャッチできると思います。該当するものをstr_replaceで削除せず、配列に代入しなければHEAD内に残って下に移動しません。

その他、「current_user_can( 'administrator'」は、wordpressの管理者だけが取得したcssとjavascriptを確認できるようにする条件分岐です。wordpressに管理者権限でログインしていない人には見えません。つまり、外部からアクセスしてきた人には見えないということです。表示させる時は、コメントアウトを外してください。

add_action('init', function (){ob_start('OutputCallback');});
add_action('shutdown', function (){
if(ob_get_contents() || ob_get_length()){
ob_end_flush();
}
});
function OutputCallback($output_wordpress){
if(is_single() || is_home()){
preg_match_all('`<[^>]+(text/css)[^>]+\/>|<[^>]+(text/javascript)[^>]+><\/script>`su', $output_wordpress, $match);
foreach($match[0] as $key => $val){
$output_wordpress=str_replace($val, '', $output_wordpress);
$cssjs_display.=strtr($val, ['<'=>'&#60;','>'=>'&#62;']).'<br>';
$cssjs[]=$val;
}
$output_wordpress=preg_replace('/(<\/body>)/', implode("\r\n",$cssjs)."\r\n$1", $output_wordpress);
}
/*
if(current_user_can( 'administrator')){
$output_wordpress=preg_replace('/(<body.*?>)/', "$1\r\n".$cssjs_display, $output_wordpress);
}
*/
return $output_wordpress;
}

wordpressでレンダリングを妨げるリソースの除外をするための正規表現

上記、wordpressプラグインのpreg_match_all関数で使っている「`」はデリミタといいます。「`<[^>]+(text/css)[^>]+\/>|<[^>]+(text/javascript)[^>]+><\/script>`」パターンの両側についてます。通常はスラッシュを用いますが、URLにはスラッシュが含まれるため、ほとんど使うことのない記号をわざと指定しています。「|」のパイプで区切っていますが、左側がcssを取り出すためのもので右側がjavascriptを取得するための正規表現です。後者が不要であればパイプを含めて閉じカッコまで削除してください。その反対も同じです。

wordpressのヘッダーから個別に取得したい場合は、preg_match_allの上記パターンで正規表現を指定します。スタイルシートの場合は、wordpressだと「id」がついてますので、それを用いても良いと思います。

wordpressでも多用する正規表現

  1. [a-zA-Z]は大小の英文字
  2. [0-9]は一桁の数字
  3. [0-9a-zA-Z]+は英数字で続く
  4. \dは数字
  5. \sは空白
  6. . は 任意の1文字
  7. *は直前もじの0回以上の繰り返し
  8. +は直前もじの1回以上の繰り返し
  9. *?は直前もじの0回以上の繰り返しで最短一致
  10. {min,max}は直前もじのmin以上max以下の繰り返し
  11. [ ~ ]はカッコ内のどれか一文字
  12. [^ ~ ]はカッコ内にいずれも無い一文字
  13. ^は行頭
  14. $はm修飾子をつけて行末、つけないと終端にもマッチ

wordpressでも多用するかも知れない特殊な正規表現

  1. a(?=b)は、aの後にbが続くaに一致。肯定先読み
  2. a(?!=b)は、aの後にbが続かないaに一致。否定先読み
  3. (?<=a)bは、aの後にbが続くbに一致。肯定後読み
  4. (?<!a)bは、aの後にbが続かないbに一致。否定後読み
  5. (?> ) は一回取ったサブパターンを再び取らないようにする。
  6. (?R)は、任意の深さのネストを 処理。グループ化したメタ文字のパイプ(or)で調べる。

ネスト

「x」は、エスケープするか文字クラスの内部を除き、パターンの空白文字を無視する修飾子。

$p="(aa(bb(ab(cd)ef)cc)dd)";
// $matches[0]に全文が入る。$matches[1]にddが入る。
echo preg_match("/ \( ( (?>[^()]+) | (?R) )* \)/x",$p,$matches);
// $matches[0][0]に全文が入る。$matches[0][0]にddが入る。
preg_match_all("/\(((?>[^()]+)|(?R))*\)/",$p,$matches);
// $1がddに置換される。
echo preg_replace("/\(((?>[^()]+)|(?R))*\)/", '$1', $p);

まとめ

wordpressでレンダリングを妨げるリソースの除外って、マルチサイト以外はプラグインを使うまでもなかったりします。上記のレンダリング速度の改善方法は、かなり強引かも知れません。ただ、プログラムの理屈が分かればwordpressの突然変異にも耐えられると思います。正規表現を変更したら良いだけですから。ただ、一般的な方法を求めるのであれば、wordpressのwp_print_stylesやwp_enqueue_scriptsフックなどを利用したほうが良いかも知れません。