Org-mode has a bundled extension called org-id
, that implements global unique IDs for org-mode files. Every entry (a headline with its body) can have an ID property in its :PROPERTIES:
drawer.
New ID for a single entry can be assigned with a function org-id-get-create
.
How can I assign an ID to every entry in an org-mode file?
I could use an Emacs method of automating this, like a macro that calls org-id-get-create
for every string starting with *
. But I'd like to know if org-mode already has that capability. If not, please recommend the most idiomatic way to write an elisp code for this purpose.
I agree with Stuart—I don't think there's anything in org-id to do this automatically so it really comes down to when you want to add the ids.
If you use org-capture to add all of your items then org-capture-prepare-finalize-hook
is a logical place to put the code:
(add-hook 'org-capture-prepare-finalize-hook 'org-id-get-create)
Alternately you could do as Stuart suggested and add a save hook for org-mode files. I think the most idiomatic way to process all of the headlines in the file would be to use the mapping API:
(defun my/org-add-ids-to-headlines-in-file ()
"Add ID properties to all headlines in the current file which
do not already have one."
(interactive)
(org-map-entries 'org-id-get-create))
Finally we just need to add a before-save-hook
which only runs in org-mode:
(add-hook 'org-mode-hook
(lambda ()
(add-hook 'before-save-hook 'my/org-add-ids-to-headlines-in-file nil 'local)))
That should do it!
I searched through the source and couldn't find anything obvious to do this already. I know it's used by Org-mobile, but I've not much experience of that.
By way of a starter, the following snippet will loop through all outline headings in the current file (Org-mode headings are basically standard Emacs outline headings), and add an ID if there's not already one there:
(require 'org-id)
(save-excursion
(goto-char (point-max))
(while (outline-previous-heading)
(org-id-get-create)))
(If you're wondering why this loop goes backwards over the buffer rather than forwards, it's because the while
loop will always call the outline navigation function at least once and if your Org-mode file starts with a heading this would be skipped if going forwards.)
This could be reasonably easily used within a loop over all the files known to the Org-mode agenda by looping over the entries returned by the function (org-agenda-files)
, or added to a save hook for Org-mode files.
If someone more nimble-fingered than I doesn't get there first, if you can identify when you'd like the IDs added I could probably expand the above to be a complete solution.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With