diff --git a/Bugzilla/Bug.pm b/Bugzilla/Bug.pm
index 71b6bc7f45b9f56aa6000c014a32108d504c1763..e2222ccb717ef37cbb3d14082d884902fa559166 100755
--- a/Bugzilla/Bug.pm
+++ b/Bugzilla/Bug.pm
@@ -1221,7 +1221,7 @@ sub ValidateBugAlias {
     my $vars = {};
     $vars->{'alias'} = $alias;
     if ($id) {
-        $vars->{'bug_link'} = &::GetBugLink($id, $id);
+        $vars->{'bug_id'} = $id;
         ThrowUserError("alias_in_use", $vars);
     }
 
@@ -1294,19 +1294,12 @@ sub ValidateDependencies {
 
     my @deps   = @{$deptree{'dependson'}};
     my @blocks = @{$deptree{'blocked'}};
-    my @union = ();
-    my @isect = ();
     my %union = ();
     my %isect = ();
     foreach my $b (@deps, @blocks) { $union{$b}++ && $isect{$b}++ }
-    @union = keys %union;
-    @isect = keys %isect;
+    my @isect = keys %isect;
     if (scalar(@isect) > 0) {
-        my $both = "";
-        foreach my $i (@isect) {
-           $both .= &::GetBugLink($i, "#" . $i) . " ";
-        }
-        ThrowUserError("dependency_loop_multi", { both => $both });
+        ThrowUserError("dependency_loop_multi", {'deps' => \@isect});
     }
     return %deps;
 }
diff --git a/Bugzilla/Template.pm b/Bugzilla/Template.pm
index 08bcfacdfc31df7c4c2d3d693cee49ac0426a05f..6327a31a54275e980aa1a0a4f724067fd79a83d3 100644
--- a/Bugzilla/Template.pm
+++ b/Bugzilla/Template.pm
@@ -218,6 +218,202 @@ sub get_format {
     };
 }
 
