Org Mode Keywords vs. Properties
Once you start Programming Org Mode, you’ll probably want to manipulate keywords and properties.
They’re different, and you use different tools to work with them.
For example, this post I’ve just started already has both keywords and properties at the file level:
:PROPERTIES:
:ID: 16b7ded8-3eda-444e-a419-b57a6e9e23a1
:END:
#+title: Org Mode Keywords vs. Properties
#+date: 2022-06-11
#+hugo_draft: true
Properties live in :PROPERTIES:
The (sole) property is in the :PROPERTIES:
drawer:
:PROPERTIES:
:ID: 16b7ded8-3eda-444e-a419-b57a6e9e23a1
:END:
Get an Org Mode Property
You can retrieve that property programmatically with, e.g.
(plist-get (org-element--get-global-node-properties) :ID)
RESULTS:
16b7ded8-3eda-444e-a419-b57a6e9e23a1
Note that we access the property with :ID
, not "ID"
.
Also note that, because I knew I wanted the properties for the entire file, I used org-element--get-global-node-properties
.
If I instead wanted the properties for the closest heading to the Emacs point, I would use org-element--get-node-properties
.
Set an Org Mode Property
You can set the property programmatically with:
(org-set-property "ID" "random-id-oops")
This time, we access the property with "ID"
, as you might expect.
IMPORTANT You’ll need to have the Emacs point in the right place, because org-set-property
acts on the closest entry. In fact, when I ran that code just now, it set the ID of the local heading (“Set an Org Mode Property”).
(I could not find anything like org-set-global-property
). If you can, let me know.)
Moving the point to edit the property feels slightly brittle to me, so for a file-level value, we might want to use a keyword instead.
Keywords start with #+
My new file’s keywords look like this:
#+title: Org Mode Keywords vs. Properties
#+date: 2022-06-11
#+hugo_draft: true
Get an Org Mode Keyword
I’m using ox-hugo
to publish this post, so the draft status is set with the keyword:
#+hugo_draft: true
I can programmatically get the value of this keyword with:
(org-collect-keywords '("HUGO_DRAFT"))
RESULTS:
HUGO_DRAFT | true |
Since I’m not ready to publish this post yet, the draft status is true
.
Note that keywords should be capitalized here, even if they aren’t in your actual text.
Also note the extra parentheses and apostrophe. You could (probably) collect multiple keywords at a time, should you desire.
Can individual headings have keywords?
YES. I didn’t expect this, because I’ve never seen it, but watch what happens if I add a hugo_draft
keyword to this heading.
Test heading with keyword
You can’t see it, but this heading has this keyword:
#+hugo_draft: oops
Let’s get the keyword(s) again:
(org-collect-keywords '("HUGO_DRAFT"))
RESULTS:
HUGO_DRAFT | false | oops |
Note that we have both keywords. If these were properties, the heading would override the file. For example, each heading can have its own ID
property.
But I wouldn’t use keywords on headings
I’ve never seen keywords anywhere but at the file level.
There must be a good use for this… or not?
Set an Org Mode Keyword
I’m about ready to publish this post. Let’s set the draft status to false
.
(org-roam-set-keyword "HUGO_DRAFT" "false")
It worked! My keyword at the top now shows:
#+hugo_draft: false
And it did not change the second hugo_draft
that I added as a test under “Test heading with keyword.”
IMPORTANT this function doesn’t come with Org Mode; it’s provided by Org-roam. There’s probably a vanilla way to do this.
Should you use a property or a keyword?
I assume there are well-thought-out reasons for choosing one or the other.
At first glance, the obvious differences are:
- Properties
- Invisible.
- Tucked away in the
PROPERTIES
drawer.
- Tucked away in the
- Both the file and individual headings usually have them.
- Lowest level property takes precedence, and replaces all other values for the property.
- Invisible.
- Keywords
- Visible.
- Sometimes you want that, e.g. the draft status of a post.
- I usually see them only at the file level.
- You can also add them to headings.
- But I’m not sure how to set them at the heading level, only at the file level.
- No precedence(?): If you reuse the keyword, the values accumulate.
- Visible.
Since a draft status should only be true or false, maybe a property would be more appropriate. But it’s important enough to me to see this status at a glance that I will stick to using a single, file-level keyword.
I hope this helps! This feels like the kind of basic distinction that can be hard to find an explanation for.