PWA for WordPress

【コピペでOK】WordPressをPWA対応させる方法(プラグインなし)

このブログ(WordPress)をPWAに対応させたので必要なファイルや導入手順を解説します。

PWA TEST

必要なファイル

PWAに必要なファイルは大きく分けて以下の3つ。

  • アイコン
  • manifest.json
  • service-worker.js

どれも記述するコード量は多くありませんので次以上の項目で詳しく説明していきます。

アイコンの作成

まず、ホームに追加した時に表示されるアイコンファイルを作成しましょう。
必須サイズは192x192xと512x512pxの2つになります。
このブログではpwa_192.pngpwa_512.pngというファイルを作成しました。

作成したら任意の名前をつけて、ドキュメントルート(wp-settings.phpなどがある所)にアップしてください。

manifest.json

次にmanifest.jsonというjsonファイルを作成します。
名前は任意のものでも構いません。

このファイルでは、アプリ名や起動時に表示するURLなどを設定します。
下記にこのブログのものを記載しますのでコピペ・改変してお使いください。

manifest.json
{
    "name": "SimoSimo",
    "short_name": "SimoSimo",
    "description": "爆速WordPressテーマ「Godios.」開発者、Simmonのブログ。このブログでは主に、デザインやプログラミングについて書いています。",
    "start_url": "/?utm_source=homescreen&utm_medium=pwa",
    "display": "standalone",
    "lang": "ja",
    "dir": "auto",
    "orientation": "any",
    "theme_color": "#6a5f80",
    "background_color": "#ffffff",
    "icons": [
        {
            "src": "/pwa_192.png",
            "type": "image/png",
            "sizes": "192x192"
        },
        {
            "src": "/pwa_512.png",
            "type": "image/png",
            "sizes": "512x512"
        }
    ]
}
JSON

各メンバーを簡単に説明します。

name
アプリ名
short_name
ホーム画面に表示されるアプリ名
description
アプリの説明
start_url
起動時に表示されるURL
display
表示モード。
指定できる値はfullscreen、fullscreen、standalone、minimal-uiの4つですが通常はstandaloneで問題ないでしょう。
lang
言語指定。
日本語であればjaを英語であればen-USを指定します。
orientation
画面の向き。
縦向きはlandscape、横向きはportraitを指定します。使用できる値は、natural、any、landscape、landscape-primary、landscape-secondary、portrait、portrait-primary、portrait-secondary。
dir
テキストの方向。
指定できる値は、ltr(左から右)、rtl(右から左)、auto。日本語はltr(左から右)でOK。アラビア語は逆なのでrtlを指定します。
theme_color
アプリのテーマカラー。
OSによってどこに適用されるかは異なる。
background_color
背景色。
サイトが表示されるまでの間、この色が適用される場合があります。
サイトの背景色と同じ色を指定するとスムーズに遷移しているように見えるのでよいでしょう。
icons
ホーム画面に表示されるアイコンを指定します。
必須サイズは192x192pxと512x512pxの2つです。

作成が完了したらアイコンと同じディレクトリにアップロードしてください。

service-worker.js

最後にPWAの核となるService Workerのファイルを作成します。
以下に当ブログのものを記載しますのでコピペ・改変してお使いください。

service-worker.js
const CACHE_NAME = 'simosimo_ver_1';
const urlsToCache = [
    '/',
    '/wp-content/themes/godios-child/images/site-icon.png',
    '/wp-content/themes/godios-child/images/ogp-rectangle.png',
    '/pwa_512.png',
    '/wp-content/uploads/2018/05/site-logo.min_.png',
    '/wp-content/uploads/2018/05/godios-link-banner.png',
    '/wp-content/uploads/2018/05/godios-link-banner-160x160.png',
    '/wp-content/uploads/2018/05/godios-link-banner-320x320.png',
    '/wp-includes/js/jquery/jquery.js',
    '/wp-includes/js/jquery/jquery-migrate.min.js',
    '/wp-content/themes/godios/js/godios.min.js',
    '/wp-content/themes/godios/js/god.min.js',
    '/wp-content/themes/godios-child/js/god-dispatcher.js',
    '/wp-content/themes/godios/js/god-custom.min.js'
];

self.addEventListener('install', function(event) {
    // インストール処理
    event.waitUntil(
        caches.open(CACHE_NAME)
        .then(function(cache) {
            console.log('Opened cache');
            return cache.addAll(urlsToCache);
        })
    );
});

