How can I position \label outside \caption in LaTeX export of figures?

Say you have a figure in your org-mode file like the following one:

#+NAME: fig:first-figure
#+CAPTION: Some caption
#+BEGIN_figure
This is a figure.
#+END_figure


This is exported to LaTeX code where \label is put inside the argument of \caption:

\begin{figure}
This is a figure.
\caption{\label{fig:first-figure}
Some caption}
\end{figure}


However, this may cause problems in some templates such that the references to the figure will be ill-formed. This can be repaired by putting the \label command outside and after \caption:

\begin{figure}
This is a figure.
\caption{Some caption}
\label{fig:first-figure}
\end{figure}


Right now, I'm using macros to achieve this in the LaTeX file, but this doesn't feel right...

How can I adjust the export routine to change the order of \label and \caption?

I've met the same problem. The only way I've found is to redefine the function that handles that part of the export and to put it as a emacs-lisp source block at the beginning of my org file.

Here is what I did:

(defun org-latex--caption/label-string (element info)
"Return caption and label LaTeX string for ELEMENT.

INFO is a plist holding contextual information.  If there's no
caption nor label, return the empty string.

For non-floats, see org-latex--wrap-label'."
(let* ((label (org-latex--label element info nil t))
(main (org-export-get-caption element))
(type (org-element-type element))
(nonfloat (or (and (plist-member attr :float)
(not (plist-get attr :float))
main)
(and (eq type 'src-block)
(not (plist-get attr :float))
(null (plist-get info :latex-listings)))))
(short (org-export-get-caption element t))
(caption-from-attr-latex (plist-get attr :caption)))
(cond
((org-string-nw-p caption-from-attr-latex)
(concat caption-from-attr-latex "\n"))
((and (not main) (equal label "")) "")
((not main) label)
;; Option caption format with short name.
(t
(format (if nonfloat "\\captionof{%s}%s{%s}\n%s"
"\\caption%s%s{%s}\n%s")
(let ((type* (if (eq type 'latex-environment)
(org-latex--environment-type element)
type)))
(if nonfloat
(cl-case type*
(paragraph "figure")
(image "figure")
(special-block "figure")
(src-block (if (plist-get info :latex-listings)
"listing"
"figure"))
(t (symbol-name type*)))
""))
(if short (format "[%s]" (org-export-data short info)) "")
(org-export-data main info)
label)))))


The original function is on the ox-latex.el file of the org-mode package, if you want to have a look. What I've modified are the lines with "\caption" and "\captionof" and I've inverted the position of the two last elements. Hope this works for you.

• This is great! I think it's very small change that is strictly an improvement on the current code. Please consider contirbuting this to Org, you can start by writing to the Org mailing list.
– Omar
Jul 5 '19 at 13:15
• @Omar I agree. I don't see why \label needs to be inside \caption`.
– Timm
Jul 6 '19 at 14:41