TEMPLATES

創建你自己的短代碼

短代碼是一種將模板整合成小型、可重用片段的方式,可以直接嵌入你的內容中。

創建自訂短代碼

Hugo 內建的短代碼涵蓋了許多常見的用例,但並非所有情境。幸運的是,Hugo 允許你輕鬆創建自訂短代碼,以滿足網站的需求。

檔案位置

要創建一個短代碼,請將 HTML 模板放在 layouts/shortcodes 目錄中。請仔細考慮檔案名稱,因為短代碼的名稱將與檔案名稱相同,但不包含 .html 擴展名。例如,layouts/shortcodes/myshortcode.html 可以這樣調用:{{< myshortcode />}}{{% myshortcode /%}}

你可以將短代碼組織在子目錄中,例如在 layouts/shortcodes/boxes 目錄中,這些短代碼可以透過相對路徑來調用,例如:

{{< boxes/square >}}

請注意前綴的斜線。

模板查找順序

Hugo 根據短代碼名稱、當前輸出格式和語言來選擇短代碼模板。以下是一些範例,按從具體到一般的順序排列。列表底部是最不具體的路徑。

短代碼名稱 輸出格式 語言 模板路徑
foo html en layouts/shortcodes/foo.en.html
foo html en layouts/shortcodes/foo.html.html
foo html en layouts/shortcodes/foo.html
foo html en layouts/shortcodes/foo.html.en.html
短代碼名稱 輸出格式 語言 模板路徑
foo rss en layouts/shortcodes/foo.en.xml
foo rss en layouts/shortcodes/foo.rss.xml
foo rss en layouts/shortcodes/foo.en.html
foo rss en layouts/shortcodes/foo.rss.en.xml
foo rss en layouts/shortcodes/foo.xml
foo rss en layouts/shortcodes/foo.html.en.html
foo rss en layouts/shortcodes/foo.html.html
foo rss en layouts/shortcodes/foo.html

請注意,主題或模組提供的模板會優先於其他模板。

位置參數與命名參數

你可以使用以下類型的參數來創建短代碼:

  • 位置參數
  • 命名參數
  • 位置或命名參數

對於位置參數,參數的順序非常重要。如果短代碼只有一個必填值,位置參數可以減少內容作者的輸入量。

對於有多個或選填參數的複雜佈局,命名參數更為合適。雖然命名參數較長,但它們讓內容作者更容易理解,且可以以任何順序在短代碼中進行設置。

允許兩種參數類型的組合在複雜佈局中很有用,這樣你可以設定預設值,並讓使用者輕鬆覆蓋這些值。

訪問參數

所有短代碼參數都可以通過 .Get 方法訪問。使用 .Get 方法時,根據是訪問命名參數還是位置參數,需要傳遞字符串或數字。

要按名稱訪問參數,使用 .Get 方法,後接命名參數作為引號字符串:

{{ .Get "class" }}

要按位置訪問參數,使用 .Get 並傳遞數字,請記住位置參數是從 0 開始計數的:

{{ .Get 0 }}

對於第二個位置,你可以直接使用:

{{ .Get 1 }}

with 在當輸出依賴於某個參數時非常有用:

{{ with .Get "class" }} class="{{ . }}"{{ end }}

.Get 也可以用來檢查某個參數是否已提供。這對於根據某些值的存在與否進行條件判斷非常有用:

{{ if or (.Get "title") (.Get "alt") }} alt="{{ with .Get "alt" }}{{ . }}{{ else }}{{ .Get "title" }}{{ end }}"{{ end }}

.Inner

.Inner 方法返回開關短代碼標籤之間的內容。若 .Inner 返回的內容非空白,可進行如下判斷:

{{ if strings.ContainsNonSpace .Inner }}
  Inner is not empty
{{ end }}

.Params

.Params 方法用於返回傳遞給短代碼的參數,這對於更複雜的用例非常有幫助。你還可以使用以下邏輯訪問更高範圍的參數:

  • $.Params:這是直接傳遞給短代碼的參數(例如 YouTube 視頻 ID)。
  • $.Page.Params:指頁面參數;這裡的「頁面」是指包含短代碼的內容檔案(例如,可以通過 $.Page.Params.shortcode_color 訪問內容 Front Matter 中的 shortcode_color 欄位)。
  • $.Site.Params:指的是在網站配置中定義的參數。

.IsNamedParams

.IsNamedParams 方法檢查短代碼是否使用了命名參數,並返回一個布林值。

例如,你可以創建一個 image 短代碼,根據內容作者的偏好,接受 src 命名參數或第一個位置參數。假設 image 短代碼是這樣調用的:

{{< image src="images/my-image.jpg" >}}

你可以在短代碼模板中包含如下代碼:

{{ if .IsNamedParams }}
  <img src="{{ .Get "src" }}" alt="">
{{ else }}
  <img src="{{ .Get 0 }}" alt="">
{{ end }}

參見下面的 Vimeo 短代碼範例,以了解 .IsNamedParams 的具體應用。

短代碼也可以嵌套。在嵌套短代碼中,你可以使用 .Parent 方法訪問父短代碼上下文。這對於根目錄的繼承非常有用。

檢查短代碼是否存在

你可以通過在頁面模板中調用 .HasShortcode 方法來檢查該頁面是否使用了特定的短代碼,並提供短代碼名稱。當你希望只在使用該短代碼時包括特定的腳本或樣式時,這非常有用。

自訂短代碼範例

以下是可以在 /layouts/shortcodes 目錄中的短代碼模板文件中創建的不同類型的短代碼範例。

單字範例:year

假設你希望在內容文件中保持版權年份的最新狀態,而不必持續檢查 Markdown。你的目標是能夠這樣調用短代碼:

{{< year >}}
layouts/shortcodes/year.html
{{ now.Format "2006" }}

單一位置參數範例:youtube

嵌入影片是 Markdown 內容中的常見元素。以下是 Hugo 內建 YouTube 短代碼使用的代碼範例:youtubeshortcode

{{< youtube 09jf3ow9jfw >}}

會加載位於 /layouts/shortcodes/youtube.html 的模板:

layouts/shortcodes/youtube.html
<div class="embed video-player">
<iframe class="youtube-player" type="text/html" width="640" height="385" src="https://www.youtube.com/embed/{{ index .Params 0 }}" allowfullscreen frameborder="0">
</iframe>
</div>

單一命名範例:image

假設你想要創建自己的 img 短代碼,而不是使用 Hugo 內建的 figure 短代碼。你的目標是能夠在內容檔案中像下面這樣呼叫該短代碼:

content-image.md
{{< img src="/media/spf13.jpg" title="Steve Francia" >}}

你已經在 /layouts/shortcodes/img.html 創建了短代碼,並且該模板載入了以下內容:

layouts/shortcodes/img.html
<!-- image -->
<figure {{ with .Get "class" }}class="{{ . }}"{{ end }}>
  {{ with .Get "link" }}<a href="{{ . }}">{{ end }}
    <img src="{{ .Get "src" }}" {{ if or (.Get "alt") (.Get "caption") }}alt="{{ with .Get "alt" }}{{ . }}{{ else }}{{ .Get "caption" }}{{ end }}"{{ end }} />
    {{ if .Get "link" }}</a>{{ end }}
    {{ if or (or (.Get "title") (.Get "caption")) (.Get "attr") }}
      <figcaption>{{ if isset .Params "title" }}
        <h4>{{ .Get "title" }}</h4>{{ end }}
        {{ if or (.Get "caption") (.Get "attr") }}<p>
        {{ .Get "caption" }}
        {{ with .Get "attrlink" }}<a href="{{ . }}"> {{ end }}
          {{ .Get "attr" }}
        {{ if .Get "attrlink" }}</a> {{ end }}
        </p> {{ end }}
      </figcaption>
  {{ end }}
</figure>
<!-- image -->

這樣將會渲染為:

img-output.html
<figure>
  <img src="/media/spf13.jpg"  />
  <figcaption>
      <h4>Steve Francia</h4>
  </figcaption>
</figure>

單一彈性範例:vimeo

{{< vimeo 49718712 >}}
{{< vimeo id="49718712" class="flex-video" >}}

這將會載入位於 /layouts/shortcodes/vimeo.html 的模板:

layouts/shortcodes/vimeo.html
{{ if .IsNamedParams }}
  <div class="{{ if .Get "class" }}{{ .Get "class" }}{{ else }}vimeo-container{{ end }}">
    <iframe src="https://player.vimeo.com/video/{{ .Get "id" }}" allowfullscreen></iframe>
  </div>
{{ else }}
  <div class="{{ if len .Params | eq 2 }}{{ .Get 1 }}{{ else }}vimeo-container{{ end }}">
    <iframe src="https://player.vimeo.com/video/{{ .Get 0 }}" allowfullscreen></iframe>
  </div>
{{ end }}

這樣將會渲染為:

vimeo-iframes.html
<div class="vimeo-container">
  <iframe src="https://player.vimeo.com/video/49718712" allowfullscreen></iframe>
