Biblatex, authoryear-comp, and hyperlinks
Both \cite
and \textcite
use \setunit
inside the <loopcode>
argument of \DeclareCiteCommand
. Links will include punctuation if you simply wrap <loopcode>
(or the cite
and textcite
bibliography macros) in \bibhyperref
. Moreover printing of \setunit
is deferred to the next \print*
or \bibstring
command. So it is difficult to ensure that this approach will create links that point to the correct item in the bibliography.
The following patches to cite
will make a single link for labelname
/label
and labelyear
+extrayear
where appropriate. The patches to textcite
will include the parentheses around labelyear
+extrayear
in the absence of prenote
, postnote
and citation lists. Otherwise separate links are applied, similar to the citation links obtained with natbib.
\documentclass{report}
\usepackage[style=authoryear-comp]{biblatex}
\usepackage{hyperref}
\usepackage{xpatch}
% Just for demo
\ExecuteBibliographyOptions{maxcitenames=1}
% Combine label and labelyear links
\xpatchbibmacro{cite}
{\usebibmacro{cite:label}%
\setunit{\addspace}%
\usebibmacro{cite:labelyear+extrayear}}
{\printtext[bibhyperref]{%
\DeclareFieldAlias{bibhyperref}{default}%
\usebibmacro{cite:label}%
\setunit{\addspace}%
\usebibmacro{cite:labelyear+extrayear}}}{}{}
% Include labelname in labelyear link
\xpatchbibmacro{cite}
{\printnames{labelname}%
\setunit{\nameyeardelim}%
\usebibmacro{cite:labelyear+extrayear}}
{\printtext[bibhyperref]{%
\DeclareFieldAlias{bibhyperref}{default}%
\printnames{labelname}%
\setunit{\nameyeardelim}%
\usebibmacro{cite:labelyear+extrayear}}}{}{}
% Access hyperref's citation link start/end commands
\makeatletter
\protected\def\blx@imc@biblinkstart{%
\@ifnextchar[%]
{\blx@biblinkstart}
{\blx@biblinkstart[\abx@field@entrykey]}}
\def\blx@biblinkstart[#1]{%
\blx@sfsave\hyper@natlinkstart{\the\c@refsection @#1}\blx@sfrest}
\protected\def\blx@imc@biblinkend{%
\blx@sfsave\hyper@natlinkend\blx@sfrest}
\blx@regimcs{\biblinkstart \biblinkend}
\makeatother
\newbool{cbx:link}
% Include parentheses around labelyear in \textcite only in
% single citations without pre- and postnotes
\def\iflinkparens{%
\ifboolexpr{ test {\ifnumequal{\value{multicitetotal}}{0}} and
test {\ifnumequal{\value{citetotal}}{1}} and
test {\iffieldundef{prenote}} and
test {\iffieldundef{postnote}} }}
\xpatchbibmacro{textcite}
{\printnames{labelname}}
{\iflinkparens
{\DeclareFieldAlias{bibhyperref}{default}%
\global\booltrue{cbx:link}\biblinkstart%
\printnames{labelname}}
{\printtext[bibhyperref]{\printnames{labelname}}}}{}{}
\xpatchbibmacro{textcite}
{\usebibmacro{cite:label}}
{\iflinkparens
{\DeclareFieldAlias{bibhyperref}{default}%
\global\booltrue{cbx:link}\biblinkstart%
\usebibmacro{cite:label}}
{\usebibmacro{cite:label}}}{}{}
\xpretobibmacro{textcite:postnote}
{\ifbool{cbx:link}% patch 2.7+
{\ifbool{cbx:parens}
{\bibcloseparen\global\boolfalse{cbx:parens}}
{}%
\biblinkend\global\boolfalse{cbx:link}}
{}}
{}
{\xpatchbibmacro{textcite}% patch earlier releases
{\setunit{%
\ifbool{cbx:parens}
{\bibcloseparen\global\boolfalse{cbx:parens}}
{}%
\multicitedelim}}
{\ifbool{cbx:link}
{\ifbool{cbx:parens}
{\bibcloseparen\global\boolfalse{cbx:parens}}
{}%
\biblinkend\global\boolfalse{cbx:link}}
{}%
\setunit{%
\ifbool{cbx:parens}
{\bibcloseparen\global\boolfalse{cbx:parens}}
{}%
\multicitedelim}}
{}{}}
\renewcommand{\baselinestretch}{1.2}
\setlength{\parskip}{\smallskipamount}
\setlength{\parindent}{0pt}
\addbibresource{biblatex-examples.bib}
\begin{document}
\null\vfill
\textbf{Single citations}
Filler text \parencite{aristotle:poetics}.
Filler text \parencite{kant:ku}. Filler text \parencite{cms}. \\
Filler text \parencite[See][23]{aristotle:poetics}.
Filler text \parencite[1--10]{kant:ku}. \\
\textcite{knuth:ct} and \textcite{knuth:ct:a}.
\textcite{knuth:ct:b} and \textcite{knuth:ct:c}. \\
\textcite{aristotle:poetics} and \textcite{kant:ku} and \textcite{cms}. \\
\textcite[e.g.][]{aristotle:poetics} and \textcite[10]{kant:ku}. \\
Filler text.\footcite[23]{aristotle:poetics} Filler text.\footcite[1--10]{aristotle:rhetoric}
Filler text.\footnote{\smartcite[10--15]{companion}}
\textbf{Unqualified citation lists}
\textcite{knuth:ct,knuth:ct:a,knuth:ct:b,knuth:ct:c} showed that... \\
\textcite[e.g.][10--15]{aristotle:poetics,aristotle:rhetoric,cms} showed that...\\
Filler text \parencite[See][for example]{aristotle:poetics,aristotle:rhetoric,cms}. \\
Filler text \parencite[etc.]{knuth:ct,knuth:ct:a,knuth:ct:b,knuth:ct:c}.
\textbf{Qualified citation lists}
\textcites{aristotle:poetics}{aristotle:rhetoric} showed that...
\textcites(See)(){aristotle:poetics}[cf.][]{aristotle:rhetoric}. \\
\textcites(See)()[e.g.][15]{aristotle:poetics}[cf.][10]{aristotle:rhetoric} \\
\parencites(See)()[10--15]{aristotle:poetics}[cf.][10]{aristotle:rhetoric} \\
\parencites{knuth:ct,knuth:ct:a}[10--11]{knuth:ct:b,knuth:ct:c}
\textbf{Mix of qualified and unqualified citation lists}
\textcites(See)()[e.g.][]{aristotle:poetics}[10]{bertram,companion} \\
\textcites[e.g.][]{aristotle:poetics,aristotle:rhetoric}[10]{companion} \\
\textcites[10]{aristotle:poetics}{aristotle:rhetoric}[cf.][]{bertram} \\
\textcites[15]{aristotle:poetics}[cf.][10]{bertram,companion}
\printbibliography
\chapter*{Appendix}
\end{document}
Here is the output you should get with biblatex 2.6 or earlier. The patches also work with later releases, where \textcite
and friends incorporate the and
string into the final citation delimiter.
I would prefer another solution:
\makeatletter
%Works without the last bracket ;-)
\let\abx@macro@citeOrig\abx@macro@cite
\renewbibmacro{cite}{%
\bibhyperref{%
\let\bibhyperref\relax\relax%
\abx@macro@citeOrig%
}%
}
\let\abx@macro@textciteOrig\abx@macro@textcite
\renewbibmacro{textcite}{%
\bibhyperref{%
\let\bibhyperref\relax\relax%
\abx@macro@textciteOrig%
}%
}%
\makeatother
You can use it for every cite-command.
\documentclass{article}
\usepackage[utf8]{inputenc}
\usepackage[style=authoryear-comp,backend=biber,hyperref]{biblatex}
\usepackage[colorlinks]{hyperref}
\bibliography{biblatex-examples}
\makeatletter
%Works without the last bracket ;-)
\let\abx@macro@citeOrig\abx@macro@cite
\renewbibmacro{cite}{%
\bibhyperref{%
\let\bibhyperref\relax\relax%
\abx@macro@citeOrig%
}%
}
\let\abx@macro@textciteOrig\abx@macro@textcite
\renewbibmacro{textcite}{%
\bibhyperref{%
\let\bibhyperref\relax\relax%
\abx@macro@textciteOrig%
}%
}%
\makeatother
\begin{document}
A reference to \parencite{kastenholz,sigfridsson} and~\cite{sigfridsson}.
\printbibliography
\end{document}
EDIT:
I change the code of the example above.
\makeatletter
\patchcmd{\blx@citeprint}%
{\blx@loopcode}%
{\blx@imc@bibhyperlink{#1}{\blx@loopcode}}%
{}{}
\makeatother
The problem: The last bracket isn't part of the link.