用denote配合ox-publish导出博客
之前写过一篇org-roam的相关教程:使用advice自动更新ox-publish的待发布org-roam文件目录。现在切换到了denote,有必要更新一下相关代码了。
直接使用denote时,可以把形如 [[denote:]]
的denote链接当作普通的 [[file:]]
链接。但是由于denote文件的文件名变化频繁,如果你和我一样选择通过网页手动上传导出的html文件到GitHub,则会遇见恼人的重复问题。另一方面,直接生成的文件链接也很长,很不直观。所以我们可以通过以下设置,将导出的文件名设置为denote标识符。
代码参考:使用 org-mode 写博客
1. 确定导出文件范围
(defun my/ox-files () "Return a list of note files containing 'blog' tag." (denote-directory-files "_blog"))
2. 自定义导出配置
(defun my/org-project-update (&optional ARG PRED) ;;使用before会接收到原函数参数,因此需要添加optional (setq org-publish-project-alist `(("posts" ;; 帖子配置项,略去了其他无关选项 :exclude ".*" :include ,(my/ox-files) :auto-sitemap t :html-link-home "index.html" :sitemap-filename "index.org" :sitemap-title "目录" :sitemap-format-entry my/org-publish-sitemap-format-entry ) ("static" ;; 静态资源配置项,略去) ("rss" ;; rss配置项,略去了其他无关选项 :exclude ".*" :include ,(my/ox-files) :publishing-function publish-posts-rss-feed :auto-sitemap t :sitemap-function posts-rss-feed :sitemap-format-entry format-posts-rss-feed-entry) ("personal-website" :components ("posts" "static" "rss"))))) ;; 为了确保及时动态更新导出文件目录,需要在导出函数执行前重新赋值一次 org-publish-project-alist (advice-add 'org-export-dispatch :before 'my/org-project-update) ;; 以下函数用于修改index.html/index.org的链接 (defun my/org-publish-sitemap-format-entry (entry style project) "格式化站点地图中的每个条目,显示标题、日期和摘要。" (let* ((title (or (org-publish-find-title entry project) (file-name-base entry))) (id (denote-retrieve-filename-identifier (file-name-base entry)))) (format "[[denote:%s][%s]]\n" id title))) ;; 以下函数用于修改rss.xml/rss.org的链接 (defun publish-posts-rss-feed (plist filename dir) "Publish PLIST to RSS when FILENAME is rss.org. DIR is the location of the output." (if (equal "rss.org" (file-name-nondirectory filename)) (org-rss-publish-to-rss plist filename dir))) (defun format-posts-rss-feed-entry (entry _style project) "Format ENTRY for the posts RSS feed in PROJECT." (let* ( (title (org-publish-find-title entry project)) (link (concat (denote-retrieve-filename-identifier (file-name-sans-extension entry)) ".html")) (pubdate (format-time-string (car org-time-stamp-formats) (org-publish-find-date entry project)))) (message pubdate) (format "%s :properties: :rss_permalink: %s :pubdate: %s :end:\n" title link pubdate)))
有了上述函数,导出denote文件为html时就可以用标识符作为文件名称了。
3. 修改导出链接处理函数
(defun denote-link-ol-export (link description format) "Modified version of `denote-link-ol-export'. Retrieve ID, replace anchor with it Original docstring below: Export a `denote:' link from Org files. The LINK, DESCRIPTION, and FORMAT are handled by the export backend." (let* ((path-id (denote-link--ol-resolve-link-to-target link :full-data)) (path (file-relative-name (nth 0 path-id))) (id (nth 1 path-id)) (query (nth 2 path-id)) (anchor (file-name-sans-extension path)) (desc (cond (description) (query (format "denote:%s::%s" id query)) (t (concat "denote:" id))))) (cond ((eq format 'html) (if query (format "<a href=\"%s.html%s\">%s</a>" (denote-retrieve-filename-identifier anchor) query desc) (format "<a href=\"%s.html\">%s</a>" (denote-retrieve-filename-identifier anchor) desc))) ((eq format 'latex) (format "\\href{%s}{%s}" (replace-regexp-in-string "[\\{}$%&_#~^]" "\\\\\\&" path) desc)) ((eq format 'texinfo) (format "@uref{%s,%s}" path desc)) ((eq format 'ascii) (format "[%s] <denote:%s>" desc path)) ((eq format 'md) (format "[%s](%s)" desc path)) (t path))))