Edgewall Software

Cross-References in Trac

Note: these ideas were once explored in an experimental branch (log:sandbox/trac-xref@2826), based on some old Trac 0.10dev version.

There is no plan to integrate this feature in Trac core. See also this mail.

As Trac is more than a wiki, its backlinks are of a more complex nature than traditional backlinks. Therefore the term cross-references will be used in favor of backlinks.

A cross-reference is a link from a Trac object (the source) to another Trac object (the target).

Usually, such links are created after processing some wiki text attached to the source object (a facet of that object).

Here's the current list of Trac objects that can reference each other, along with their facets:

  • Wiki page (has the Cross-references navigation link)
    • content facet (done)
    • attachment comment facets (depends-on #787)
  • Ticket (has the Cross-references navigation link)
    • summary facet (seems that it was never intended to support wiki formatting, see #1888)
    • description facet (done)
    • comments facets (done)
    • attachment comment facets (depends-on #787)
  • Changeset
    • log message facet
  • Report
    • title facet (see summary facet above)
    • description facet
  • Milestone
    • title facet (see summary facet above)
    • description facet
  • Source
    • (no facet, only available as a target)

To check the status on cross-references, see the list of issues.


A cross-reference is also called a relation when an explicit semantic is attached to the link from the source object to the target object.

If there is no relation defined, one simply knows that the two objects are somehow related, like with traditional backlinks.

However, in the cross-references listing, for each backlink, Trac will also show an excerpt of the source Wiki text containing the link, so that the implicit semantic can be easily guessed.

Those relations can be used to fulfill many needs. The ticket dependencies and other ticket relationships are one example (see #886). The tag feature, which could be reimplemented on top of relations, is another.

Displaying Cross-References

Each resource page has a navigation link Cross References, which leads to a page displaying the relations (Incoming and Outgoing) and the Backlinks:

Example showing how the cross-references look like

Creating Explicit Relations with the User Interface

This should be the normal way to create explicit relations. For example, the ticket form could be extended to include a duplicate of field, activated when the resolution type is set to duplicate (see #1395). The content of that field would be a facet for the ticket and any reference found in the facet will create a specific duplicate-of relation, with the ticket as a source and the reference as a target.

Wiki Syntax for Explicit Relations

If one wants maximum flexibility, it can be convenient to use a specific wiki syntax for creating an explicit relation from the current object to any other Trac object.

I would propose using <<the-relation LinkToTargetedObject>>, which can be nicely rendered in HTML as «the-relationLinkToTargetedObject».

Example, using the tag relation (should it be has-tag?): Writing

<<tag xref>>

would relate the Trac object to which this wiki text belongs to the Wiki page named "xref", using the explicit relation tag. This would tag the current page with the xref tag.

Multiple targets should be supported too:

<<tag xref, idea, #1242>>

Would tag this page with all those 3 objects.

Undecided issue:
In the above, I assume that unrecognized words should be taken as wiki page names, so that one can write idea instead of IdeaTag or wiki:idea. However, in a facet (like in the duplicate of example above), it might be convenient to add a description to the reference, like this is quite similar to #123, and just a rewording of #431. In that case, only recognized links should be taken as targets, of course.

Displaying Relations in the Wiki

Also, a few macros could be created to make a powerful usage of the relations:

  • Relations(rel) would provide a brief listing of Trac objects matching the rel.
  • Closure(rel) would provide a brief listing of all Trac objects in the transitive closure of the specified relation.
  • Count(rel) would provide a count of the objects matching the rel.

The relation description rel could be written using a similar syntax to the one used for the wiki and described above.

The idea being that if there exists a relation <<A relates-to B>>, then specifying:

  • <<A relates-to>> should result in B
  • <<relates-to B>> should result in A

Some concrete examples:

  • <<*rel* *tgt*>> would refer to the source objects related to the specified target object *tgt* by the relation *rel*. Examples:
    • <<tag xref>> all the objects having the xref tag
    • <<depends-on #123>> all the objects that depend on the ticket #123
    • Special object patterns: "." and "%"
      • <<depends-on .>> all the objects that depend on the current object
      • <<depends-on>> same as above, "." is the target if none given
      • <<tag CS103/%>> all the objects having a tag which name starts with CS103
  • <<*src* *rel*>> would refer to the target objects related to the specified source object *src* by the relation *rel*. Examples:
    • <<. tag>> would list all tags of the current object
    • <<% tag>> would list all tags of any object
    • <<. depends-on>> would list all the objects (usually tickets) on which the current object (usually a ticket) depends.

Implementation Notes

The xref branch currently contains an implementation of the cross-references, plus the infrastructure needed for the relations. That branch is kept in sync with all my other branches (TracDiff and InterTrac, which now both have been merged into trunk) and, as such, it is also quite in sync with the trunk.

See also:

  • The original enhancement request ticket: #1242
  • Backlink support: #611 and #646
  • Relationship and ticket dependencies support: #31, #226 and #886
  • Wiki Page renames: #1106
  • Other relationships: #449, #508

Refactoring Ideas

It should be noted that this general mechanism could be used to reimplement a few things in Trac so that they become more general:

  • the ticket keywords could be reimplemented by using the tag relation described above. Unifying keywords and tags would enable to attach them to any Trac Object (see #695). In addition, one could fill the keyword list by picking in a list of already existing keywords.
  • the ticket components could be be reimplemented using a has-component relation, with the components being wiki pages. The advantage would be that a ticket could have multiple components (#1730), and that the component could be documented (#1233) and used in a meaningful way in other relationships (e.g. #548, #1678 and TracMultipleProjects/SingleEnvironment#UsingComponentobjects).
  • idem for the versions, using a has-version relation.

Components would be Wiki pages created from a ComponentTemplate page, therefore having an is-a relationship to the above ComponentTemplate page. This makes it simple to retrieve all components: those are the [[Relation(<<is-a ComponentTemplate>>)]] objects, or, in Python code,

components = WikiPage(self.env, 'ComponentTemplate').sources('is-a')

Of course, the ComponentTemplate is-a TemplateTemplate.


Q: This feature was cited in a Trac feature request comment as supporting automatic back-links in wiki pages, but this descriptions sounds like something different. Am I reading it wrong?

A: Well, the TracCrossReferences scope is much wider than simple back links, but nevertheless back links are implemented here. Look at the snapshot again.

Last modified 5 years ago Last modified on Aug 6, 2018, 2:43:34 PM

Attachments (1)

Download all attachments as: .zip

Note: See TracWiki for help on using the wiki.