结合 denote 和 org-publish 写博客

最近又折腾了一下博客,把文章都用 denote 来命名管理,方便后面文章多了维护。

这里面主要有一个问题是,denote 的文件名很长,而且可能会变化,如果作为导出的 URL,那么这个 URL 就可能会经常变,如果有人引用了旧的 URL,再访问就会是 404。

在翻 org-mode export 的 info 的时候,发现一个 keyword,#+export_file_name,可以设置导出的文件名,正好解决我这个问题。

此外,还需要处理一些问题:

  • denote 内部链接的导出,使用 export_file_name 作为链接名
  • org-publish 基于 denote keyword 过滤文件
  • org-publish 输出的 sitemap,使用 export_file_name 作为链接名

都处理完之后,目前用着还行,所以分享一下,如果你也打算用 denote 来管理博客文章的话,希望对你有帮助。

5 个赞

可以这样:

(defun my/ox-files ()
  "返回一个包含'blog'标签的'denote'文件路径列表"
  (denote-directory-files "_blog"))

……
(setq org-publish-project-alist
        ;; 处理帖文
        `(("posts"
           :exclude ".*"
           :include ,(my/ox-files)
)))
1 个赞

Cool!学习了,thanks!

denote-directory-files 只会搜索 denote-directory 里的文件,但是我用了 silos,和 denote-directory 不是一个目录。

我需要临时改变 denote-directory 的值后再使用 denote-directory-files

  (defun spike-leung/get-file-list-from-denote-silo (silos tag)
    "Return files in SILOS match TAG.
  SILO is a file path from `denote-silo-directories'.
  TAG is string."
    (cl-letf ((denote-directory (expand-file-name silos)))
      (denote-directory-files tag)))

(setq org-publish-project-alist
        `(("orgfiles"
           :base-directory "~/git/taxodium/posts"
           :base-extension "org"
           :exclude ".*"
           :include  ,(spike-leung/get-file-list-from-denote-silo "~/git/taxodium/posts" "_published")
          ;; 省略部分代码
          )

          ;; 省略部分代码
          ))

比我原来用 exclude 排除直观和方便得多,非常感谢。

2 个赞

这个方法似乎有个问题,当新增了一篇文章的时候,需要重新执行 setq org-publish-project-alist,让它获取到最新的文件列表,新增的文章才会被发布。

不知道你有没碰到,如果碰到了你又是如何解决的。

可能会对你有所帮助。

谢谢你的分享!

这是我从你文章中看到的 puhlish 配置:

;; Define the publishing project
(setq org-publish-project-alist
      (list
       (list "org-site:main"
             :recursive t
             :base-directory "./content"
             :publishing-function 'org-html-publish-to-html
             :publishing-directory "./public"
             :exclude-tags '("draft" "noexport")
             :exclude "draft*"
             :with-author  t
             :with-creator t
             :with-toc t
             :with-email t
             :html-link-home "/"
             :section-numbers nil
             :time-stamp-file nil)))

看起来你应该主要是通过 :exclude:exclude-tags 过滤文件?

:exclude-tags 我在 org-publish 的 info 里好像没有看到。

:exclude 我尝试过,但是我目前有三种 tag: publisheddraftblackhole(一些特殊的页面)

因为我所有的文章都在一个目录里,如果用 :exclude 的话,对于 published 的文章,我需要 exclude draftblackhole,如果后面有更多的 tag,我就需要排除更多。而对于 draft 我又需要排除 publishedblackhole。感觉有些麻烦,没有用 :include 来得直观。


看了你的文章我也收获了不少,例如 org-html-home/up-format 可以设置一个固定在顶部的内容。

利用 org-export-before-processing-hook 可以给每个页面添加一些内容。

你实现了 tags!我一直也想实现,我会研究一下你是怎么做的,我也想做一个 tag page。

关于 setup.org,我尝试了一下,它的内容会出现在 toc 下面。

我也看到你的配置:

#+OPTIONS: toc:nil
#+TOC: headlines 5

就是用来解决这个问题的吗?

但这是每个文件都引用的内容,有的文章只需要 headlines 1,看起来还需要写点 Elisp 判断一下?


另外,我有一些关于博客的小建议:

  • 作用在 html 上的这个 filter,会影响一些插件的样式表现,看起来有点怪= =

  • 代码块可以考虑添加一个 Copy 按钮?因为页面不足以显示所有的代码,我更倾向于复制下来在 Emacs 里看,我尝试了鼠标选择一直往下滚动,直到选择全部,但不知道为什么页面滚动的很慢(似乎只在那个 Full Script 的代码块中滚动比较慢)
(defun my/org-project-update (&optional ARG PRED)
  "这个函数的作用是动态更新`org-publish-project-alist',以便及时匹配'denote'文件标签的变动。"
  (setq org-publish-project-alist
        ;; 处理帖文
        `(("posts"
           :exclude ".*"
           :include ,(my/ox-files)))))

(advice-add #'org-export-dispatch :before 'my/org-project-update)
1 个赞

把 advide 加载 org-publish 之前也可以。

(advice-add 'org-publish :before #'spike-leung/setup-org-publish-project-alist)

如果您想改变标题数量,很简单。

(defun remove-org-element (string)
  "Delete the first element which contains STRING."
  (save-excursion
    (search-backward string nil t 2)
    (goto-char (match-beginning 0))
    (org-mark-element)
    (delete-region (region-beginning) (region-end))))

在文档中设定一些其他的参数。

#+begin_src emacs-lisp :exports results
  (remove-org-element "#+TOC:")
#+end_src

移除 #+TOC: 行,然后在该页面添加自己的 TOC。

博客贴士:

  • 过滤器是用来获取光线主题的,我以前只知道CSS中的黑色主题(有点懒我承认)。
  • 我会尝试添加它。虽然src块没有什么问题。
2 个赞