Footnotes in boxes compatible with hyperref

expl3footnoteshyperref

I am trying to implement a support for \footnote in a horizontal list (boxed)
environment based on shortlst and ported (more less) to expl3. The
trick used in shortlst is taken from the tabularx package and goes
something like this:

% Code Part I
\ifx\TX@ftn\undefined
   \newtoks\TX@ftn
   \long\def\TX@ftntext#1{%
     \edef\@tempa{\the\TX@ftn\noexpand\footnotetext
                       [\the\csname c@\@mpfn\endcsname]}%
     \global\TX@ftn\expandafter{\@tempa{#1}}}%
   \long\def\TX@xftntext[#1]#2{%
     \global\TX@ftn\expandafter{\the\TX@ftn\footnotetext[#1]{#2}}}
\fi
% Code Part II
\global\TX@ftn\expandafter{\expandafter}\the\TX@ftn
% Code Part III
\let\@footnotetext\TX@ftntext\let\@xfootnotenext\TX@xftntext

My MWE is:

\documentclass{article}
\usepackage{hyperref,lua-visual-debug}
\ExplSyntaxOn
\IfPackageLoadedTF { hyperref }
  {
    \legacy_if:nT { Hy@hyperfootnotes } { \typeout{hyperfootnotes=true} }
  }{ }
% copy footnote
\cs_new_eq:NN \__my_footnotetext:nn \footnotetext
\cs_new_eq:NN \__my_footnotet:n \footnote
% \NewCommandCopy \__my_footnotet:n \footnote
% Redefine
\cs_new_protected:Nn \__my_renew_footnote:
  {
    \RenewDocumentCommand \footnote { o +m }
      {
        \IfNoValueTF {##1}
           {
             %\stepcounter{footnote}
             %\footnotemark[ \int_use:c { c@footnote } ]
             \tl_gset:Ne \g_tmpa_tl
               {
                 %\exp_not:N \__my_footnotetext:nn [ \int_use:c { c@footnote } ] {##2}
                 \exp_not:N \__my_footnotet:n {##2}
               }
           }
           {
             \footnotemark[##1]
             \tl_gset:Ne \g_tmpa_tl
               {
                 \exp_not:N \__my_footnotetext:nn [##1] {##2}
               }
           }
      }
  }
% Environment
\NewDocumentEnvironment{test}{}
  {
    \group_begin:
      \lrbox{ \l_tmpa_box }
      \__my_renew_footnote:
  }
  {
      \endlrbox
    \group_end:
    \box_set_wd:Nn \l_tmpa_box { 0.75\linewidth }
    \box_use:N \l_tmpa_box
    % footnote
    \tl_if_empty:NF \g_tmpa_tl
      {
        \g_tmpa_tl
        \tl_gclear:N \g_tmpa_tl
      }
  }
\ExplSyntaxOff
\begin{document}
Test here \footnote{footnote numered 1.}
\begin{test}
This is a test \footnote{footnote numbered 2.} more text
\end{test}
\begin{test}
This is a test \footnote[5]{footnote numered 5}.
\end{test}
This is a test \footnote{footnote numbered 3.}.
\end{document}

I can't get the marks in the right place when loading hyperref…any way to get around this?

First attempt

With this version I get the markings and numbering to be just what I want, but, now I get:

warning  (pdf backend): unreferenced destination with name 'Hfootnote.2'

So I get out of one…and stay in another 🙁

\documentclass{article}
\usepackage{hyperref}
\ExplSyntaxOn
\IfPackageLoadedTF { hyperref }
  {
    \legacy_if:nT { Hy@hyperfootnotes } { \typeout{hyperfootnotes=true} }
  }{ }
% copy footnote
\cs_new_eq:NN \__my_footnotetext:nn \footnotetext
% Redefine (based on https://latexref.xyz/Footnotes-in-a-table.html)
\cs_new_protected:Nn \__my_renew_footnote:
  {
    \RenewDocumentCommand \footnote { o +m }
      {
        \IfNoValueTF {##1}
           {
             \int_gset_eq:Nc \g_tmpa_int { c@footnote }
             \footnotemark
             \tl_gset:Ne \g_tmpa_tl
               {
                 \int_gincr:N \g_tmpa_int
                 \exp_not:N \__my_footnotetext:nn [ \g_tmpa_int ] {##2}
               }
           }
           {
             \footnotemark[##1]
             \tl_gset:Ne \g_tmpa_tl
               {
                 \exp_not:N \__my_footnotetext:nn [##1] {##2}
               }
           }
      }
  }
% Environment
\NewDocumentEnvironment{test}{}
  {
    \group_begin:
      \lrbox{ \l_tmpa_box }
      \__my_renew_footnote:
  }
  {
      \endlrbox
    \group_end:
    \box_set_wd:Nn \l_tmpa_box { 0.75\linewidth }
    \box_use:N \l_tmpa_box
    % footnote
    \tl_if_empty:NF \g_tmpa_tl
      {
        \g_tmpa_tl
        \tl_gclear:N \g_tmpa_tl
      }
  }
\ExplSyntaxOff
\begin{document}
Test here \footnote{footnote numered 1.}
\begin{test}
This is a test \footnote{footnote numbered 2.} more text
\end{test}
\begin{test}
This is a test \footnote[5]{footnote numered 5}.
\end{test}
This is a test \footnote{footnote numbered 3.}.
\end{document}

NOTE

I will leave this here as a note for future users.
My original idea was to be able to support \footnote inside boxes and have it be compatible with hyperref, preferably without using third party packages, but it's not that simple. The solution presented by @cfr fits perfect, just a couple of conditionals and we have hyperref support without major problems 😀

\documentclass{article}
\usepackage{hyperref}
\usepackage{footnotehyper}
\makesavenoteenv{test}
\ExplSyntaxOn
% vars
\box_new:N \l__pgl_footnote_box
\int_new:N \g__pgl_footnote_int
\seq_new:N \g__pgl_footnotes_seq
\seq_new:N \g__pgl_footnotenos_seq
\bool_new:N \l__pgl_hyper_foot_key_bool
% hyperref
\IfPackageLoadedTF { hyperref }
  {
    \legacy_if:nT { Hy@hyperfootnotes }
      {
        \typeout{hyperfootnotes=true}
        \bool_set_true:N \l__pgl_hyper_foot_key_bool
      }
  }{ }
\bool_if:NT \l__pgl_hyper_foot_key_bool
  {
    \IfPackageLoadedTF { footnotehyper }
      {
         \typeout{OK ~ hyperref ~ and ~ footnotehyper}
      }
      {
         \typeout{No ~ footnotehyper ~ load}
         \typeout{Load ~ and  ~ use  ~ \string\makesavenoteenv{test}}
         \bool_set_false:N \l__pgl_hyper_foot_key_bool
      }
  }

% copy footnote
\cs_new_protected:Nn \__my_footnotetext:nn
  {
    \footnotetext[#1]{#2}
  }
% Redefine (based on https://latexref.xyz/Footnotes-in-a-table.html)
\cs_new_protected:Nn \__my_renew_footnote:
  {
    \seq_gclear:N \g__pgl_footnotes_seq
    \seq_gclear:N \g__pgl_footnotenos_seq
    \RenewDocumentCommand \footnote { o +m }
      {
        \IfNoValueTF {##1}
          {
            \stepcounter{footnote}
            \int_gset_eq:Nc \g__pgl_footnote_int { c@footnote }
          }
          {
            \int_gset:Nn \g__pgl_footnote_int { ##1 }
          }
            \footnotemark[\g__pgl_footnote_int]
            \seq_gput_right:Nn \g__pgl_footnotes_seq  { ##2 }
            \seq_gput_right:NV \g__pgl_footnotenos_seq  \g__pgl_footnote_int
     }
  }
% Environment
\NewDocumentEnvironment{test}{}
  {
    \group_begin:
    \lrbox{ \l__pgl_footnote_box }
    \bool_if:NF \l__pgl_hyper_foot_key_bool
      {
        \__my_renew_footnote:
      }
  }
  {
    \endlrbox
    \group_end:
    \box_set_wd:Nn \l__pgl_footnote_box { 0.75\linewidth }
    \box_use:N \l__pgl_footnote_box
    % footnote
    \seq_if_empty:NF \g__pgl_footnotenos_seq
      {
        \seq_map_pairwise_function:NNN \g__pgl_footnotenos_seq \g__pgl_footnotes_seq \__my_footnotetext:nn
      }
  }
\ExplSyntaxOff
\begin{document}
Test here \footnote{footnote numbered 1.}
\begin{test}
  This is a test \footnote{footnote numbered 2.} more text\footnote{Another footnote.}
\end{test}
\begin{test}
  This is a test \footnote[5]{footnote numbered 5}.
\end{test}
This is a test \footnote{footnote numbered 4.}.
\end{document}

Out

Best Answer

Let me know if I should delete this.

This produces the marks and texts you want without hyperref warnings about either undefined or multiply defined destinations. It also permits multiple footnotes in a box and eliminates the use of standard temporary variables.

\documentclass{article}
% ateb: https://tex.stackexchange.com/a/700092/ i gwestiwn Pablo González L: https://tex.stackexchange.com/q/699441/
\usepackage{hyperref}
\ExplSyntaxOn
\IfPackageLoadedTF { hyperref }
{
  \legacy_if:nT { Hy@hyperfootnotes } { \typeout{hyperfootnotes=true} }
}{ }
\box_new:N \l__gpl_footnote_box
\int_new:N \g__pgl_footnote_int
\seq_new:N \g__pgl_footnotes_seq
\seq_new:N \g__pgl_footnotenos_seq
% copy footnote
\cs_new_protected:Nn \__my_footnotetext:nn {\footnotetext[#1]{#2}}
% Redefine (based on https://latexref.xyz/Footnotes-in-a-table.html)
\cs_new_protected:Nn \__my_renew_footnote:
{
  \seq_gclear:N \g__pgl_footnotes_seq
  \seq_gclear:N \g__pgl_footnotenos_seq
  \RenewDocumentCommand \footnote { o +m }
  {
    \IfNoValueTF {##1}
    {
      \stepcounter{footnote}
      \int_gset_eq:Nc \g__pgl_footnote_int { c@footnote }
    }
    {
      \int_gset:Nn \g__pgl_footnote_int { ##1 }
    }
    \footnotemark[\g__pgl_footnote_int]
    \seq_gput_right:Nn \g__pgl_footnotes_seq  { ##2 }
    \seq_gput_right:NV \g__pgl_footnotenos_seq  \g__pgl_footnote_int
  }
}
% Environment
\NewDocumentEnvironment{test}{}
{
  \group_begin:
  \lrbox{ \l__gpl_footnote_box }
  \__my_renew_footnote:
}
{
  \endlrbox
  \group_end:
  \box_set_wd:Nn \l__gpl_footnote_box { 0.75\linewidth }
  \box_use:N \l__gpl_footnote_box
  % footnote
  \seq_if_empty:NF \g__pgl_footnotenos_seq
  {
    \seq_map_pairwise_function:NNN \g__pgl_footnotenos_seq \g__pgl_footnotes_seq \__my_footnotetext:nn
  }
}
\ExplSyntaxOff
\begin{document}
Test here \footnote{footnote numbered 1.}
\begin{test}
  This is a test \footnote{footnote numbered 2.} more text\footnote{Another footnote.}
\end{test}
\begin{test}
  This is a test \footnote[5]{footnote numbered 5}.
\end{test}
This is a test \footnote{footnote numbered 4.}.
\end{document}

two boxes with three footnotes and non-boxes with two footnotes

five footnotes