</div>
<div class="flex-video">
  <iframe src="https://player.vimeo.com/video/49718712" allowfullscreen></iframe>
</div>

配對範例:highlight

以下是來自 highlight 的範例,這是 Hugo 內建的短代碼之一。

highlight-example.md
{{< highlight html >}}
  <html>
    <body> 這是 HTML </body>
  </html>
{{< /highlight >}}

highlight 短代碼的模板使用以下代碼,這是 Hugo 預設已經包含的:

{{ .Get 0 | highlight .Inner }}

渲染後的 HTML 範例代碼區塊將會如下所示:

syntax-highlighted.html
<div class="highlight" style="background: #272822"><pre style="line-height: 125%"><span style="color: #f92672">&lt;html&gt;</span>
    <span style="color: #f92672">&lt;body&gt;</span> 這是 HTML <span style="color: #f92672">&lt;/body&gt;</span>
<span style="color: #f92672">&lt;/html&gt;</span>
</pre></div>

嵌套短代碼:圖像畫廊

Hugo 的 .Parent 短代碼方法提供了當短代碼在父級短代碼的上下文中被呼叫時,能夠訪問父級短代碼的上下文,這提供了一個繼承模型。

以下範例是構造出來的,但能夠展示這個概念。假設你有一個 gallery 短代碼,並且它預期一個名為 class 的參數:

layouts/shortcodes/gallery.html
<div class="{{ .Get "class" }}">
  {{ .Inner }}
</div>

你還有一個 img 短代碼,它有一個名為 src 的參數,你想要在 gallery 和其他短代碼中呼叫它,這樣父代碼就能定義每個 img 的上下文:

layouts/shortcodes/img.html
{{- $src := .Get "src" -}}
{{- with .Parent -}}
  <img src="{{ $src }}" class="{{ .Get "class" }}-image">
{{- else -}}
  <img src="{{ $src }}">
{{- end -}}

然後你可以在內容中這樣呼叫短代碼:

{{< gallery class="content-gallery" >}}
  {{< img src="/images/one.jpg" >}}
  {{< img src="/images/two.jpg" >}}
{{< /gallery >}}
{{< img src="/images/three.jpg" >}}

這將會輸出以下 HTML。注意到前兩個 img 短代碼繼承了由父級 gallery 設定的 classcontent-gallery,而第三個 img 只使用了 src

<div class="content-gallery">
    <img src="/images/one.jpg" class="content-gallery-image">
    <img src="/images/two.jpg" class="content-gallery-image">
</div>
<img src="/images/three.jpg">

短代碼中的錯誤處理

使用 errorf 模板函數與 NamePosition 短代碼方法來生成有用的錯誤訊息:

layouts/shortcodes/greeting.html
{{ with .Get "name" }}
  <p>你好,我的名字是 {{ . }}。</p>
{{ else }}
  {{ errorf "The %q shortcode requires a 'name' argument. See %s" .Name .Position }}
{{ end }}

當上述失敗時,你將看到類似以下的 ERROR 訊息:

ERROR The "greeting" shortcode requires a 'name' argument. See "/home/user/project/content/_index.md:12:1"

行內短代碼

你也可以在內容文件中實現行內短代碼 – 例如,當你只需要在某一個地方使用它們時。這對於只需要一次的腳本來說非常有用。

此功能預設是禁用的,但可以在你的網站配置中啟用:

hugo.
     
security:
  enableInlineShortcodes: true
[security]
  enableInlineShortcodes = true
{
   "security": {
      "enableInlineShortcodes": true
   }
}

預設是禁用的,出於安全原因。Hugo 的模板處理所使用的安全模型假設模板作者是受信任的,但內容文件不是,因此模板可以安全地防範來自不當輸入資料的注入攻擊。但在大多數情況下,你對內容也擁有完全控制權,這時 enableInlineShortcodes = true 會被視為安全的。不過這是需要注意的:它允許從內容文件執行即時 Go 文本模板

一旦啟用,你可以在內容文件中這樣操作:

{{< time.inline >}}{{ now }}{{< /time.inline >}}

上述代碼將輸出當前的日期和時間。

注意,行內短代碼的內部內容會像普通短代碼模板一樣作為 Go 文本模板進行解析和執行,並使用相同的上下文。

這意味著可以通過 .Page.Title 等來訪問當前頁面。這也意味著沒有「嵌套行內短代碼」的概念。

相同的行內短代碼可以在同一個內容文件中再次使用,並且可以根據需要使用不同的參數,這時可以使用自閉合語法:

{{< time.inline />}}