Two hooks are run during the first steps of the export process. The first
org-export-before-processing-hook is called before expanding
macros, Babel code and include keywords in the buffer. The second one,
org-export-before-parsing-hook, as its name suggests, happens just
before parsing the buffer. Their main use is for heavy duties, that is
duties involving structural modifications of the document. For example, one
may want to remove every headline in the buffer during export. The following
code can achieve this:
(defun my-headline-removal (backend) "Remove all headlines in the current buffer. BACKEND is the export back-end being used, as a symbol." (org-map-entries (lambda () (delete-region (point) (progn (forward-line) (point)))))) (add-hook 'org-export-before-parsing-hook 'my-headline-removal)
Note that functions used in these hooks require a mandatory argument, a symbol representing the back-end used.
Filters are lists of functions applied on a specific part of the output from a given back-end. More explicitly, each time a back-end transforms an Org object or element into another language, all functions within a given filter type are called in turn on the string produced. The string returned by the last function will be the one used in the final output.
There are filters sets for each type of element or object, for plain text,
for the parse tree, for the export options and for the final output. They
are all named after the same scheme:
TYPE is the type targeted by the filter. Valid types are:
For example, the following snippet allows me to use non-breaking spaces in
the Org buffer and get them translated into LaTeX without using the
\nbsp macro (where
_ stands for the non-breaking space):
(defun my-latex-filter-nobreaks (text backend info) "Ensure \"_\" are properly handled in LaTeX export." (when (org-export-derived-backend-p backend 'latex) (replace-regexp-in-string "_" "~" text))) (add-to-list 'org-export-filter-plain-text-functions 'my-latex-filter-nobreaks)
Three arguments must be provided to a filter: the code being changed, the
back-end used, and some information about the export process. You can safely
ignore the third argument for most purposes. Note the use of
org-export-derived-backend-p, which ensures that the filter will only
be applied when using
latex back-end or any other back-end derived
from it (e.g.,
This is obviously the most powerful customization, since the changes happen at the parser level. Indeed, some export back-ends are built as extensions of other ones (e.g., Markdown back-end an extension of HTML back-end).
Extending a back-end means that if an element type is not transcoded by the new back-end, it will be handled by the original one. Hence you can extend specific parts of a back-end without too much work.
As an example, imagine we want the
ascii back-end to display the
language used in a source block, when it is available, but only when some
attribute is non-
nil, like the following:
#+ATTR_ASCII: :language t
Because that back-end is lacking in that area, we are going to create a new
my-ascii that will do the job.
(defun my-ascii-src-block (src-block contents info) "Transcode a SRC-BLOCK element from Org to ASCII. CONTENTS is nil. INFO is a plist used as a communication channel." (if (not (org-export-read-attribute :attr_ascii src-block :language)) (org-export-with-backend 'ascii src-block contents info) (concat (format ",--[ %s ]--\n%s`----" (org-element-property :language src-block) (replace-regexp-in-string "^" "| " (org-element-normalize-string (org-export-format-code-default src-block info))))))) (org-export-define-derived-backend 'my-ascii 'ascii :translate-alist '((src-block . my-ascii-src-block)))
my-ascii-src-block function looks at the attribute above the
element. If it isn't true, it gives hand to the
Otherwise, it creates a box around the code, leaving room for the language.
A new back-end is then created. It only changes its behavior when
src-block type element. Now, all it takes to use the new
back-end is calling the following from an Org buffer:
(org-export-to-buffer 'my-ascii "*Org MY-ASCII Export*")
It is obviously possible to write an interactive function for this, install it in the export dispatcher menu, and so on.