1. Home
  2. /
  3. Saltの使い方
  4. /
  5. Hugoでついに外部URLのブログカードを作れるようになった【自作ショートコード】

Hugoでついに外部URLのブログカードを作れるようになった【自作ショートコード】

Hugoでついに外部URLのブログカードを作れるようになった【自作ショートコード】

Hugoでは外部サイトのデータを扱う場合、getJSONgetCSVを使った方法しかありませんでしたが、ついにv0.91でGetRemoteが実装されました。

failed to fetch remote resource: Too Many Requests

Release v0.91.0 · gohugoio/hugo

Hugo 0.91.0 is mostly on the boring and technical side. See the list of changes below, but especially note the fix that allows passing falsy arguments to partials with the return keyword (5758c37 #...


Hugo Pipes Introduction

Hugo Pipes is Hugo's asset processing set of functions.


GetRemoteの基本

基本の使い方はこんな感じで、html以外にも外部の画像、css、jsといったデータも取得できます。

{{ with resources.GetRemote "https://example.com" }}
    {{ .Content }}
{{ end }}

エラーハンドリング

{{ with resources.GetRemote "https://gohugo.io/images/gohugoio-card-1.png" }}
  {{ with .Err }}
    {{ warnf "%s" . }}
  {{ else }}
    <img src="{{ .RelPermalink }}" width="{{ .Width }}" height="{{ .Height }}" alt="">
  {{ end }}
{{ end }}

外部URLブログカードのショートコード

実際のコード

  • unmarshalを使いたかったのですが、多くのサイトでパースエラーが起きてしまうので、正規表現を使うことにしました。

layouts/shortcodes/blog-card.html

{{- $url := (.Get 0) -}}
{{- with $result := resources.GetRemote $url -}}
    {{- with $result.Err -}}
        {{- warnf "%s" . -}}{{- . -}}
    {{- else -}}
        {{- $title := "" -}}
        {{- $description := "" -}}
        {{- $image := "" -}}
        {{- with $findHead := index (findRE "<head>(.|\n)*?</head>" $result.Content) 0 -}}
            {{- range $meta := findRE "<meta.*?>" $findHead -}}
                {{- $name := replaceRE "<.*name=\"(.*?)\".*>" "$1" $meta -}}
                {{- $property := replaceRE "<.*property=\"(.*?)\".*>" "$1" $meta -}}
                {{- $content := replaceRE "<.*content=\"(.*?)\".*>" "$1" $meta -}}
                {{- if eq $property "og:title" -}}
                    {{- $title = $content -}}
                {{- else if eq $property "og:description" -}}
                    {{- $description = $content -}}
                {{- else if eq $property "og:image" -}}
                    {{- $image = $content -}}
                {{- end -}}
                {{- if and (eq $description "") (eq $name "description") -}}
                    {{- $description = $content -}}
                {{- end -}}
            {{- end -}}
            {{- if eq $title "" -}}
                {{- with index (findRE "<title>(.*?)</title>" $findHead) 0 -}}
                    {{- $title = replaceRE "<title>(.*?)</title>" "$1" . -}}
                {{- end -}}
            {{- end -}}
        {{- end -}}

        {{- $thumbnail_url := "" -}}
        {{- if $image -}}
            {{- with $thumbnail := resources.GetRemote $image -}}
                {{- with $thumbnail.Err -}}
                    {{- warnf "%s" . -}}{{- . -}}
                {{- else -}}
                    {{- $thumbnail_url = ($thumbnail.Fit (printf "200x200 center q%d webp" $.Site.Params.imageQuality)).Permalink -}}
                {{- end -}}
            {{- end -}}
        {{- else -}}
            {{- $thumbnail := resources.Get $.Site.Params.dafaultNoimage -}}
            {{- $thumbnail_url = ($thumbnail.Fit (printf "200x200 center q%d webp" $.Site.Params.imageQuality)).Permalink -}}
        {{- end -}}

        <a href="{{- $url -}}" style="padding: 12px;border: solid 1px #eee;display: flex;text-decoration: none;color: #000;" onMouseOver="this.style.opacity='0.9'">
            <div style="flex-shrink: 0;">
                <img src="{{- $thumbnail_url -}}" alt="" width="100" height="100" style="object-fit: contain;">
            </div>
            <div style="margin-left: 10px;">
                <h2 style="margin: 0;padding-bottom: 13px;border: none;font-size: 16px;">
                    {{- $title -}}
                </h2>
                <p style="margin: 0;font-size: 13px;word-break: break-word;display: -webkit-box;-webkit-box-orient: vertical;-webkit-line-clamp: 3;overflow: hidden;">
                    {{- $description | plainify | safeHTML -}}
                </p>
            </div>
        </a>
    {{- end -}}
{{- end -}}

使い方

  • 外部のurlを設定するだけ
  • このサイトで使っているHugoブログテーマ「Salt」内でも実装済みです
{{< blog-card "https://hugo-theme-salt.okdyy75.com/" >}}

表示例

エンジニアに関する知識を記録・共有するためのサービス - Qiita

Qiitaは、エンジニアに関する知識を記録・共有するためのサービスです。 プログラミングに関するTips、ノウハウ、メモを簡単に記録 &amp; 公開することができます。


Zenn|エンジニアのための情報共有コミュニティ

Zennはエンジニアが技術・開発についての知見をシェアする場所です。本の販売や、読者からのバッジの受付により対価を受け取ることができます。


はてなブックマーク

はてなブックマークはオンラインにブックマークを無料で保存できるソーシャルブックマークサービスです。みんながブックマークしたインターネット上の旬なニュースや情報が集まります。


Hugoブログテーマ「Salt」

このサイトはHugo用ブログテーマ「Salt」のサンプルサイトです

エラー時の表示例

ページが存在しない場合(500系など)

  • その場でエラーメッセージが表示されます
{{< blog-card "https://example.com.invalid/" >}}
error calling resources.GetRemote: Get "https://example.com.invalid/": dial tcp: lookup example.com.invalid: Temporary failure in name resolution

ページが見つからない場合(400系など)

  • 何も表示されません
{{< blog-card "https://example.com/test" >}}

metaタグにog:imageがない場合

  • デフォルトのNoImage画像が表示されます
{{< blog-card "https://example.com" >}}

Example Domain


metaタグにog:imageが存在するが、リンク切れを起こしている場合

  • リンク切れで表示されます。(src=""
{{< blog-card "https://hugo-theme-salt.okdyy75.com/test.html" >}}

テストページ

テストページです。

関連記事

サイト内ブログカードを作る自作ショートコード

サイト内ブログカードを作る自作ショートコード

このテーマ内でサイト内ブログカードを作れる「self-blog-card」というショートコードを作成しました。 使い方 自サイト内のurlを指定します 自記事のブログカードは表示できません。 日本語だとconfig.ymlのsummaryLength: 200以上推奨です {{< self-blog-card "/article/salt/custom-figure" >}} 表示例 画像のリサイズ・トリミング可能な自作ショートコード このテーマ内で画像のリサイズ・トリミングができる「custom-figur
画像のリサイズ・トリミング可能な自作ショートコード

画像のリサイズ・トリミング可能な自作ショートコード

このテーマ内で画像のリサイズ・トリミングができる「custom-figure」というショートコードを作成しました。 使い方 Hugo標準のfigureショートコードの機能をそのまま使えます HugoのImage Processingで使えるResize、Fit、Fillが使えます Image Processingについてはこちらをチェック Image Processing Resize, crop, rotate, filter, and convert images. {{< custom-figure src="image.png" title="Resize スイカ" Resize="320x180" >}} {{< custom-figure src="image.png" title="Fit スイカ" Fit="320x180" >}} {{< custom-figure src="image.png"