Featured image of post 配置Pages CMS让其支持Hugo目录结构

配置Pages CMS让其支持Hugo目录结构

在上一篇文章 Pages CMS:一个勉强够用的HUGO博客后台 中,我提到可以用 Pages CMS 作为 Hugo 的文章后台管理面板。但有个问题不是很好解决,即 Hugo 默认目录结构很难与 Pages CMS 进行适配。这也不单单是 Pages CMS 独有问题,其他任何 CMS 可能都会在适配 Hugo 时遇到这个问题。但在 Hugo 社区的强大支持下,我最终解决了这一问题。


问题表现形式

Hugo 需要什么样的图片目录结构

Hugo 目录一般是下边这种形式,index.md 文件 与图片文件都保存在同一文件夹内。在 index.md 中引用图片,只需要输入 ![a](a.jpg) 即可,不需要输入图片的目录结构。除非一种情况,在下边代码类似 article-1 内有子目录,这时才需要在图片引用子目录路径。

1
2
3
4
5
6
7
8
9
content/
├── post/
│   ├── article-1/
│   │   ├── a.jpg
│   │   └── index.md
│   └── article-2/
│       ├── b.jpg
│       └── index.md
└── _index.md

CMS 能提供什么样的图片目录结构

CMS 的图片目录结构一般是下边这种形式,通常只有一个图片入口和出口,用于图片集中管理。在 CMS 中,上传或插入图片,默认的链接(按照下方代码设置)是 content/post/article-1/a.jpg 。在使用 markdown 语法后,会变成 ![a](content/post/article-1/a.jpg) ,一旦手动设置图片链接为 ![a](a.jpg) 就会产生错误。但 ![a](content/post/article-1/a.jpg) 这种链接格式,在 Hugo 中会被认为图片是保存在 index.md 所在目录的下级,即 content/post/article-1/content/post/article-1/a.jpg ,这当然是一个错误的路径。冲突由此而产生。

1
2
3
media:
  input: content/post
  output: /content/post

原因分析

诚然,这看起来似乎是一个很小的问题。但想要解决这个问题却并不容易。在 CMS 中,如果要让程序将 ![a](a.jpg) 这种链接结构能够直接关联到index.md 所在目录的图片,需要下很大功夫。因为绝大多数人使用 CMS 都是使用统一图片文件夹管理,需要用到图片绝对地址,很难为了适配 Hugo 单独去做一套方案来适配,而且会产生其他冲突。例如,index.md 所在目录的下级还有图片文件夹的情况。

于是,压力给到 Hugo 这边。

在本地测试中发现,![a](content/post/article-1/a.jpg) 被 Hugo 转换为了 https://localhost/content/post/article-1/a.jpg 其中,/content/post/ 来自 CMS 的图片输出设置,/article-1/index.md 所在文件夹名称。

![a](a.jpg) 在 Hugo 中被转换为 https://localhost/article/slug/a.jpg 其中 /article/ 是由 Hugo.yaml 中的 permalinks: { post: /article/:slug/ } 输出,/slug/ 内容是在 front-matter 中手动设置。

到了这里,问题解决方法就逐渐明晰起来。


初步解决办法

  1. 在 CMS 图片输出路径中删掉 /content/ 部分,这样 CMS 输出图片路径变成了 ![a](post/article-1/a.jpg)

  2. Hugo.yaml 中将 permalinks: { post: /article/:slug/ } 删除,同时删除测试 index.md 中手动设置的 slug,这样固定链接将默认使用文件夹名称。

如此,CMS 中的 ![a](content/post/article-1/a.jpg) 在 Hugo 中被转换为了 https://localhost/post/article-1/a.jpg ,同样,手动输入的 ![a](a.jpg) 也在 Hugo 中被转换为了 https://localhost/post/article-1/a.jpg 。问题基本得到解决。


进阶解决办法

由于 CMS 中图片路径就是 Hugo 生成静态站点后的绝对地址,等于 CMS 在 Hugo 渲染中打了提前量,预测到这个地址最后就会有个文件存在,所以在网页中不会出现错误。

但是这种方法对于很多复杂的 Hugo 主题模板而言,还是差点意思。因为 Hugo 没有对这个地址上的图片文件作任何处理,主题模板也不会对这个地址上的图片文件作 CSS 预设。因为在整个过程而言,这实际上就相当于一个第三方图片。

