Notes by Bill Alive

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.
  • Both the file and individual headings usually have them.
  • Lowest level property takes precedence, and replaces all other values for the property.
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.

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.