At $dayjob I take notes using org-mode and from time to time end up sharing these as exported PDF's or HTML files. When I export a subtree these notes end up overwriting the same file over and over again, the file workbook-2021.pdf when using i.e. C-c C-e C-s l p. I would like to have subtrees export to a file named workbook-2021-headline.pdf.

Using code shared by Melioratus on the Emacs Stack Exchange I was able to write a function that finds the current headline and removes non-alphanumeric characters.

(defun headline-title()
    (let* ((headline
                        (org-element-property :title (org-element-at-point)))))
        (replace-regexp-in-string "[^[:alnum:]-_]" "-" headline)))

I then want for this string to be appended to the filename of the current org-file when exporting the subtree. So given the following file named export-subtree.org and that the cursor is standing under the heading of "Works of wizards" then the file name would be export-subtree-Works-of-wizards.pdf:

* Week 1
** 2021-01-01
*** Concerning Hobbits
A word or two about their lore.
*** Works of wizards
Many more about wandering| wizards.

But this is where my Emacs foo comes short. I really don't know where to start. Because I do not want to be adding a property to every headline I want to export with a different name as many other answers on this network suggests.


Try this function:

(defun my/org-export-headline (&optional backend async subtreep visible-only body-only ext-plist)
  "Export the current Org headline using BACKEND.

The available backends are the ones of `org-export-backends' and

When optional argument SUBTREEP is non-nil, transcode the
sub-tree at point, extracting information from the headline
properties first.

When optional argument VISIBLE-ONLY is non-nil, don't export
contents of hidden elements.

When optional argument BODY-ONLY is non-nil, only return body
code, without surrounding template.

Optional argument EXT-PLIST, when provided, is a property list
with external parameters overriding Org default settings, but
still inferior to file-local settings."
  (let* ((backend (unless backend
                     (completing-read "Available backends: "
                                      (append org-export-backends '(pdf))))))
         (headline (car (last (org-get-outline-path t))))
         (headline-alnum (replace-regexp-in-string "[^[:alnum:]-_]" "-" headline))
         (file-prefix (file-name-sans-extension (buffer-file-name)))
         (filename (format "%s-%s.%s" file-prefix headline-alnum
                           (if (eq backend 'pdf) "tex" backend))))
       (if (eq backend 'pdf) 'latex backend)
        filename async subtreep visible-only body-only ext-plist
      (when (eq backend 'pdf)
        (lambda (file) (org-latex-compile file))))

Usage: M-x my/org-export-headline and select a backend (e.g. pdf, html, etc.).

It may look over-complicated, but it is in fact really simple. To let it support pdf export, I inspired myself from org-latex-export-to-pdf which unfortunately force you to use its filename. I also make it support org-export-to-file extra parameters as org-latex-export-to-pdf does and copy-pasted its docstring. If you ignore the conditional (if (eq backend 'pdf) ...), it's really a matter of narrowing, org-export-to-file, then widening.

This site is temporarily in read only mode and not accepting new answers.

Not the answer you're looking for? Browse other questions tagged .