I would like to set the #+OPTIONS: settings in an org-mode file to behave differently if the org-mode file is exported to HTML or to PDF.

More precisely, I would like to have control of

  • the table of contents,
  • the numbering of the sections and
  • the depth of the headers.

I would like to setup my org-mode document such that the behaviour is different if I export the same file to different format:

  • For PDF export C-c C-e l p, no table of contents, the sections numbered:
#+OPTIONS: toc:nil num:t H:7 
  • For HMTL export C-c C-e h h, with table of contents, the sections not numbered:
#+OPTIONS: toc:2 num:nil H:4

How can I do this?


EDIT 2021-04-05): there is a better solution, based on an idea of Juan Manuel Macías on the Org mode mailing list. It is based on macro expansion and the fact that you can evaluate arbitrary Lisp code in the macro definition. The details are presented in this Emacs SE question: Can org options be applied to specific export modes only?.

Here is one possible solution that uses the #+INCLUDE: mechanism. Another possible option is (probably) an options filter, but I have not investigated that.

The idea is to have an Org mode file like this:


* Links

* Foo
** bar
*** baz

**** hunoz
***** hukerz

and a bunch of options files, one for each possible export backend:


#+OPTIONS: toc:2 num:nil H:4


#+OPTIONS: toc:nil num:t H:7


The trick is to then replace the <SUFFIX> with the relevant backend at the time you export.

org-export-as, the main function that gets called when you are exporting a file, does things in a definite order:

  • include file processing
  • macro expansion
  • babel processing
  • options filters
  • pruning of tree
  • parse-tree filters
  • collect properties
  • transcode tree
  • final output filters

The point is that you cannot use later things to change earlier things, since the earlier things are already done. Since the includes are processed first, we cannot use any of the other mechanisms to change the suffix. Fortunately, there are various hooks that are applied at specific times during the export process. One such hook is org-export-before-processing-hook, which is the first thing that is done, before the include file processing step. This hook is a list of functions (as is any hook), but the functions in this hook are expected to take a single argument: the export backend. The hook runs through the list and calls each function with the current export backend.

Perfect! All we need to do is define a function that does the edit of the #+INCLUDE: line and add it to the hook, like this:

(defun ndk/org-export-edit-suffix (backend)
  (replace-string "opts.<SUFFIX>" (format "opts.%s" backend)))

(add-hook 'org-export-before-processing-hook #'ndk/org-export-edit-suffix)

and we are done. When you export to HTML, the backend is "html" and we include opts.html and when you export to PDF, the backend is "latex" and we include opts.latex.

One obvious caveat: make sure that you do not have another instance of the replacement string opts.<SUFFIX> in your file or it will be modified as well. You can make the replace-string arguments longer to match e.g. the whole #+INCLUDE: line, if that is a problem.

  • Thank you very much for your answer! I appreciate that you not only gave the correct answer but also provide a comprehensive insight of the org-export system. Your solution works and it seems to me a valid workaround to my problem. – chan gimeno Oct 1 '20 at 18:07
  • However, the org-export-before-processing-hook hook does not solve the problem of nested included files, the case I am interested in (and inaccurately described above). The solution given by @Nick works if opts.<SUFFIX> is #+included in the file you export. But, the the main org file, main.org includes another one, say headers.org, and the headers.org has the statement #+INCLUDE: opts.<SUFFIX>, the proposed solution does not work. I have also tried (add-hook 'org-export-before-parsing-hook #'ndk/org-export-edit-suffix) and also does not work. Any idea how to do it? – chan gimeno Oct 1 '20 at 19:14
  • I can't think of a way to do that off the top of my head. You might want to ask it as a separate question and emphasize the nesting: that will give it more visibility. – NickD Oct 1 '20 at 21:21
  • 1
    Ok, thanks! I have already accepted your answer as he correct one. I will create a different question for the nesting. – chan gimeno Oct 2 '20 at 9:03

The solution given by @NickD is correct.

A solution that would work also for nested org files would be using macros (see related question and the macros defined by fniessen).

In a test case where the content main.org is separated from the settings header.org, one can export differently for different backends as follows:

  • In the content file main.org, the settings are "#+INCLUDED":
#+INCLUDE: headers.org  

* The first section  

  Contents here
  • The backend dependent settings are included in headers.org using macros:
#+MACRO: if-latex-else (eval (if (org-export-derived-backend-p org-export-current-backend 'latex) "#+OPTIONS: toc:nil H:7 num:t"
"#+OPTIONS: toc:2 num:nil H:4"))


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.