由此,接下来需要解决的实际问题是:如何将 ![a](content/post/article-1/a.jpg) 导入到 Hugo 的图片渲染程序中。由于我在 Hugo 官方论坛提出前一个目录结构问题,当时技术大佬就指出我可以使用 Hugo 的图片钩子来保证这个路径上的图片得到渲染。

但这个设置并不简单。

我尝试了很多种方法去定义图片钩子。例如,判断 ![a](content/post/article-1/a.jpg) 图片 Markdown 语法中是否包含 / 斜杠符号,是否属于绝对地址,或者更改 Resources.GetMatch 函数等方式。但这些都没成功。

最终,我选择了一个最老土的办法,直接将 ![a](content/post/article-1/a.jpg) 中的图片文件名单独提取出来,无视 content/post/article-1 路径部分,只要匹配到 a.jpg 即导入 Hugo 渲染。但这样做有一个代价,就是前边说的,图片不能再放置于 article-1 内的子目录,必须直接放置在 article-1 中。


至此,我想上一篇博客的文章标题可以修改了,Pages CMS 不再是一个勉强可以使用的 Hugo 博客后台,而是一个具有完全能力的后台,一个设计非常优秀的CMS 软件。

示例:Hugo-theme-stack 主题中的图片钩子设置

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
{{- $destination := .Destination | safeURL -}}  
{{- $filename := path.Base $destination -}}  // 增加一个变量用来提取文件名
{{- $image := .Page.Resources.GetMatch $filename -}}  // 依旧使用Resources.GetMatch函数来匹配图片资源,只不过换成了$filename变量,而不是之前的纯路径匹配

{{- if $image -}}
  {{- $permalink := $image.RelPermalink | safeURL -}}  // $image.RelPermalink赋值给$permalink变量
  {{- $alt := .PlainText | safeHTML -}}  
  {{- $width := $image.Width -}}  // $image.Width赋值给$width变量
  {{- $height := $image.Height -}}  // $image.Height赋值给$height变量
  {{- $srcset := "" -}}  

   {{- $notSVG := ne (path.Ext $filename) ".svg" -}}  // 同步修改SVG判断逻辑
  {{- $galleryImage := false -}}  

  {{- if $notSVG -}}
      {{- $width = $image.Width -}}  
      {{- $height = $image.Height -}}  
      {{- $galleryImage = true -}}  

      {{- if (default true .Page.Site.Params.imageProcessing.content.enabled) -}}
          {{- $small := $image.Resize "480x" -}}  
          {{- $big := $image.Resize "1024x" -}}  
          {{- $srcset = printf "%s 480w, %s 1024w" $small.RelPermalink $big.RelPermalink -}}  
      {{- end -}}
  {{- end -}}

  <img src="{{ $permalink }}"  
       {{ with $width }}width="{{ . }}"{{ end }}  
       {{ with $height }}height="{{ . }}"{{ end }} 
       {{ with $srcset }}srcset="{{ . }}"{{ end }}  
       loading="lazy"
       {{ with $alt }}alt="{{ . }}"{{ end }}  
       {{ if $galleryImage }}
           class="gallery-image"
           data-flex-grow="{{ div (mul $image.Width 100) $image.Height }}"  
           data-flex-basis="{{ div (mul $image.Width 240) $image.Height }}px"  
       {{ end }}>
{{- else -}}
    <img src="{{ "links/error.webp" | relURL }}" alt="Default Image" loading="lazy">  // 新增处理图片未找到的情况
{{- end -}}

备注:需要批量将index.md 所在文件夹内所有 images 文件夹中的图片文件上提一级使其与index.md 并列

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
#!/bin/bash

# 定义content目录的路径
CONTENT_DIR="D:/Hugo/content/posts"

find "$CONTENT_DIR" -type d -name "images" | while read -r IMAGES_DIR; do
   
    PARENT_DIR=$(dirname "$IMAGES_DIR")
    
       mv "$IMAGES_DIR"/* "$PARENT_DIR"/
    
    # 删除空文件夹
    rmdir "$IMAGES_DIR"
done
All textual works on this website are protected by copyright, and the authors reserve all rights. The photos on this website, unless specifically stated, licensed under the CC BY-NC-ND 4.0 license.
Built with Hugo & Stack, Powered by Github.
全站共 300 篇文章 合计 824072 字
本站已加入BLOGS·CN