self.addEventListener('activate', function(event) {
    const cacheWhitelist = [CACHE_NAME];

    event.waitUntil(
        caches.keys().then(function(cacheNames) {
            return Promise.all(
                cacheNames.map(function(cacheName) {
                    if (cacheWhitelist.indexOf(cacheName) === -1) {
                        return caches.delete(cacheName);
                    }
                })
            );
        })
    );
});

self.addEventListener('fetch', function(event) {

    // 管理画面はキャッシュを使用しない
    if (/\/wp-admin|\/wp-login|preview=true/.test(event.request.url)) {
        return;
    }

    // POSTの場合はキャッシュを使用しない
    if ('POST' === event.request.method) {
        return;
    }

    // 管理画面にログイン時はキャッシュを使用しない
    console.log(event);

    event.respondWith(
        caches.match(event.request)
        .then(function(response) {
            // キャッシュがあったら、そのレスポンスを返す
            if (response) {
                return response;
            }

            // 重要:リクエストをcloneする。リクエストはStreamなので
            // 一度しか処理できない。ここではキャッシュ用、fetch用と2回
            // 必要なのでリクエストはcloneしないといけない
            const fetchRequest = event.request.clone();

            return fetch(fetchRequest,{credentials: 'include'}).then(
                function(response) {
                    // レスポンスが正しいかをチェック
                    if (!response || response.status !== 200 || response.type !== 'basic') {
                        return response;
                    }

                    // 重要:レスポンスを clone する。レスポンスは Stream で
                    // ブラウザ用とキャッシュ用の2回必要。なので clone して
                    // 2つの Stream があるようにする
                    const responseToCache = response.clone();

                    caches.open(CACHE_NAME)
                        .then(function(cache) {
                            cache.put(event.request, responseToCache);
                        });

                    return response;
                }
            );
        })
    );
});
JavaScript

変更箇所はCACHE_NAMEurlsToCacheだけでOKです。
CACHE_NAMEには任意の文字列を指定します。何か変更を加えたらバージョンを上げましょう。

urlsToCacheには予めキャッシュして置きたいページやファイルのパスを指定します。
当ブログではトップページと画像・JavaScriptファイルを指定しています。(CSSはインラインで読み込んでいるので指定していません)

作成が完了したらmanifest.jsonと同じディレクトリにアップロードしましょう。

Service Workerの登録

最後にService Workerを登録する処理をheadタグの中に記述しましょう。
以下に当ブログのものを記載しますのでコピペ・改変してお使いください。

<link rel="manifest" href="/manifest.json">
<script>
	document.addEventListener('DOMContentLoaded', function() {
		if ('serviceWorker' in navigator) {
			window.addEventListener('load', function() {
				navigator.serviceWorker.register('/service-worker.js').then(function(registration) {
					// Registration was successful
					console.log('ServiceWorker registration successful with scope: ', registration.scope);
				}, function(err) {
					// registration failed
					console.log('ServiceWorker registration failed: ', err);
				});
			});
		}
	}, false);
</script>
<!-- manifest.jsonのtheme_colorと同じ色を指定します -->
<meta name="theme-color" content="#6a5f80"/>

<!-- 以下はiOS用のコードです -->
<!-- ホーム画面に表示されるアプリ名 -->
<meta name="apple-mobile-web-app-title" content="SimoSimo">
<!-- URLバーの非表示 -->
<meta name="apple-mobile-web-app-capable" content="yes">
<!-- ステータスバーのスタイル(default / black / black-translucent) -->
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<!-- アイコンの指定 -->
<link rel="apple-touch-icon-precomposed" href="/pwa_512.png" sizes="512x512">
Markup

これでPWAの作業は完了です。
最後に、次に説明する方法でPWA対応になっているかチェックしてみましょう。

確認・デバッグ方法

PWAのチェックにはGoogle Chromeのデベロッパーツールを使います。

チェックしたいサイトを開いた状態で「表示」→「開発 / 管理」→「デベロッパーツール」をクリックしてデベロッパーツールを表示させます。
一番右に「Audits」という項目がありますのでそこを選択し、「Probress Web App」にチェック、そして一番下の「Run audits」をクリックし、テストを開始します。

Audits PWAテスト

1分程すると結果が表示されますので、100点が出れば正常にPWAに対応できています。

Audits PWAのテスト結果

Manifestファイル、Service Workerがどのように認識されているかもChromeのデベロッパーツールで確認できます。

デベロッパーツールのApplicationを選択すると左側のメニューに「Manifest」と「Service Workers」という項目がありますのでそちらから確認ができます。

PWA ManifestファイルとService Workerの確認