wordpress で SNS や SEO に優しい簡単 SPA 作り

SPA と wordpress を組み合わせたら意外と SPA の問題を解決できた。という記事です。

## 経緯

経緯は、もともと存在する SPA のサイトを
wordpress で管理されている記事コンテンツ配信サイトに
リニューアルしたいというお話をいただいたことでした。

リニューアル前のサイトのインタラクションが良かったので、
その雰囲気は残しつつ、クローラー対策などの作り込みを行い
ちゃんと記事メインのサイトとして耐えうるものを目指しました。


## 課題と対応

### 1. クローラーにページ独自の meta 情報を認識させる

動的に生成されたページを検索エンジンや SNS のクローラーに
認識させるためには、プリレンダリングでファイルを用意するか
SSR（サーバサイドレンダリング）の対応が必要になります。

今回は wordpress の利用が前提だったので、 
アクセス開始されたページのみ、```<head>``` 内の情報を書き換えるようサーバ側でレンダリングするようにしました。

■ wordpress
1. 普段通りに wordpress を設置
2. 今回はルーティングは数字ベース（ https://**/archives/123 ）を設定
3. テーマのテンプレートファイルは index.php のみを用意
4. functions.php で記事ページの meta や OGP が出力されるようにする


```html+php:index.php
<?php get_header(); ?>

<div class="wrapper">
  <div id="app"></div>
</div>


<?php get_footer(); ?>

```

wordpress は規定のテンプレートがなければ
最終的に index.php を探しに行くのでこれだけで大丈夫です。
footer.php では JavaScript のファイル呼びこみなどを行なっています。


```functions.php
/**
 * OGP タグ出力例
 */
add_action( 'wp_head', 'XXX_meta_ogp' );
function XXX_meta_ogp() {

  // title
  $title = is_single()
    ? strip_tags(get_the_title()) . ' | ' . get_bloginfo('name')
    : get_bloginfo('name');

  echo '<meta property="og:title" content="' .$title .'">';
}
```

wp_head をフックに情報が書き換わるようにします。

■ vue.js
JavaScript フレームワークは vue.js を使いました。

1. vue-router を使って、wordpress のパーマリンクに合わせたルーティングを設定
2. 後は作り込み

```routes.js
import VueRouter from 'vue-router'
Vue.use(VueRouter)

const routes = [
  { path: '/', component: Top, name: 'top'},
  { path: '/archives/:id', component: Archive, name: 'archive'}
  // id は 記事の id（数字）を渡す
]

export default new VueRouter({
  mode: 'history',
  base: __dirname,
  routes
})
```

### 2. SEO対策

google のクローラーは JavaScript を理解するが
インデックスが遅い可能性があるという記事を見かけたので、
そちらの対応を行います。

[JavaScriptで生成されたコンテンツもリンクも静的なものと同等にGoogleは評価する。ただし時間がかかることも | 海外SEO情報ブログ](https://www.suzukikenichi.com/blog/content-and-link-generated-by-javascript-are-treated-just-same-as-static-content-and-link/)

具体的には、sitemap.xml と feed を google Search Console に登録しました。
ついでに feed には PubSubHubbub を設定しました。

### 3. AMP 対応

SEO には直接関係ないですが、
検索エンジンから流入するモバイルユーザのために AMP 対応も行いました。
（wordpress の 「AMP」というプラグインを利用）

SPA ではモバイル回線でも巨大な JavaScript を最初に読み込ませるため、
状況によってはサイトが遅くなってしまいますが、
AMP ページを用意することでそのストレスも解消できるのではと期待しました。


## 効果

sitemap.xml と feed を google Web Console に登録してから ３日後に
ステータスが「インデックス済み」になり、
順位は低いものの検索結果に出てくるようになりました。

モバイル版の SERP は AMP へリンクされており、
スニペットはページの description が使われていました。
登録から 3日後にインデックスなら、悪くないのでは？と思ったのですが、
静的ページの場合、Fetch as Google　を使って一日以内にインデックスされた
ということを聞いたので、やはり動的なページの登録は遅いかもしれないです。


全体として、 wordpress + SPA で実感した利点としては、

- フロントは SPA 作り込みに集中できた
- 動的ページの弱点は wordpress を使うことで簡単にフォローできた
- wordpress なのでフロントエンドエンジニアにも馴染みがある
- SPA はページ遷移が速い

でした。
コンテンツ管理そのものは wordpress でなくてヘッドレス CMS でも良いのですが、
困ったら view に出力できるというのは便利でした。


## 今後の課題

- JavaScript をオフにしているユーザーへの対応 → AMP へのリダイレクトで解決？
- ページを遷移したときに音声ブラウザへ移動を通知

このあたりは今回解決する余力がありませんでした。
ユーザビリティをしっかり対応する場合は、静的サイトにするべきな気がしています。

- １ページだけ記事を読みに来た人にも重い JavaScript のロードを強要する
- JavaScript のレンダリングブロッキングを発生させてしまう

今回使った JavaScript は gzip しても約 100kb でした。
静的ページならここまで重い JavaScript は必要ないので少し後ろめたさを感じます。

また、PageSpeed Insights でよく指摘される
初回表示のレンダリングブロックも解決できませんでした。
JavaScript の作り方によってうまく回避できるかもしれないのですが、
どうすればよいか思案中です。。

- 貧弱な環境に弱い

今回は Android5 以降、IE11 からという新し目のブラウザを対象に作っていました。
Android4.3 以前ではアニメーション処理も含めキャパオーバーになりそうな怖さを感じます。
古いデバイスも対象に含まれるなら、静的サイトで作りたいです。

## まとめ

出来上がったサイトは当初の要求をクリアできたこと、
ページ遷移の速さが評判良く、安心しました。

SPA の SSR というとアイソモーフィックやら難しいイメージがありますが、
wordpress と組み合わせるのは敷居が低くておすすめです！