0

In this answer I have been suggested to patch hyperref’s automatic pdfauthor metadata handling mechanism as follows. The goal is to have PDF metadata work with authblk and multiple authors.

\documentclass{article}
\usepackage[pdfusetitle]{hyperref}
\usepackage{authblk}
\usepackage{xpatch}

\newtoggle{patchhref}
\toggletrue{patchhref}
%\iftoggle{patchhref}{
    \xpretocmd{\author}{\addhrauthor{#2}}{}{}
    \newif\iffirstauthor
    \firstauthortrue
    \newcommand{\addhrauthor}[1]{%
        \iffirstauthor%
            \newcommand{\hrauthor}{#1}\firstauthorfalse%
        \else%
            \xapptocmd{\hrauthor}{, #1}{}{}%
        \fi
    }
    \AtEndDocument{
        \hypersetup{pdfauthor={\hrauthor}}
    }
%}{
%}

\begin{document}
\title{The title}
\author{Firstname 1 Lastname 1}
\author{Second author}
\affil{First affiliation\\
   \href{mailto:firstname.fastname@affiliation}{firstname.fastname@affiliation}
}
\author{Name3}
\affil{Second affiliation}

\maketitle
Content.

\end{document}

I have added the iftoggle thing, it was not in the original answer. When not using iftoggle, it works. But, when using iftoggle (uncomment the three related lines to try it out), it fails when reaching the end of the document with Undefined control sequence. <argument> \hrauthor. As if the commands that define hrauthor had not been executed. But the part about \AtEndDocument does get executed. According to this comment, replacing iftoggle with legacy if construct works.

How can I make this patch work conditionally, using iftoggle, the preferred mechanism for conditional toggling?

  • 1
    You can't. The patching fails due to the #2 (and if you had added e.g. a \fail command you would have get a suitable error message \xpretocmd{\author}{\addhrauthor{#2}}{}{\fail}). – Ulrike Fischer Feb 18 '19 at 17:30

2 Answers2

2

This has nothing to do with \iftoggle per se but with category codes (catcodes). When TeX scans a token for the first time, its category code is "frozen", i.e. TeX remembers what it was when it was first read. In your case, the # is the culprit.

\iftoggle{patchhref} expands to something equivalent to \@firstoftwo or \@secondoftwo:

\newcommand\@firstoftwo[2]{#1}
\newcommand\@secondoftwo[2]{#2}

This scans the next two groups and removes the second one. All the catcodes in the first group are frozen in the process. # usually has category code 6 and some care is needed when patching commands with #. \xpretocmd tries to take care of this, but if the # has already been scanned, this fails.

You can work around this problem by defining

{\catcode`#=11\relax
    \gdef\fixauthor{\xpretocmd{\author}{\addhrauthor{#2}}{}{}}%
}

before your \iftoggle and replacing the \xpatchcmd line with \fixauthor.

schtandard
  • 14,892
1

You don't need to define the \addrauthor in the toggle part: you have to write the code anyway.

The problem with doing the patch in the argument to a command can be solved in various ways, the simplest one is to use standard conditionals.

Here I suggest an easier version of the \addhrauthor macro with expl3.

\documentclass{article}

\usepackage{xpatch,xparse}
\usepackage[pdfusetitle]{hyperref}
\usepackage{authblk}

\ExplSyntaxOn
\seq_new:N \g_oc_hrauthor_seq
\NewDocumentCommand{\addhrauthor}{m}
 {
  \seq_gput_right:Nn \g_oc_hrauthor_seq { #1 }
 }
\NewExpandableDocumentCommand{\hrauthor}{}
 {
  \seq_use:Nn \g_oc_hrauthor_seq {,~}
 }
\ExplSyntaxOff

\newif\ifpatchhref
%\patchhreftrue

\ifpatchhref
  \xpretocmd{\author}{\addhrauthor{#2}}{}{}
  \AtEndDocument{\hypersetup{pdfauthor={\hrauthor}}}
\fi


\begin{document}
\title{The title}
\author{Firstname 1 Lastname 1}
\author{Second author}
\affil{First affiliation\\
   \href{mailto:firstname.fastname@affiliation}{firstname.fastname@affiliation}
}
\author{Name3}
\affil{Second affiliation}

\maketitle
Content.

\end{document}
egreg
  • 1,121,712
  • Good point about the definitions out of the toggle. For the rest, using a standard conditional (ifpatchhref) is not great in my case: I use a global toggle (to separate the presentation and article cases) and use heavily iftoggle in various parts of my preamble. I’d like to patch the author mechanism iff that same toggle is in presentation mode. Now, either I have to completely get rid of iftoggle and replace by a standard conditional everywhere; or I have to use ifpatchhref (set equal to the toggle) especially for this, a strange exception that will reduce clarity of the code. – Olivier Cailloux Feb 27 '19 at 17:32
  • Hard to choose one answer for acceptance. I ended up accepting @schtandard’s answer because it lets me stick to the toggle mechanism I prefer. But I actually implemented parts of both answers. – Olivier Cailloux Mar 09 '19 at 20:52