PHP
JavaScript
WordPress
HTML5
jQuery

【爆速】WordPressで始めるpjax入門

AWS+KUSANAGIでWordPressサイトを運用しており、その時点でかなり速かったのですが、さらに高速化するべくpjax(barba.js)を導入しました。
導入後、ページ遷移体感速度が5000兆倍になったので導入方法をシェアします。

barba.jsとは

pjax(非同期画面遷移)を使いやすくしたjsライブラリ。
これを使うとページ遷移時にコンテンツ部分のみを読み込むことができ、
まるでネイティブアプリを使っているようなページ遷移を体験できます。
また、animation、prefetch、cache等に対応しています。

デモサイト

barba.jsを導入しているサイトのご紹介。
Grid Demo(公式)
Next/Prev Demo(公式)
Circles Demo(公式)
Accueil | Effektiv, cabinet de recrutement(非公式)
Famiglia Cecchi | Official site(非公式)

導入手順

1. 必要なファイルの準備

必要なファイルは2つ。
barba.js本体とカスタム用のjsファイル。
今回本体はCDNで読み込みますので、まずはカスタム用のjsファイルを作成して、
WordPressで使用しているテーマディレクトリにブチ込んでください。

今回はbarba-custom.jsという名前で作成します。
アップロード先の例:wp-content/themes/yourtheme/js/barba-custom.js

2. jsファイルの読み込み

barba.js本体と先ほど作成したjsを読み込みます。
functions.phpに下記コードをコピペしてください。
※wp_enqueue_script()の第5引数をtrueにすると</body>タグの直前で読み込まれ、
falseにすると<head>タグ内で読み込みます。

function my_enqueue_scripts() {
   // barba.js本体の読み込み
   wp_enqueue_script(
      'barba',
      '//cdnjs.cloudflare.com/ajax/libs/barba.js/1.0.0/barba.min.js',
      array(),
      '1.0.0',
      true
   );
   // barbar-custom.jsの読み込み
   wp_enqueue_script(
      'barba-custom',
      get_template_directory_uri() . '/js/barba-custom.js',
      array(),
      false,
      true
   );
}
add_action( 'wp_enqueue_scripts', 'my_enqueue_scripts' );

※jQueryが読み込まれていない場合はjQueryも読み込んでください。

3. テーマファイルのHTML書き換え

書き換え対象ファイル例:
・home.php
・index.php
・single.php
・archive.php
・category.php
・tag.php
・page.php
・search.php

上記ファイルの非同期で読み込みたい部分(コンテンツ部分)を下記のタグで囲みます。
ヘッダー、サイドバー、フッターは基本的に固定になると思いますので、
それ以外の部分を下記タグで囲うを良いでしょう。

.php
<div id="barba-wrapper">
  <div class="barba-container">
    <!-- 動的コンテンツ -->
  </div>
</div>

home.phpの書き換え例

home.php
<?php get_header(); ?>

<div id="content" class="clearfix">
  <div id="contentInner">
    <div id="barba-wrapper"> <!-- ←追加した -->
      <div class="barba-container"> <!-- ←追加した -->
        <div class="main">
          <article>
            <div class="sidebar">
              <?php get_template_part('list'); ?>
              <?php get_template_part('pagenavi'); ?>
            </div>
          </article>
        </div>
      </div> <!-- ←追加した -->
    </div> <!-- ←追加した -->
  </div>
  <?php get_sidebar(); ?>
</div>

<?php get_footer(); ?>

書き換え対象ファイルは、ご自身でお使いのテーマやpjaxさせたいページに合わせて適宜変更してください。
※pjaxさせたくないリンクには.no-barbaを付けると無効化されます。

4. barba-custom.jsの編集

最後にbarba-custom.jsに下記コードをコピペしてbarba.jsを有効化しましょう。
ご自身の環境に合わせて適宜変更してください。
cacheはデフォルトで有効になっています。

barba-custom.js
// 現在と同じページのリンクをクリックした場合、リロードをしない設定(オプション)
// リロードしたい場合は削除してOKです。
var links = document.querySelectorAll('a[href]');
var cbk = function(e) {
 if(e.currentTarget.href === window.location.href) {
   e.preventDefault();
   e.stopPropagation();
 }
};
for(var i = 0; i < links.length; i++) {
  links[i].addEventListener('click', cbk);
}

