The following command lets you choose a back-end and then exports each top-level subtree to a separate file:
(defun org-export-all (backend)
"Export all subtrees that are *not* tagged with :noexport: to
separate files.
Note that subtrees must have the :EXPORT_FILE_NAME: property set
to a unique value for this to work properly."
(interactive "sEnter backend: ")
(let ((fn (cond ((equal backend "html") 'org-html-export-to-html)
((equal backend "latex") 'org-latex-export-to-latex)
((equal backend "pdf") 'org-latex-export-to-pdf))))
(save-excursion
(set-mark (point-min))
(goto-char (point-max))
(org-map-entries (lambda () (funcall fn nil t)) "-noexport" 'region-start-level))))
This currently supports HTML (html
), LaTeX (latex
), and PDF (pdf
) export.
You can add support for more back-ends by adding more clauses to cond
.
As the docstring says, for each subtree you need to set the :EXPORT_FILE_NAME:
property to the file name you want it to be exported to. (See below for other options.)
Automatically generating export file name from heading text
If you don't want to add :EXPORT_FILE_NAME:
properties to every top-level heading, you can modify org-export-all
to generate the filename automatically from e.g. the heading text, temporarily setting :EXPORT_FILE_NAME:
during export:
(defun org-export-all (backend)
"Export all subtrees that are *not* tagged with :noexport: to
separate files.
Subtrees that do not have the :EXPORT_FILE_NAME: property set
are exported to a filename derived from the headline text."
(interactive "sEnter backend: ")
(let ((fn (cond ((equal backend "html") 'org-html-export-to-html)
((equal backend "latex") 'org-latex-export-to-latex)
((equal backend "pdf") 'org-latex-export-to-pdf)))
(modifiedp (buffer-modified-p)))
(save-excursion
(set-mark (point-min))
(goto-char (point-max))
(org-map-entries
(lambda ()
(let ((export-file (org-entry-get (point) "EXPORT_FILE_NAME")))
(unless export-file
(org-set-property
"EXPORT_FILE_NAME"
(replace-regexp-in-string " " "_" (nth 4 (org-heading-components)))))
(funcall fn nil t)
(unless export-file (org-delete-property "EXPORT_FILE_NAME"))
(set-buffer-modified-p modifiedp)))
"-noexport" 'region-start-level))))
This function generates the export filename by replacing spaces with "_" in the headline text. If you want to generate the filename some other way, change the replace-regexp-in-string
sexp to whatever you like.
Generating :EXPORT_FILE_NAME:
when setting :CUSTOM_ID:
With the following advice, org-set-property
will automatically set an appropriate value for :EXPORT_FILE_NAME:
when you set :CUSTOM_ID:
:
(defadvice org-set-property (after set-export-file-name
(property value) activate compile)
(when (equal org-last-set-property "CUSTOM_ID")
(let ((export-file-name
(concat (org-entry-get nil "CUSTOM_ID")
"-"
(replace-regexp-in-string " " "-" (downcase (org-get-heading t t))))))
(org-entry-put nil "EXPORT_FILE_NAME" export-file-name))))
Note that this will not add a file extension to the value of :EXPORT_FILE_NAME:
but that doesn't matter because when exporting to a specific back-end, org-mode
will automatically choose the correct extension for the resulting files.
Additional information
Updating existing subtrees in bulk
If you have a large number of existing subtrees that you need to set the :EXPORT_FILE_NAME:
property for, you can use a keyboard macro. Position point on the first subtree, then do the following:
F3
... to start recording.
C-c C-x p CUSTOM_ID
RET RET
... to make Emacs set :EXPORT_FILE_NAME:
based on :CUSTOM_ID:
.
C-c C-f
... to move to the next top-level headline.
F4
... to stop recording.
To repeat the macro for the next subtree, press F4. To repeat the macro for all remaining subtrees, press M-0 F4 (that's a zero).
Saving macros for future sessions
By default, keyboard macros are not saved across sessions. To store the macro in your init-file for later use, do this:
Name the macro:
M-x name-last-kbd-macro
RET org-set-export-file-name
RET
Find your init-file and move to a spot where you would like to insert the macro.
Insert the macro:
M-x insert-kbd-macro
RET org-set-export-file-name
RET
Emacs will insert the following code at point:
(fset 'org-set-export-file-name
"\C-c\C-xpCUSTOM_ID\C-m\C-m\C-c\C-f")
If you squint hard enough you can see that the second argument to fset
contains the sequence of keys that you pressed when you recorded the macro :)
(Optional) For best results, you might want to bind org-set-export-file-name
to a key:
(define-key org-mode-map (kbd "<f6>") 'org-set-export-file-name)
Save.