当ブログのフロントエンドは、WordPress標準のSSR(PHPで出力したHTMLを表示)を使用してきましたが、SPAとして再作成しました。
作成にはReactを使用しています。
記事の入力については、引き続きWordPressの標準のものを使用しています。
WordPress標準のエディタであるGutenbergエディタは使いやすいと思っているので、完全にWordPressから独自サイトに移行ではなく、入力は今まで通りに出来るようにしました。
なぜSPAとして再作成することにしたか
SPAとして再作成した理由は以下となります。
- Webサイトの表示速度について、Googleから「検索順位に考慮するようになった」とアナウンスされているため
- Reactで作成されたサイトでもコンテンツの内容が正しくGoogleに読み取られるようになったことが確認できたため
- AMPは制限事項が多く当サイトでは採用していなかった
要はSEO対策で有利になってくるのではないかと思い、SPA化させることにしました。
Googleが読み込み速度を検索順位に考慮しているというのは、以下の公式ブログに記載されています。
https://webmaster-ja.googleblog.com/2018/01/using-page-speed-in-mobile-search.html
WordPressをReactで再作成した影響について
記事執筆時点で、Reactに切り替えて1ヶ月になります。
検索流入については、Bingからの流入が激減、Googleからは微増となりました。
下記図はアクセス数の推移ですが、赤線を引いた部分がReactに切り替えたタイミングになります。
Bing
そもそも波があるグラフになっているのですが、これは当ブログが休日にほとんどアクセスがないためです。
Bingのアクセスが激減している原因としては、2021年5月時点ですとBingがReactのコンテンツを正確に読み取れないためだと思います。
↓Bing Web Masterツールから確認をすると、ドキュメントサイズが3KBとなっており本文が読み込めてないことがわかります。
Googleのアクセスについては、20%ほどアクセスが増えました。
もともとブログのアクセス数が上昇傾向にあったので、React化の影響で上昇した可能性もあります。しかし、少なくともマイナスに評価されることはないと思います。
ブログのSPA化のデメリット
その他に、デメリットと感じた点が既にいくつか存在しています。
- アドセンスやアナリティクスについては、SSRの方が有利
- 古いIEで接続してくるユーザがエラーとなってしまう
- ブログの場合は初回の離脱率が高いため、SPAのメリットを生かしにくい
頑張れば解消できる課題な気がするのですが、現時点で当サイトでは対応できていません。以下、詳細に記載をしてみたいと思います。
アドセンスやアナリティクスについては、SSRの方が有利
ブログでGoogleアドセンスやGoogleアナリティクスを使用している方は多いと思いますが、これについて厄介な問題が発生します。
SPAでは2回目以降(ページ遷移の場合)は、差分の更新のみになるため、ページ内リンクをクリックしたということがアナリティクスやアドセンスが感知することができません。
そのため、ページが遷移した時にアナリティクスやアドセンスの関数を呼び出すという処理が必要になります。※こちらについては、後述いたします。
また、アドセンスについては自動広告が非常に使いにくいという点が挙げられます。
前述の「初回しか読み込まれないので、ページ遷移しても広告が変わらない」という問題ももちろんあるのですが、SSRを使用していたころと比較して、自動広告の配置場所や数が悪くなりました。
これはReactのコンポーネントの描画前の状態で、自動広告をどこに配置するかを決めているからではないかと思われます。
(SetTimeOutなどで後から自動広告を呼び出してみても同じだったので、単純にSPAの構造分析が苦手なだけかもですが。)
全画面広告や関連コンテンツの最適化など、自動広告を使うことによるメリットは大きいので、アドセンスを使う場合にはかなり不利になると思います。
古いIEで接続してくるユーザがエラーとなってしまう
モダンなJavaScriptを使う時の宿命ですが、古いIEではエラーとなって表示できない場合が多いです。
「IEなんて対応する必要ないじゃん」
と言われる方も多いと思いますが、Web上で公開している限りできる限り考慮すべきと考えています。
当サイトのアクセス解析によると、2021年現在でも約15%程度のユーザがIEを使用しています。
これはサイトによって違うと思いますが、少なくとも当サイトではFIreFoxやSafariよりも多く、無視できるものではありません。
最も多いと思われるIE11では、以下の方法で対応をすることができました。
ただ、IE10以下で動かしている人向けには対策が練れていない状況です。
ブラウザがIEだったら、htaccessとかでPHPで表示されるようにしようとも思ったんですが、2重管理になってまでSPA化するのかと言われると微妙です。
ブログの場合は初回の離脱率が高いため、SPAのメリットを生かしにくい
皆さんはブログで目的の記事を読んだ後、他の記事も読むことってありますか?
自分の場合はほとんどありません。
ほとんどの場合が、「検索エンジンから目的の記事を開く→読み終わったら離脱」ではないでしょうか。
その場合、2ページ目以降のアクセスが速くなるというSPAのメリットを生かすことができません。
むしろ初回にJSをダウンロードする分、SPAの方が不利であると思います。
メリット・デメリットのまとめ
結論、頑張ってReactで作ってみたものの「ブログはSSRの方がいいんじゃねーか」と思いました。
Googleからの検索流入が微増したというメリットもあり、かなり工数も使っているので、継続はしていこうかなと思います。
作成したソースや気を付けたことなど
今回はTypeScript+Reactで作成を行いました。ソースはGitで公開をしています。
https://github.com/namekoX/blog
ポイントとなる点について、記載をしていきたいと思います。
記事取得はWordPress APIを使用する
記事の内容を取得したり、記事の一覧を取得するにはWordPressが標準で公開しているREST APIを使用します。
記事を取得するためのAPIのURLは以下となります。
ブログホームURL + /wp-json/wp/v2/posts/ + 記事ID + ?_embed
_embedパラメータを与えることで、アイキャッチなどの添付ファイルのURLも同時に取得することができます。
固定ページ取得のAPIのURLは以下となります。
ブログホームURL + /wp-json/wp/v2/pages/ + 記事ID + ?_embed
一覧用の複数記事取得のAPIは以下となります。
ブログホームURL + /wp-json/wp/v2/posts?_embed&per_page=10&page=1
per_pageが1回で取得する記事数、pageが何ページ目を取得するかを表しています。上記例は、記事を10件ごと取得、1~10件目を取得にしています。
ページャを作る際に、最大記事件数や最大ページ数が欲しくなると思いますが、それはレスポンスヘッダーから取得できます。
x-wp-totalが総記事数、x-wp-totalpagesが総ページ数になります。
記事取得APIのレスポンスは、自分は下記のソースの型で受けるようにしています。
https://github.com/namekoX/blog/blob/master/src/interface/GetPostDataResult.tsx
主要なところだけ挙げると、axiosで通信を行った時、
- response.data.idが記事ID
- response.data.titleが件名
- response.data.contentが本文
になります。
カテゴリ名を取得できるようにfunction.phpを修正する
Word Press APIの標準だとカテゴリ名の取得ができないため、wp-includesフォルダに有るfunction.phpに以下を追記しています。
add_action( 'rest_api_init', 'register_category_name' );
function register_category_name() {
register_rest_field( 'post',
'category_name',
array(
'get_callback' => 'get_category_name'
)
);
}
function get_category_name( $object ) {
$category = get_the_category($object[ 'id' ]);
$cat_name = $category[0]->cat_name;
return $cat_name;
}
※以下サイトを参考にさせていただきました。
https://qiita.com/yumayamada1029/items/c40e40200899330f957b
dangerouslySetInnerHTMLを使用して、本文を表示する
APIから返却される本文は、HTMLのデータとなっているためdangerouslySetInnerHTMLを使用して、HTMLとして評価して画面表示してあげるようにします。
自分のブログで言うと該当のコードは以下になります。
https://github.com/namekoX/blog/blob/master/src/components/PostComponent.tsx#L87
アドセンスとアナリティクスの設定
上の方でも書きましたが、SPAではアナリティクスやアドセンスページ遷移が発生した際に、明示的にAPIをキックしていなければ、1ページしかアクセスしていないという判断がされてしまいます。
色々と方法はあるかと思いますが、私が対応した方法は以下になります。
アナリティクスの設定方法
まず、index.htmlにアナリティクスの読み込み設定を記載します。
自分はオンコードしてしまっていますが、アナリティクスのIDは.envとかで管理できるようにしたほうがいいですね。
https://github.com/namekoX/blog/blob/master/public/index.html#L30
上記を設定することで、ブログへの初回アクセス時のアクセスは記録されるようになります。
次に、ページのパスが変わったときにアナリティクスのAPIを叩くようにします。
私はHOOKを使用しているのですが、useEffectでパスが変更されるたびに以下の関数を実行しています。
https://github.com/namekoX/blog/blob/master/src/common/utils.tsx#L51
index.htmlで定義したgtag関数を呼んでいるだけです。
gtagの使い方は以下の公式ページが参考になります。
https://developers.google.com/gtagjs/reference/api?hl=ja
アドセンスの設定方法
アナリティクスと同様に、まずはindex.htmlにアドセンスの読み込み設定を記載します。
https://github.com/namekoX/blog/blob/master/public/index.html#L36
次に、アドセンスの広告ユニット用のコンポーネントを作成します。自分が作成したソースは以下になります。
https://github.com/namekoX/blog/blob/master/src/components/AdsComponent.tsx
ポイントはuseEffectでアドセンスのAPIをキックしているということです。
useEffect(() => {
if (window.adsbygoogle && process.env.NODE_ENV === "production") {
window.adsbygoogle.push({});
}
}, [])
adsbygoogle.pushを実行することで、用意していたコンポーネントに広告がロードされます。
index.htmlがロードされた時点では、まだ広告ユニットが存在しないので、レンダーしたタイミングでキックしないといけないということです。
コメントを残す