Introduction
Today I decided to reconfigure org-roam-capture-templates
. I haven’t changed this custom variable for months.
My use case
I use org-roam-node-find
to search nodes. When a node is not found, I type the name of the new node in the prompt shown by org-roam-node-find
and press Enter. In the version of Org Roam that I’m using (version 2.2.2), org-roam-node-find
automatically creates a new node when the user press Enter and there’s no selected node.
I don’t create nodes through org-roam-capture
.
My previous configuration
When using the configuration in the first code block below, nodes are created as shown in the second code block below.
(setq org-roam-capture-templates '(("d" "default" plain "%?" :target (file+head "%<%Y_%m_%d_%H_%M_%S_%N_%z>.org" "#+TITLE: ${title}") ;; We set immediate-finish to t because we want to switch to the ;; buffer that has the new node. If :immediate-finish equals ;; nil, a new window is opened for the new node, the name of ;; that window has the prefix "CAPTURE-". :immediate-finish t)))
:PROPERTIES: :ID: fafaeaac-46e8-4b85-a310-ebdad6feaab5 :END: #+TITLE: Title of a node <point>
I wanted to store the creation date of each node, so I added a hook to org-roam-capture-new-node-hook
.
(defun my-org-roam-set-property-created-top-property-drawer () (save-excursion (goto-char (point-min)) (org-set-property "CREATED" (format-time-string "[%Y-%m-%d %H:%M:%S %z]")))) (add-hook 'org-roam-capture-new-node-hook 'my-org-roam-set-property-created-top-property-drawer)
:PROPERTIES: :ID: c8e231df-d7b2-402e-9e69-6caaf4e26f23 :CREATED: [2024-09-20 22:48:26 -0500] :END: #+TITLE: Title of a node <point>
I wanted to remove the spaces in the properties drawer were unnecessary, so I removed them by setting org-property-format
as shown in the first code block below. The second code block below shows the result of creating a node.
(setq org-property-format "%s %s")
:PROPERTIES: :ID: a7e89a71-96b7-419a-aeb1-7dbfea3606b3 :CREATED: [2024-09-20 23:00:58 -0500] :END: #+TITLE: Title of a node <point>
I wanted to separate the properties drawer and the title with an empty line, so I added the hook shown in the first code block below.
(defun my-org-roam-insert-empty-line-above-title () (save-excursion (goto-char (point-min)) (search-forward "#+TITLE:") (beginning-of-line) (newline))) (add-hook 'org-roam-capture-new-node-hook 'my-org-roam-insert-empty-line-above-title)
:PROPERTIES: :ID: 59f88b7d-4da0-45d5-96ee-711210a37e32 :CREATED: [2024-09-20 23:07:49 -0500] :END: #+TITLE: Title of a node <point>
Reason I decided to change my configuration
Let me make something clear: There are two possible formats to define an Org Roam node: (1) using #+TITLE
and setting ID
in the top property drawer in an Org Mode file (see first code block below) and (2) setting the property ID
in a headline (see second code block below).
:PROPERTIES: :ID: fad0e874-35fb-4548-a08b-7ee232f4bf20 :CREATED: [2024-09-20 23:25:24 -0500] :END: #+TITLE: Title of an Org Roam node
* Title of an Org Roam node :PROPERTIES: :ID: fad0e874-35fb-4548-a08b-7ee232f4bf20 :CREATED: [2024-09-20 23:25:24 -0500] :END:
Most of my Org Roam nodes are headlines inside an Org Mode file that has #+TITLE
and ID
in the top property drawer (the #+TITLE
usually is the main subject of all the headlines in that specific Org Mode file). I initially created Org Roam nodes using the format #+TITLE
because that was the default configuration.
I have now decided to only use headlines because I usually move nodes between files in org-roam-directory
and it is easier to move nodes when they are headlines: I can select an entire subtree using org-mark-element
(by default, bound to M-h
in org-mode-map
).
My current configuration
I had to add the hook my-org-roam-remove-top-property-drawer
because Org Roam automatically sets an ID for the top property drawer and it seems that it is not possible to change that behavior. See this thread in the official Org Roam forum.
(setq org-roam-capture-templates `(("d" "default" entry ,(string-join '("* ${title}" ":PROPERTIES:" ":ID: %(org-id-new)" ":CREATED: %(my-org-verbose-timestamp)" ":END:") "\n") :target (file "%<%Y_%m_%d_%H_%M_%S_%N_%z>.org") :immediate-finish t))) (defun my-org-roam-remove-top-property-drawer () (save-excursion (goto-char (point-min)) (let* ((element (org-element-at-point-no-context)) (type (org-element-type element))) (when (eq type 'property-drawer) (delete-region (org-element-begin element) (org-element-end element)))))) (add-hook 'org-roam-capture-new-node-hook 'my-org-roam-remove-top-property-drawer)
Conclusion
My current configuration can’t automatically create nodes with the format #+TITLE
. The only reason I would create an Org Roam using #+TITLE
is when I need to export the Org Roam to PDF because #+TITLE
has a special meaning for the Org Mode PDF exporter. In my current workflow, I hardly ever need to export to PDF. When I need to do it, I will use the default template and manually set #+TITLE
. I could define a yasnippet that inserts #+TITLE:
to help me do this.