+# This routine quoteUrls contains inspirations from the HTML::FromText CPAN
+# module by Gareth Rees <garethr@cre.canon.co.uk>.  It has been heavily hacked,
+# all that is really recognizable from the original is bits of the regular
+# expressions.
+# This has been rewritten to be faster, mainly by substituting 'as we go'.
+# If you want to modify this routine, read the comments carefully
+
+sub quoteUrls {
+    my ($text, $curr_bugid) = (@_);
+    return $text unless $text;
+
+    # We use /g for speed, but uris can have other things inside them
+    # (http://foo/bug#3 for example). Filtering that out filters valid
+    # bug refs out, so we have to do replacements.
+    # mailto can't contain space or #, so we don't have to bother for that
+    # Do this by escaping \0 to \1\0, and replacing matches with \0\0$count\0\0
+    # \0 is used because its unliklely to occur in the text, so the cost of
+    # doing this should be very small
+    # Also, \0 won't appear in the value_quote'd bug title, so we don't have
+    # to worry about bogus substitutions from there
+
+    # escape the 2nd escape char we're using
+    my $chr1 = chr(1);
+    $text =~ s/\0/$chr1\0/g;
+
+    # However, note that adding the title (for buglinks) can affect things
+    # In particular, attachment matches go before bug titles, so that titles
+    # with 'attachment 1' don't double match.
+    # Dupe checks go afterwards, because that uses ^ and \Z, which won't occur
+    # if it was subsituted as a bug title (since that always involve leading
+    # and trailing text)
+
+    # Because of entities, its easier (and quicker) to do this before escaping
+
+    my @things;
+    my $count = 0;
+    my $tmp;
+
+    # non-mailto protocols
+    my $protocol_re = qr/(afs|cid|ftp|gopher|http|https|irc|mid|news|nntp|prospero|telnet|view-source|wais)/i;
+
+    $text =~ s~\b(${protocol_re}:  # The protocol:
+                  [^\s<>\"]+       # Any non-whitespace
+                  [\w\/])          # so that we end in \w or /
+              ~($tmp = html_quote($1)) &&
+               ($things[$count++] = "<a href=\"$tmp\">$tmp</a>") &&
+               ("\0\0" . ($count-1) . "\0\0")
+              ~egox;
+
+    # We have to quote now, otherwise our html is itsself escaped
+    # THIS MEANS THAT A LITERAL ", <, >, ' MUST BE ESCAPED FOR A MATCH
+
+    $text = html_quote($text);
+
+    # Color quoted text
+    $text =~ s~^(&gt;.+)$~<span class="quote">$1</span >~mg;
+    $text =~ s~</span >\n<span class="quote">~\n~g;
+
+    # mailto:
+    # Use |<nothing> so that $1 is defined regardless
+    $text =~ s~\b(mailto:|)?([\w\.\-\+\=]+\@[\w\-]+(?:\.[\w\-]+)+)\b
+              ~<a href=\"mailto:$2\">$1$2</a>~igx;
+
+    # attachment links - handle both cases separately for simplicity
+    $text =~ s~((?:^Created\ an\ |\b)attachment\s*\(id=(\d+)\)(\s\[edit\])?)
+              ~($things[$count++] = get_attachment_link($2, $1)) &&
+               ("\0\0" . ($count-1) . "\0\0")
+              ~egmx;
+
+    $text =~ s~\b(attachment\s*\#?\s*(\d+))
+              ~($things[$count++] = get_attachment_link($2, $1)) &&
+               ("\0\0" . ($count-1) . "\0\0")
+              ~egmxi;
+
+    # Current bug ID this comment belongs to
+    my $current_bugurl = $curr_bugid ? "show_bug.cgi?id=$curr_bugid" : "";
+
+    # This handles bug a, comment b type stuff. Because we're using /g
+    # we have to do this in one pattern, and so this is semi-messy.
+    # Also, we can't use $bug_re?$comment_re? because that will match the
+    # empty string
+    my $bug_re = qr/bug\s*\#?\s*(\d+)/i;
+    my $comment_re = qr/comment\s*\#?\s*(\d+)/i;
+    $text =~ s~\b($bug_re(?:\s*,?\s*$comment_re)?|$comment_re)
+              ~ # We have several choices. $1 here is the link, and $2-4 are set
+                # depending on which part matched
+               (defined($2) ? get_bug_link($2,$1,$3) :
+                              "<a href=\"$current_bugurl#c$4\">$1</a>")
+              ~egox;
+
+    # Old duplicate markers
+    $text =~ s~(?<=^\*\*\*\ This\ bug\ has\ been\ marked\ as\ a\ duplicate\ of\ )
+               (\d+)
+               (?=\ \*\*\*\Z)
+              ~get_bug_link($1, $1)
+              ~egmx;
+
+    # Now remove the encoding hacks
+    $text =~ s/\0\0(\d+)\0\0/$things[$1]/eg;
+    $text =~ s/$chr1\0/\0/g;
+
+    return $text;
+}
+
+# Creates a link to an attachment, including its title.
+sub get_attachment_link {
+    my ($attachid, $link_text) = @_;
+    my $dbh = Bugzilla->dbh;
+
+    detaint_natural($attachid)
+      || die "get_attachment_link() called with non-integer attachment number";
+
+    my ($bugid, $isobsolete, $desc) =
+        $dbh->selectrow_array('SELECT bug_id, isobsolete, description
+                               FROM attachments WHERE attach_id = ?',
+                               undef, $attachid);
+
+    if ($bugid) {
+        my $title = "";
+        my $className = "";
+        if (Bugzilla->user->can_see_bug($bugid)) {
+            $title = $desc;
+        }
+        if ($isobsolete) {
+            $className = "bz_obsolete";
+        }
+        # Prevent code injection in the title.
+        $title = value_quote($title);
+
+        $link_text =~ s/ \[edit\]$//;
+        my $linkval = "attachment.cgi?id=$attachid&amp;action=";
+        # Whitespace matters here because these links are in <pre> tags.
+        return qq|<span class="$className">|
+               . qq|<a href="${linkval}view" title="$title">$link_text</a>|
+               . qq| <a href="${linkval}edit" title="$title">[edit]</a>|
+               . qq|</span>|;
+    }
+    else {
+        return qq{$link_text};
+    }
+}
+
+# Creates a link to a bug, including its title.
+# It takes either two or three parameters:
+#  - The bug number
+#  - The link text, to place between the <a>..</a>
+#  - An optional comment number, for linking to a particular
+#    comment in the bug
+
+sub get_bug_link {
+    my ($bug_num, $link_text, $comment_num) = @_;
+    my $dbh = Bugzilla->dbh;
+
+    if (!defined($bug_num) || ($bug_num eq "")) {
+        return "&lt;missing bug number&gt;";
+    }
+    my $quote_bug_num = html_quote($bug_num);
+    detaint_natural($bug_num) || return "&lt;invalid bug number: $quote_bug_num&gt;";
+
+    my ($bug_state, $bug_res, $bug_desc) =
+        $dbh->selectrow_array('SELECT bugs.bug_status, resolution, short_desc
+                               FROM bugs WHERE bugs.bug_id = ?',
+                               undef, $bug_num);
+
+    if ($bug_state) {
+        # Initialize these variables to be "" so that we don't get warnings
+        # if we don't change them below (which is highly likely).
+        my ($pre, $title, $post) = ("", "", "");
+
+        $title = $bug_state;
+        if ($bug_state eq 'UNCONFIRMED') {
+            $pre = "<i>";
+            $post = "</i>";
+        }
+        elsif (! &::IsOpenedState($bug_state)) {
+            $pre = '<span class="bz_closed">';
+            $title .= " $bug_res";
+            $post = '</span>';
+        }
+        if (Bugzilla->user->can_see_bug($bug_num)) {
+            $title .= " - $bug_desc";
+        }
+        # Prevent code injection in the title.
+        $title = value_quote($title);
+
+        my $linkval = "show_bug.cgi?id=$bug_num";
+        if (defined $comment_num) {
+            $linkval .= "#c$comment_num";
+        }
+        return qq{$pre<a href="$linkval" title="$title">$link_text</a>$post};
+    }
+    else {
+        return qq{$link_text};
+    }
+}
+
 ###############################################################################
 # Templatization Code
 
@@ -406,7 +602,7 @@ sub create {
                                my ($context, $bug) = @_;
                                return sub {
                                    my $text = shift;
-                                   return &::quoteUrls($text, $bug);
+                                   return quoteUrls($text, $bug);
                                };
                            },
                            1
@@ -416,7 +612,7 @@ sub create {
                               my ($context, $bug) = @_;
                               return sub {
                                   my $text = shift;
-                                  return &::GetBugLink($bug, $text);
+                                  return get_bug_link($bug, $text);
                               };
                           },
                           1
diff --git a/attachment.cgi b/attachment.cgi
index 973b8b528de66ef516403f37f50d3cac4ea6d1ad..1fd3c199432ce2e6eaa498567657968aec329879 100755
--- a/attachment.cgi
+++ b/attachment.cgi
@@ -837,7 +837,6 @@ sub viewall
   $vars->{'attachments'} = \@attachments;
   $vars->{'bugassignee_id'} = $assignee_id;
   $vars->{'bugsummary'} = $bugsummary;
-  $vars->{'GetBugLink'} = \&GetBugLink;
 
   print $cgi->header();
 
@@ -884,7 +883,6 @@ sub enter
   $vars->{'attachments'} = \@attachments;
   $vars->{'bugassignee_id'} = $assignee_id;
   $vars->{'bugsummary'} = $bugsummary;
-  $vars->{'GetBugLink'} = \&GetBugLink;
 
   SendSQL("SELECT product_id, component_id FROM bugs
            WHERE bug_id = $bugid");
@@ -1145,7 +1143,6 @@ sub edit {
   $vars->{'bugsummary'} = $bugsummary; 
   $vars->{'isviewable'} = $isviewable; 
   $vars->{'attachments'} = $bugattachments; 
-  $vars->{'GetBugLink'} = \&GetBugLink;
 
   # Determine if PatchReader is installed
   eval {
diff --git a/globals.pl b/globals.pl
index 9979008d1d622f502eeb85d977e5132ad8d59bb4..4f7b6e03a2bc24e2830db41181054a7411d9a798 100644
--- a/globals.pl
+++ b/globals.pl
@@ -475,243 +475,6 @@ sub get_component_name {
     return $comp;
 }
 
-# This routine quoteUrls contains inspirations from the HTML::FromText CPAN
-# module by Gareth Rees <garethr@cre.canon.co.uk>.  It has been heavily hacked,
-# all that is really recognizable from the original is bits of the regular
-# expressions.
-# This has been rewritten to be faster, mainly by substituting 'as we go'.
-# If you want to modify this routine, read the comments carefully
-
-sub quoteUrls {
-    my ($text, $curr_bugid) = (@_);
-    return $text unless $text;
-
-    # We use /g for speed, but uris can have other things inside them
-    # (http://foo/bug#3 for example). Filtering that out filters valid
-    # bug refs out, so we have to do replacements.
-    # mailto can't contain space or #, so we don't have to bother for that
-    # Do this by escaping \0 to \1\0, and replacing matches with \0\0$count\0\0
-    # \0 is used because its unliklely to occur in the text, so the cost of
-    # doing this should be very small
-    # Also, \0 won't appear in the value_quote'd bug title, so we don't have
-    # to worry about bogus substitutions from there
-
-    # escape the 2nd escape char we're using
-    my $chr1 = chr(1);
-    $text =~ s/\0/$chr1\0/g;
-
-    # However, note that adding the title (for buglinks) can affect things
-    # In particular, attachment matches go before bug titles, so that titles
-    # with 'attachment 1' don't double match.
-    # Dupe checks go afterwards, because that uses ^ and \Z, which won't occur
-    # if it was subsituted as a bug title (since that always involve leading
-    # and trailing text)
-
-    # Because of entities, its easier (and quicker) to do this before escaping
-
-    my @things;
-    my $count = 0;
-    my $tmp;
-
-    # non-mailto protocols
-    my $protocol_re = qr/(afs|cid|ftp|gopher|http|https|irc|mid|news|nntp|prospero|telnet|view-source|wais)/i;
-
-    $text =~ s~\b(${protocol_re}:  # The protocol:
-                  [^\s<>\"]+       # Any non-whitespace
-                  [\w\/])          # so that we end in \w or /
-              ~($tmp = html_quote($1)) &&
-               ($things[$count++] = "<a href=\"$tmp\">$tmp</a>") &&
-               ("\0\0" . ($count-1) . "\0\0")
-              ~egox;
-
-    # We have to quote now, otherwise our html is itsself escaped
-    # THIS MEANS THAT A LITERAL ", <, >, ' MUST BE ESCAPED FOR A MATCH
-
-    $text = html_quote($text);
-
-    # Color quoted text
-    $text =~ s~^(&gt;.+)$~<span class="quote">$1</span >~mg;
-    $text =~ s~</span >\n<span class="quote">~\n~g;
-    
-    # mailto:
-    # Use |<nothing> so that $1 is defined regardless
-    $text =~ s~\b(mailto:|)?([\w\.\-\+\=]+\@[\w\-]+(?:\.[\w\-]+)+)\b
-              ~<a href=\"mailto:$2\">$1$2</a>~igx;
-
-    # attachment links - handle both cases separately for simplicity
-    $text =~ s~((?:^Created\ an\ |\b)attachment\s*\(id=(\d+)\)(\s\[edit\])?)
-              ~($things[$count++] = GetAttachmentLink($2, $1)) &&
-               ("\0\0" . ($count-1) . "\0\0")
-              ~egmx;
-
-    $text =~ s~\b(attachment\s*\#?\s*(\d+))
-              ~($things[$count++] = GetAttachmentLink($2, $1)) &&
-               ("\0\0" . ($count-1) . "\0\0")
-              ~egmxi;
-
-    # Current bug ID this comment belongs to
-    my $current_bugurl = $curr_bugid ? "show_bug.cgi?id=$curr_bugid" : "";
-    
-    # This handles bug a, comment b type stuff. Because we're using /g
-    # we have to do this in one pattern, and so this is semi-messy.
-    # Also, we can't use $bug_re?$comment_re? because that will match the
-    # empty string
-    my $bug_re = qr/bug\s*\#?\s*(\d+)/i;
-    my $comment_re = qr/comment\s*\#?\s*(\d+)/i;
-    $text =~ s~\b($bug_re(?:\s*,?\s*$comment_re)?|$comment_re)
-              ~ # We have several choices. $1 here is the link, and $2-4 are set
-                # depending on which part matched
-               (defined($2) ? GetBugLink($2,$1,$3) :
-                              "<a href=\"$current_bugurl#c$4\">$1</a>")
-              ~egox;
-
-    # Old duplicate markers
-    $text =~ s~(?<=^\*\*\*\ This\ bug\ has\ been\ marked\ as\ a\ duplicate\ of\ )
-               (\d+)
-               (?=\ \*\*\*\Z)
-              ~GetBugLink($1, $1)
-              ~egmx;
-
-    # Now remove the encoding hacks
-    $text =~ s/\0\0(\d+)\0\0/$things[$1]/eg;
-    $text =~ s/$chr1\0/\0/g;
-
-    return $text;
-}
-
-# GetAttachmentLink creates a link to an attachment,
-# including its title.
-
-sub GetAttachmentLink {
-    my ($attachid, $link_text) = @_;
-    detaint_natural($attachid) ||
-        die "GetAttachmentLink() called with non-integer attachment number";
-
-    # If we've run GetAttachmentLink() for this attachment before,
-    # %::attachlink will contain an anonymous array ref of relevant
-    # values.  If not, we need to get the information from the database.
-    if (! defined $::attachlink{$attachid}) {
-        # Make sure any unfetched data from a currently running query
-        # is saved off rather than overwritten
-        PushGlobalSQLState();
-
-        SendSQL("SELECT bug_id, isobsolete, description 
-                 FROM attachments WHERE attach_id = $attachid");
-
-        if (MoreSQLData()) {
-            my ($bugid, $isobsolete, $desc) = FetchSQLData();
-            my $title = "";
-            my $className = "";
-            if (Bugzilla->user->can_see_bug($bugid)) {
-                $title = $desc;
-            }
-            if ($isobsolete) {
-                $className = "bz_obsolete";
-            }
-            $::attachlink{$attachid} = [value_quote($title), $className];
-        }
-        else {
-            # Even if there's nothing in the database, we want to save a blank
-            # anonymous array in the %::attachlink hash so the query doesn't get
-            # run again next time we're called for this attachment number.
-            $::attachlink{$attachid} = [];
-        }
-        # All done with this sidetrip
-        PopGlobalSQLState();
-    }
-
-    # Now that we know we've got all the information we're gonna get, let's
-    # return the link (which is the whole reason we were called :)
-    my ($title, $className) = @{$::attachlink{$attachid}};
-    # $title will be undefined if the attachment didn't exist in the database.
-    if (defined $title) {
-        $link_text =~ s/ \[edit\]$//;
-        my $linkval = "attachment.cgi?id=$attachid&amp;action=";
-        # Whitespace matters here because these links are in <pre> tags.
-        return qq|<span class="$className">|
-               . qq|<a href="${linkval}view" title="$title">$link_text</a>|
-               . qq| <a href="${linkval}edit" title="$title">[edit]</a>|
-               . qq|</span>|;
-    }
-    else {
-        return qq{$link_text};
-    }
-}
-
-# GetBugLink creates a link to a bug, including its title.
-# It takes either two or three parameters:
-#  - The bug number
-#  - The link text, to place between the <a>..</a>
-#  - An optional comment number, for linking to a particular
-#    comment in the bug
-
-sub GetBugLink {
-    my ($bug_num, $link_text, $comment_num) = @_;
-    if (! defined $bug_num || $bug_num eq "") {
-        return "&lt;missing bug number&gt;";
-    }
-    my $quote_bug_num = html_quote($bug_num);
-    detaint_natural($bug_num) || return "&lt;invalid bug number: $quote_bug_num&gt;";
-
-    # If we've run GetBugLink() for this bug number before, %::buglink
-    # will contain an anonymous array ref of relevent values, if not
-    # we need to get the information from the database.
-    if (! defined $::buglink{$bug_num}) {
-        # Make sure any unfetched data from a currently running query
-        # is saved off rather than overwritten
-        PushGlobalSQLState();
-
-        SendSQL("SELECT bugs.bug_status, resolution, short_desc " .
-                "FROM bugs WHERE bugs.bug_id = $bug_num");
-
-        # If the bug exists, save its data off for use later in the sub
-        if (MoreSQLData()) {
-            my ($bug_state, $bug_res, $bug_desc) = FetchSQLData();
-            # Initialize these variables to be "" so that we don't get warnings
-            # if we don't change them below (which is highly likely).
-            my ($pre, $title, $post) = ("", "", "");
-
-            $title = $bug_state;
-            if ($bug_state eq 'UNCONFIRMED') {
-                $pre = "<i>";
-                $post = "</i>";
-            }
-            elsif (! IsOpenedState($bug_state)) {
-                $pre = '<span class="bz_closed">';
-                $title .= " $bug_res";
-                $post = '</span>';
-            }
-            if (Bugzilla->user->can_see_bug($bug_num)) {
-                $title .= " - $bug_desc";
-            }
-            $::buglink{$bug_num} = [$pre, value_quote($title), $post];
-        }
-        else {
-            # Even if there's nothing in the database, we want to save a blank
-            # anonymous array in the %::buglink hash so the query doesn't get
-            # run again next time we're called for this bug number.
-            $::buglink{$bug_num} = [];
-        }
-        # All done with this sidetrip
-        PopGlobalSQLState();
-    }
-
-    # Now that we know we've got all the information we're gonna get, let's
-    # return the link (which is the whole reason we were called :)
-    my ($pre, $title, $post) = @{$::buglink{$bug_num}};
-    # $title will be undefined if the bug didn't exist in the database.
-    if (defined $title) {
-        my $linkval = "show_bug.cgi?id=$bug_num";
-        if (defined $comment_num) {
-            $linkval .= "#c$comment_num";
-        }
-        return qq{$pre<a href="$linkval" title="$title">$link_text</a>$post};
-    }
-    else {
-        return qq{$link_text};
-    }
-}
-
 # Returns a list of all the legal values for a field that has a
 # list of legal values, like rep_platform or resolution.
 sub get_legal_field_values {
diff --git a/summarize_time.cgi b/summarize_time.cgi
index 0827077e8d2c0b9b25c6e9f88bc4d9a44cb66441..df6ae913c9692b402b707daaff8a79fa6652db9a 100755
--- a/summarize_time.cgi
+++ b/summarize_time.cgi
@@ -523,7 +523,6 @@ $vars->{'do_report'} = $do_report;
 $vars->{'do_depends'} = $do_depends;
 $vars->{'check_time'} = \&check_time;
 $vars->{'sort_bug_keys'} = \&sort_bug_keys;
-$vars->{'GetBugLink'} = \&GetBugLink;
 
 my $format = $template->get_format("bug/summarize-time", undef, $ctype);
 
diff --git a/t/008filter.t b/t/008filter.t
index 8c4e3e24adb11ed2bd56f49ec80cbd0c58b4606c..f57a8adedca0ea525f0082cfc2516acfc34e70b1 100644
--- a/t/008filter.t
+++ b/t/008filter.t
@@ -205,7 +205,7 @@ sub directive_ok {
     return 1 if $directive =~ /^Hook.process\(/;
 
     # Other functions guaranteed to return OK output
-    return 1 if $directive =~ /^(time2str|GetBugLink|url)\(/;
+    return 1 if $directive =~ /^(time2str|url)\(/;
 
     # Safe Template Toolkit virtual methods
     return 1 if $directive =~ /\.(length$|size$|push\()/;
diff --git a/template/en/default/attachment/create.html.tmpl b/template/en/default/attachment/create.html.tmpl
index 4de1e5a08d010d3933291402f395575d70abb6fb..410f274f20a701c311f1dde6a66581e2b69a919e 100644
--- a/template/en/default/attachment/create.html.tmpl
+++ b/template/en/default/attachment/create.html.tmpl
@@ -26,7 +26,7 @@
 [%# Define strings that will serve as the title and header of this page %]
 [% title = BLOCK %]Create New Attachment for [% terms.Bug %] #[% bugid %][% END %]
 [% h1 = BLOCK %]Create New Attachment for
-  [%+ GetBugLink(bugid, "$terms.Bug $bugid") %][% END %]
+  [%+ "$terms.Bug $bugid" FILTER bug_link(bugid) FILTER none %][% END %]
 [% h2 = BLOCK %][% bugsummary FILTER html %][% END %]
 
 [% PROCESS global/header.html.tmpl
diff --git a/template/en/default/attachment/edit.html.tmpl b/template/en/default/attachment/edit.html.tmpl
index 53eb44d9e07a96bd77a9ab3a7ceb32a3531b2932..b2b5b13e5a364720ee34965114f89b63da599796 100644
--- a/template/en/default/attachment/edit.html.tmpl
+++ b/template/en/default/attachment/edit.html.tmpl
@@ -28,7 +28,7 @@
 [% END %]
 [% h1 = BLOCK %]
   Attachment [% attachment.id %] Details for
-  [%+ GetBugLink(attachment.bug_id, "$terms.Bug ${attachment.bug_id}") %]
+  [%+ "$terms.Bug ${attachment.bug_id}" FILTER bug_link(attachment.bug_id) FILTER none %]
 [% END %]
 [% h2 = BLOCK %][% bugsummary FILTER html %][% END %]
 
diff --git a/template/en/default/attachment/show-multiple.html.tmpl b/template/en/default/attachment/show-multiple.html.tmpl
index 06cea8683d6fb4e5459aa06b04120e92d0db0994..03ad0ea47086b246882a0b143497e0c181e9d545 100644
--- a/template/en/default/attachment/show-multiple.html.tmpl
+++ b/template/en/default/attachment/show-multiple.html.tmpl
@@ -22,7 +22,7 @@
 [% PROCESS global/variables.none.tmpl %]
 [% filtered_summary = bugsummary FILTER html %]
 [% h1 = BLOCK %]View All Attachments for
-  [%+ GetBugLink(bugid, "$terms.Bug $bugid") %][% END %]
+  [%+ "$terms.Bug $bugid" FILTER bug_link(bugid) FILTER none %][% END %]
 [% PROCESS global/header.html.tmpl
   title = "View All Attachments for $terms.Bug #$bugid"
   h1 = h1
diff --git a/template/en/default/bug/summarize-time.html.tmpl b/template/en/default/bug/summarize-time.html.tmpl
index 5761b24cfe6bbe911e18b8de20e7e7e66d0041c9..35808f9514a2d6c3ee9b8a7bd44ab6694afaf18c 100644
--- a/template/en/default/bug/summarize-time.html.tmpl
+++ b/template/en/default/bug/summarize-time.html.tmpl
@@ -21,7 +21,7 @@
 [% title = "Time Summary " %]
 [% IF do_depends %]
     [% title = title _ "for " %]
-    [% h1 = title _  GetBugLink(ids.0, "$terms.Bug $ids.0") %]
+    [% h1 = title _ "$terms.Bug $ids.0" FILTER bug_link(ids.0) FILTER none %]
     [% title = title _ "$terms.Bug $ids.0: " %]
     [% h1 = (h1 _ " (and $terms.bugs blocking it)") IF do_depends %]
 [% ELSE %]
diff --git a/template/en/default/filterexceptions.pl b/template/en/default/filterexceptions.pl
index dbc618ee638e9a949a5c94232e923a6c246177f1..40a96e70b67e6c106c286d23d67c391f29721b78 100644
--- a/template/en/default/filterexceptions.pl
+++ b/template/en/default/filterexceptions.pl
@@ -29,7 +29,7 @@
 # Simple literals                 - [% " selected" ...
 # Values always used for numbers  - [% (i|j|k|n|count) %]
 # Params                          - [% Param(...
-# Safe functions                  - [% (time2str|GetBugLink)...
+# Safe functions                  - [% (time2str)...
 # Safe vmethods                   - [% foo.size %] [% foo.length %]
 #                                   [% foo.push() %]
 # TT loop variables               - [% loop.count %]
diff --git a/template/en/default/global/user-error.html.tmpl b/template/en/default/global/user-error.html.tmpl
index 3863cb150245eb573fb224fa918eea6eb0f7c602..390c6b12c39e7e74425db668b6d1e216c111920e 100644
--- a/template/en/default/global/user-error.html.tmpl
+++ b/template/en/default/global/user-error.html.tmpl
@@ -82,8 +82,9 @@
 
   [% ELSIF error == "alias_in_use" %]
     [% title = "Alias In Use" %]
-    [% terms.Bug %] [%+ bug_link FILTER none %] has already taken the alias 
-    <em>[% alias FILTER html %]</em>.  Please choose another one.
+    [% terms.Bug %] [%+ bug_id FILTER bug_link(bug_id) FILTER none %]
+    has already taken the alias <em>[% alias FILTER html %]</em>.
+    Please choose another one.
 
   [% ELSIF error == "alias_not_defined" %]
     [% title = "Alias Is Not Defined" %]
@@ -303,8 +304,11 @@
     [% title = "Dependency Loop Detected" %]
     The following [% terms.bug %](s) would appear on both the "depends on"
     and "blocks" parts of the dependency tree if these changes
-    are committed: [% both FILTER none %]. This would create a circular
-    dependency, which is not allowed.
+    are committed:
+    [% FOREACH dep = deps %]
+      [%+ dep FILTER bug_link(dep) FILTER none %]
+    [% END %].
+    This would create a circular dependency, which is not allowed.
 
   [% ELSIF error == "dependency_loop_single" %]
     [% title = "Dependency Loop Detected" %]
diff --git a/template/en/default/global/variables.none.tmpl b/template/en/default/global/variables.none.tmpl
index 76ec1bec6ded7185586b64e7d7d70bd2f634975f..d19d6407f3a837f7638b1c0d700074ad80177534 100644
--- a/template/en/default/global/variables.none.tmpl
+++ b/template/en/default/global/variables.none.tmpl
@@ -33,7 +33,7 @@
   # This means if you change "bug" to "problem", then if you have
   # "problem 3" in a comment, it won't become a clickable URL.
   # To have that feature, you must edit the quoteUrls function in
-  # globals.pl (in the base Bugzilla directory).
+  # Bugzilla/Template.pm.
   # Change the line:
   # my $bug_re = qr/bug\s*\#?\s*(\d+)/i;
   # to something like:
diff --git a/template/en/extension/filterexceptions.pl b/template/en/extension/filterexceptions.pl
index b8da2930f7dc408bb31582003071f993c7299b8c..29e2a1e94a8f163f13186884ab87f292a2373fc2 100644
--- a/template/en/extension/filterexceptions.pl
+++ b/template/en/extension/filterexceptions.pl
@@ -30,7 +30,7 @@
 # Simple literals                 - [% " selected" ...
 # Values always used for numbers  - [% (i|j|k|n|count) %]
 # Params                          - [% Param(...
-# Safe functions                  - [% (time2str|GetBugLink)...
+# Safe functions                  - [% (time2str)...
 # Safe vmethods                   - [% foo.size %] [% foo.length %]
 #                                   [% foo.push() %]
 # TT loop variables               - [% loop.count %]