/* 
* 遷移時に変更したい処理
* デフォルトではhead内のmetaタグは変わりません。(titleタグは変わります)
* また、barba-container内のjsは実行されないので個別に変更・実行したい処理をココに書きます。
*/
Barba.Dispatcher.on('newPageReady', function(currentStatus, oldStatus, barbaContainer, newPageRawHTML) {

   if ( Barba.HistoryManager.history.length === 1 ) {  // ファーストビュー
      return; // この時に更新は必要ありません
   }

   // jquery-pjaxから借りた
   var $newPageHead = $( '<head />' ).html(
      $.parseHTML(
         newPageRawHTML.match( /<head[^>]*>([\s\S.]*)<\/head>/i )[ 0 ],
         document,
         true
      )
   );
   // 変更したいタグ(ご自身の環境に合わせて適宜変更してください)
   var headTags = [
      "link[rel='canonical']",
      "link[rel='shortlink']",
      "link[rel='alternate']",
      "meta[name='description']",
      "meta[property^='og']",
      "meta[name^='twitter']",
      "meta[name='robots']"
   ].join( ',' );
   $('head').find(headTags).remove(); // タグを削除する
   $newPageHead.find(headTags).appendTo('head'); // タグを追加する

   // Analyticsにヒットを送信(Google Analyticsを導入している場合)
   if (typeof ga === 'function') {
      ga('send', 'pageview', location.pathname);
   }

   // 外部ファイルを任意の場所に追加して実行する(オプション)
   // 外部ファイルにdocument.write()が書かれていると、それは無視されますので正常に表示されません。
   var script = document.createElement('script');
   script.src = 'http://example.com/hoge.js';
   document.body.appendChild(script);

   // インラインに書いたjsを実行する(オプション)
   var temp = document.createElement('div');
   temp.innerHTML = newPageRawHTML;
   var hoge = temp.querySelector('.hoge script');
   if(hoge != null){
      eval(hoge.innerHTML);
   }

}); // End Dispatcher

// アニメーションの設定(フェードアウト→フェードイン)(オプション)
// 必要ない場合は削除してOKです。
var fadeTransition = Barba.BaseTransition.extend({
   start: function() {
      //startはトランジションが起動した直後の一番最初に呼び出される。

      //promise.allを使うと、配列で渡された処理が全て終わった後に.thenを実行。
      //この場合は.newContainerLOadingと.fadeOutが終わってから.thenが実行される。
      Promise
         .all([this.newContainerLoading, this.fadeOut()])
         .then(this.fadeIn.bind(this));
   }, // End start function

   fadeOut: function() {
      //古いページコンテンツに対して行う処理。
      //ここでは、animateを使って、fadeoutさせている。
      return $(this.oldContainer).animate({ opacity: 0 },{duration:'fast'}).promise();
   },

   fadeIn: function() {
      // topに移動(地味に重要)
      document.body.scrollTop = 0;

      //startに記述したallによって、fadeOutが終わったらこのfadeIn関数が呼び出されている。

      var _this = this;
      //ここでのnewContainerは、ajaxで読み込まれてきた新しい方の.barba-containerにあたる。
      var $el = $(this.newContainer);

      //opacity:0;になっていた古いbarba-containerをdisplay:none;に。
      //こちらおそらくfadeIn発動時古いbarba-containerの初期設定として。
      $(this.oldContainer).hide();
      //こちらも新しいbarba-containerの初期設定。
      //visiblityがあるのは、デフォルトではこれがhiddenになってるっぽいから。
      $el.css({
         visibility : 'visible',
         opacity : 0
      });

      $el.animate({opacity: 1}, 200, function() {
         //.done()をつけることで古いbarba-containerのDOMは削除され、transitionが終了する。
         _this.done();
      });
   }
}); // End BaseTransition

// returnに作ったトランジションを設定
Barba.Pjax.getTransition = function() {
   return fadeTransition;
};

// barba実行
$().ready(function(){
   Barba.Pjax.start();
   Barba.Prefetch.init(); // prefetchを有効化
});

参考記事・サイト

Barba.js
Barba.jsを使って、metaタグを動的に更新する方法
シームレスなページ遷移を!PJAXの実装に便利な軽量プラグイン Barba.js の使い方 | あらかぜ手帖
Scripts within container are not evaluated · Issue #32 · luruke/barba.js · GitHub
Google Analytics Issue · Issue #88 · luruke/barba.js · GitHub
Page reloaded · Issue #34 · luruke/barba.js · GitHub