Repository links and page info
The repository-related entries in the action menu at the right of the
breadcrumb row are derived from a few github_* parameters, and the “last
modified” line at the page end comes from git history. Both assume the content
lives in a GitHub-style repository.
Four keys wire up every link
Every repository-related entry in the action menu derives from these keys:
That is this site’s real configuration. With it filled in, this page’s action menu points at:
| Menu entry | Target |
|---|---|
| Edit this page | …/edit/main/content/docs/customize/repository.md |
| View history | …/commits/main/content/docs/customize/repository.md |
| Create child page | …/new/main/content/docs/customize?filename=change-me.md&value=<template> |
| Open a documentation issue | …/issues/new?title=Repository links and page info |
| Open a project issue | https://github.com/pgsty/oink/issues/new |
A few conventions:
github_repopoints at the repository holding the content, not the theme repository. Naming the theme repository sends a reader’s change to the wrong place. Omit it and all five rows above disappear.github_project_repois a second repository, receiving product bugs rather than documentation errors. Do not configure it where readers cannot tell the two apart.github_branchdefaults tomainand names the content branch — not the deployment branch, and not the branch Pages generates.github_subdiris the path inside the repository. Leave it empty when the site source is at the repository root; set it towebsitewhen the source sits in a subdirectory (a repository holding both code andwebsite/, say).
All of these can be set at site level, per language, in a section cascade or in a page’s front matter, which matters when content comes from several repositories. The full definitions are in Configuration.
Content from another repository
When a subtree is mounted from an upstream repository, override the repository
parameters with a section cascade, then use path_base_for_github_subdir to
tell the theme: strip the local path prefix, and append what remains to
github_subdir.
content/reference/api/client.md therefore maps to the upstream’s
docs/api/client.md.
The value of path_base_for_github_subdir is a regular expression. Where the
source filename differs from the local one, use a from / to mapping instead
— for example, matching each section’s _index.md to the upstream README.md:
OINK keeps .md and .zh.md side by side in one directory, so both languages
share a path prefix and the expression needs no language directory. After
changing it, click “edit this page” once from a leaf page, once from a section
index and once in each language: when the expression strips too much, the
generated URL looks plausible and is a 404.
Turning individual entries off
Every menu entry carries a stable action ID:
| Menu entry | Action ID |
|---|---|
| Copy as Markdown | copy_markdown |
| View Markdown source | view_markdown |
| Open in ChatGPT / Claude | open_chatgpt / open_claude |
| View history | view_history |
| Edit this page | edit_page |
| Create child page | create_child_page |
| Open a documentation issue | create_issue |
| Open a project issue | create_project_issue |
| Print the whole section | print_section |
Where a host does not support one, hide it with CSS:
The command palette uses the same IDs, so hiding a menu entry does not remove it from the palette. A target the whole site cannot use should have its key omitted from the configuration rather than covered with CSS: CSS can hide a link, but it cannot make a wrong link right.
The whole menu can also be turned off per page with page_context_menu: false
in front matter — see Page parameters.
The new-page template that “create child page” prefills comes from the theme’s
assets/stubs/new-page-template.md; a site replaces it with its own skeleton by
placing a file of the same name at assets/stubs/new-page-template.md.
Last modified
This line’s data comes from git, not from a file’s mtime. Turn on Hugo’s git support:
The page end then reads “Last modified August 17, 2026 · …/commit/<hash>. The three values
of lastmod_commit:
| Value | What is shown |
|---|---|
subject (default) |
The commit subject plus the abbreviated hash |
hash |
commit a1b2c3d |
none |
The date only, with no commit link |
Any other value fails the build with invalid params.ui.lastmod_commit.
Two things to watch:
- CI needs enough git history. A shallow clone (
fetch-depth: 1) cannot reach a file’s last commit, and the date goes missing or wrong. Setfetch-depth: 0in GitHub Actions. - An uncommitted file has no git time. Previewing a newly written page locally, this line is simply absent.
Where git history is unavailable, do not substitute the build time for “last modified”: build time is not when the content changed.
This line belongs to the annotation component, which is on by default and
sits after feedback and before the pager. Turn it off for a page with
annotation: false.
The line is not all the annotation block renders. The same block also carries two kinds of provenance, both driven by page front matter and needing no template override:
- Upstream attribution: a page derived from elsewhere writes
upstream_linkplus the four required keysupstream_name,upstream_copyright,upstream_licenseandupstream_notice, and the page end gains an attribution line naming the work, the copyright holder, the licence and a link to the full notice. Addingupstream_modified: trueappends a “modified downstream” line. - Translation notice:
params.ui.translation_noticeholds the language code of the authoritative version, and a translated page then shows a line pointing back at the original; a page authored natively in this language opts out withtranslation_notice: false.
Both families are defined in full in Page parameters.
Where customization really is needed, three override points cover one layer each:
| Partial to override | What it changes |
|---|---|
layouts/_partials/annotation-items.html |
Add, remove or reorder the lines, keeping the theme’s markup, icons, print rules and accessible label |
layouts/_partials/page-meta-lastmod.html |
Replace the markup those lines render as |
layouts/_partials/page-annotation.html |
Replace the block’s outer container |
What the page end is made of
The five components are in a fixed order, and every reading layout shares one implementation:
| Order | Component | Theme default | Page switch |
|---|---|---|---|
| 1 | Share | Off (params.ui.share is empty) |
share: false, or the page’s own list |
| 2 | Feedback | Off | feedback: true / false |
| 3 | Annotation | On | annotation: false |
| 4 | Pager | On for docs / book / blog | pager: false |
| 5 | Comments | On when fully configured | comments: false |
The order follows what a reader does after the last paragraph: hand the page on, say whether it helped, see where it came from, go to the next one, join the discussion. Share leads because it is the only block that points outward, and because a reader who has decided to pass a page on decided it before being asked how the page went. Configuring the bar is in Writing a blog.
Configuring comments is in Comments.
The feedback widget
One question and two buttons: “Did this page solve your problem?” → yes / no. Choosing no expands four optional reasons. It is off by default:
To enable it for the documentation section only, use a cascade (a blog usually keeps just comments):
Where the boundaries are:
- A click completes it. There is no text box, no submit button and no sign-in.
- The choice is written to the browser’s
localStorageper page and language, so a returning reader sees and can change it. - Where the site already has Google Analytics (
gtag), it sends adocs_feedbackevent withresult(solved/not_solved),page_pathandlanguage; choosing a reason sends a second event carryingreasonandrefinement: true, distinguishing it from the first count. Without analytics the widget still works, simply reporting nothing — it needs no backend at all. - Where the page has comments enabled, an anchor link reading “add details in the comments” appears under the result. Feedback and giscus are two independent data flows, and the theme never writes a comment on the reader’s behalf.
This page sets feedback: true in its front matter (the docs section defaults
it off), so the real widget is visible at the page end.
The contributor wall
The contributors shortcode renders a wall of GitHub avatars from a file under
the site’s data/ directory, and never contacts GitHub at build time:
The fields: github is required (validated as a GitHub username, and a
duplicate fails the build); name defaults to github; role is optional;
url defaults to https://github.com/<github>; avatar is optional, and
without it an initial placeholder block is rendered with no network request at
all, while a value must be http(s):// or a site-root-relative path.
Several lists mean several data files, selected with data=:
In Markdown and RSS output the wall degrades to a list of
- [@handle](url) — role.
data/contributors.yamlThe example above therefore does not render on this page. Drop a data file
into data/ to see it.
Verify
- Open the action menu at the right of this page’s breadcrumb row: “edit this page” should point at
github.com/<your repository>/edit/<branch>/<source path>, with the path matching the repository segment for segment. - Click it again from a section index (
_index.md): a section index is the likeliest thing for apath_base_for_github_subdirexpression to get wrong. - The page end should have a “last modified” line; its absence on a locally created, not-yet-committed page is expected.
- Check the generated links from the command line:
Related
- Page parameters —
annotation/feedback/pager/page_context_menuand the other page switches - Configuration — full definitions of
github_*,ui.lastmod_commitandui.feedback - Comments — the last block at the page end
- Analytics and SEO — where feedback events land
- AI-agent support — the Markdown and assistant entries in the action menu
Was this page helpful?
Thanks—your feedback helps us improve this page.
What got in the way? (optional)