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.

enter image description here


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.