c0e8fa6df3a0bd406c4188d49ee00f20aef203e5
max
  Mon Sep 7 12:07:18 2026 -0700
Substitute trackDb variables in hub track description pages

A hub's description page comes straight off the hub's web server and has
never been through variable substitution, so a $db or $parentTrack in it
reached the reader as literal text. Native trackDb pages are fine, since
hgTrackDb substitutes them when it loads trackDb, but there was no
equivalent step for a hub.

hgc's getTrackHtml and hgTrackUi's trackUi both call hVarSubstTrackDbHtml
on a hub track's html.  Only a short list of variables is recognized there and nothing is an
error, because a hub page written before this existed can easily contain
a dollar sign inside a shell example, and silently rewriting that would
be worse than not substituting at all.

Adds $parentTrack, the name of the container a track sits in, which is
what a subtrack description page needs to link back to its superTrack or
composite. Views are skipped, since a view has no page of its own, and
the hub_<id>_ prefix is kept so the name works as hgTrackUi's g=
parameter. Documents $track, $parentTrack and $hgsid in trackDb/README.

refs #37599

diff --git src/hg/inc/hVarSubst.h src/hg/inc/hVarSubst.h
index 6241a7cd930..d657292f331 100644
--- src/hg/inc/hVarSubst.h
+++ src/hg/inc/hVarSubst.h
@@ -18,16 +18,25 @@
  * debugging. tdb maybe NULL to only do substitutions based on database
  * and organism. See trackDb/README for more information.*/
 
 void hVarSubstInVar(char *desc, struct trackDb *tdb, char *database, char **varPtr);
 /* hVarSubst on a dynamically allocated string, replacing string in substitutions
  * occur, freeing the old memory if necessary.  See hVarSubst for details.
  */
 
 void hVarSubstWithCart(char *desc, struct cart *cart, struct trackDb *tdb, char *database,
                        char **varPtr);
 /* Like hVarSubstInVar, but if cart is non-NULL, $hgsid will be substituted. */
 
 void hVarSubstTrackDb(struct trackDb *tdb, char *database);
 /* Substitute variables in trackDb shortLabel, longLabel, and html fields. */
 
+void hVarSubstTrackDbHtml(struct cart *cart, struct trackDb *tdb, char *database);
+/* Substitute variables in the description page of a hub track.  Native trackDb needs no
+ * such call: hgTrackDb already substituted the html when it loaded trackDb.  A hub's html
+ * comes straight off the hub's web server and has never been through substitution, so it
+ * is done here, at render time, where $db, $hgsid and $parentTrack resolve to the hub_<id>_
+ * names the CGIs actually use.  Only a short list of variables is recognized and nothing
+ * is an error, so a dollar sign in a description page that was not written with this in
+ * mind stays a dollar sign. */
+
 #endif