hexo-related-popular-posts
ブログによくある「この記事に関連する記事」みたいなやつを出したい。
このブログはHexoにより生成されており、Hexoには良い感じのプラグインが多数存在する。
ここでhexo-related-popular-posts
というHexo用の素晴らしいプラグインを使うことで関連記事を生成する。
hexo-related-popular-postsのGitHubリポジトリで実験する。
公式ドキュメント通りにやればおおよそうまくいくが環境の問題か一部詰まった所がある。
パッケージ | バージョン |
---|
hexo | 4.2.1 |
node | 12.14.1 |
icarus | 2.6.0 |
実装方法を以下に記す。
1. インストール
下記のコマンドでhexo-related-popular-posts
をインストール。
1
| npm install hexo-related-popular-posts@4.0.0. --save
|
インストール後、hexo s
でプレビュー表示しても特にエラーが起きなければOK。
1.1. 失敗例
以下のようにバージョン指定せずにインストールしたら、
1
| npm install hexo-related-popular-posts --save
|
hexo s
でプレビュー表示したときに下記のエラーが起きた。
1
| TypeError: hexo.locals.cache.cache.get is not a function
|
その場合は以下のようにアンインストールしてからやり直す。
1
| npm uninstall hexo-related-popular-posts --save
|
2. シンプルな実装
icarus\layout\widget
にrelated_posts.ejs
という名前のファイルを作る。
中身は以下のようにする。
公式サンプルではpost
だがIcarusではpage
にする必要がある。
related_posts.ejs
1 2 3 4 5 6 7 8 9 10
| <div class="card widget"> <div class="card-content"> <h3 class="menu-label"> <%= __('widget.related_posts') %> </h3> <%- popular_posts( { maxCount: 5 , ulClass: 'popular-posts' , PPMixingRate: 0.0 , isDate: false , isImage: true , isExcerpt: false} , page ) %> </div> </div>
|
icarus\_config.yml
にWidgetの設定を追加。
widgets:
のところに以下のように追記する。
1 2 3 4 5
| - # Widget name type: related_posts # Where should the widget be placed, left or right position: left
|
hexo s
でプレビュー表示すると関連記事が表示されている。
トップページには関連記事が出ないので適当な記事を見る。
リンクは正しく表示されているがサムネイル画像が表示されていない記事がある。
表示されているサムネイル画像も記事に設定されているものとは違う。
これを修正する。
3. サムネイル画像の取得
hexo-related-popular-posts
のサムネイル取得部分を修正する。
node_modules\hexo-related-popular-posts\lib\collector.js
のコメントで
と書いてあるあたりを以下のように変更。
変更前
1 2 3
| // get eyecatch image if (post.eyeCatchImage || post.postImage || (post.ampSettings && post.ampSettings.titleImage.path) ) { eyeCatchImage = post.eyeCatchImage || post.postImage || ( (post.ampSettings && post.ampSettings.titleImage.path) ? post.ampSettings.titleImage.path : null )
|
変更後
1 2 3
| // get eyecatch image // 修正 "post.thumbnail || " 追加 if (post.thumbnail || post.eyeCatchImage || post.postImage || (post.ampSettings && post.ampSettings.titleImage.path) ) { eyeCatchImage = post.thumbnail || post.eyeCatchImage || post.postImage || ( (post.ampSettings && post.ampSettings.titleImage.path) ? post.ampSettings.titleImage.path : null )
|
保存した後、一度hexo clean
でキャッシュを消去。
再度hexo s
でプレビュー表示すると関連記事のサムネイル画像が想定通りに変わっている。
4. フォーマットの修正
このブログで使われているHexoテーマのIcarusには最新の記事を表示する機能がある。
これは先のhexo-related-popular-posts
により作られた関連する記事とフォーマットが異なる。
なのでhexo-related-popular-posts
のフォーマットを修正することで統一する。
icarus\scripts
にrelatedPostsHelper.js
という名前のファイルを作る。
relatedPostsHelper.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| // hexo-related-popular-posts のフォーマットを変換する hexo.extend.helper.register('relatedPostsConvert', function(args){ // 中身が無かったら空白を返す if(!args) return "";
// cheerio で 画像path,記事path,記事タイトルのリストを取得 const cheerio = require('cheerio'); const $ = cheerio.load(args); const imgsrclist = $('div[class="popular-posts-img"]').find('img').toArray().map(element => $(element).attr('src')); const pathlist = $('div[class="popular-posts-title"]').find('a').toArray().map(element => $(element).attr('href')); const titlelist = $('div[class="popular-posts-title"]').find('a').toArray().map(element => $(element).attr('title'));
// 返すHTMLを作る var returnHTML = ""; for(var i=0; i<imgsrclist.length; i++){ returnHTML += `<article class="media">` returnHTML += `<a href="` + pathlist[i] + `" class="media-left"><p class="image is-64x64">` returnHTML += `<img class="thumbnail" src="` + imgsrclist[i] + `" alt="` + titlelist[i] + `"></p></a>` returnHTML += `<div class="media-content">` returnHTML += `<a href="` + pathlist[i] + `" class="title has-link-black-ter is-size-6 has-text-weight-normal">` returnHTML += titlelist[i] + `</a></div></article>` } return returnHTML; });
|
これにより作られた関数relatedPostsConvert
は引数として与えたHTMLを良い感じに変換する。
さっきのrelated_posts.ejs
の中から呼んで使う。
related_posts.ejs
1 2 3 4 5 6 7 8 9 10 11 12
| <div class="card widget"> <div class="card-content"> <h3 class="menu-label"> <%= __('widget.related_posts') %> </h3> <%- relatedPostsConvert( popular_posts( { maxCount: 5 , ulClass: 'popular-posts' , PPMixingRate: 0.0 , isDate: false , isImage: true , isExcerpt: false} , page ) ) %> </div> </div>
|
するとこうなる。
おおよそフォーマットの統一ができた。
多少の違いはあるが気にならない程度なので良し。
5. 関連する記事が存在しないページの対応
仕組み上、トップページなど関連する記事が存在しないページの場合「無」が生成される。
なので関連する記事がなかった場合は関連する記事を作らないようにする。
さっきのrelated_posts.ejs
を以下のように修正する。
related_posts.ejs
1 2 3 4 5 6 7 8 9 10 11 12
| <% var relatedPostsHTML = popular_posts( { maxCount: 5 , ulClass: 'popular-posts' , PPMixingRate: 0.0 , isDate: false , isImage: true , isExcerpt: false} , page ) %> <% if (relatedPostsHTML == '') { %> <% } else { %> <div class="card widget"> <div class="card-content"> <h3 class="menu-label"> <%= __('widget.related_posts') %> </h3> <%- relatedPostsConvert( relatedPostsHTML ) %> </div> </div> <% } %>
|
これによりトップページなどを開いたときに関連する記事が表示されなくなった。