index.md (5198B)
1 --- 2 title: "Create an expiring Now Page in Hugo" 3 date: 2024-05-23T20:35:40-07:00 4 draft: false 5 categories: 6 - Meta 7 - Personal 8 tags: 9 - Hugo 10 --- 11 12 I have added a [now page](https://nownownow.com/about) to my site and a link 13 to it in the navigation footer below. This isn’t particularly 14 noteworthy---I’m pretty boring, so its content will probably only interest 15 a few of my friends and family members (..._maybe_). However, because I have 16 enough self-awareness to realize that I will “occasionally” let this become 17 out of date, I devised a workaround that feels worth sharing: I learned how 18 to make [Hugo](https://gohugo.io) (the program I use to build this site) 19 hide my now page whenever it gets too old. 20 21 The changes I made to my site configuration are captured in [this Git 22 commit](https://git.eamoncaddigan.net/www.eamoncaddigan.net/commit/1cf71f032c794808d5a4d6bc5fcd7dd8024074dd.html#h3-0-8). 23 Since configurations and templates can vary so much between Hugo projects, 24 I’ll explain each one a little bit in case anyone wants to do something 25 similar for their site. 26 27 ## Set an expiration time parameter 28 29 First, decide how old you’ll let your page get before it expires, and 30 convert that value to seconds. For expiration times in days or weeks this is 31 pretty straightforward: every day has exactly 86,400 seconds, so every week 32 has 604,800 seconds. For expiration times in months and years, this is 33 trickier. I recommend approximating months with fractional years; e.g., 34 three months is about 1/4 of a year. If you go this route, you’ll need to 35 choose the duration of a year, bearing in mind: 36 37 - The modal year has 365 days 38 - The mean year according to our Gregorian calendar has 365.2425 days 39 - The mean year between 2024 and 2099 (inclusive) has 365.25 days 40 41 Create a new variable in your [Hugo 42 configuration](https://gohugo.io/getting-started/configuration/) with this 43 value; I called mine `now_timeout` and set it to ~1/2 a year. 44 45 ``` 46 now_timeout: 15778800 47 ``` 48 49 ## Create your now page 50 51 Create new content to represent your now page: 52 53 ``` 54 hugo new content content/now/index.md 55 ``` 56 57 (Note that all the shell commands should be run from the root folder of your 58 project directory.) 59 60 Write your post, and make sure the following parameters are included in your 61 [front matter](https://gohugo.io/content-management/front-matter/): 62 63 ``` 64 --- 65 title: "Now" 66 date: [Place the date here] 67 layout: now 68 alternate: This page is out of date. 69 --- 70 ``` 71 72 The `layout` is explained in the next step, and the `alternate` parameter 73 defines the text that will be shown in place of your now page when it 74 becomes a “then page”. 75 76 ## Create a ‘now’ layout 77 78 Your now page will probably use a layout similar to your ‘page’ layout. If 79 you’re still using your theme’s default layout, make a copy and modify it 80 (replacing `your-theme` with the name of the theme you’re using): 81 82 ``` 83 mkdir -p layouts/page 84 cp themes/your-theme/layouts/_default/single.html layouts/page/now.html 85 ``` 86 87 Edit this file, replacing the occurrence of `{{ .Content }}` with the 88 following: 89 90 ``` 91 {{ if ge .Lastmod.Unix (sub time.Now.Unix .Site.Params.now_timeout) }} 92 {{ .Content }} 93 {{ else }} 94 <p>{{ .Param "alternate" }}</p> 95 {{ end }} 96 ``` 97 98 This is a basic if-then-else construct. If the page hasn’t expired yet, it 99 will display it as normal, but if it has, the `alternate` text from the 100 front matter will replace it. The reason that we chose an expiration time in 101 seconds is that we’re comparing the “Unix time” representations of the page 102 build time and the now page’s last modification time. If the template 103 language supported duration values in months, I’d probably use that, but 104 since it doesn’t it’s not worth the effort. 105 106 ## Add a disappearing “Now” link to your navigation 107 108 This step will be highly theme-dependent. Your site’s navigation is probably 109 implemented with a [“partial”](https://gohugo.io/templates/partials/); for 110 example, [my theme](https://github.com/cjtheham/hugo-theme-readable) keeps 111 this in `themes/readable/layouts/partials/footer.html`. Replacing 112 `your-theme` with your actual theme name again, and `nav-partial` with the 113 file that contains the navigation elements, make a copy of the file and edit 114 it: 115 116 ``` 117 mkdir -p layouts/partials 118 cp themes/your-theme/layouts/partials/nav-partial.html layouts/partials/ 119 ``` 120 121 Now the version of the navigation partial that lives in your 122 `layouts/partials` directory will override your theme’s. Find the list of 123 navigation links in your copy, and add a block like the following: 124 125 ``` 126 {{ $now := .GetPage "/now/" }} 127 {{ if ge $now.Lastmod.Unix (sub time.Now.Unix .Site.Params.now_timeout) }} 128 <a href="{{ $now.RelPermalink }}">{{ $now.Title }}</a> 129 {{ end }} 130 ``` 131 132 The `<a>` tag will probably need to be wrapped in a `<p>` or `<li>` tag, 133 depending on your theme. 134 135 This is similar to the change we made for the now layout, only there’s no 136 “else” clause, and we’re finding the now page content, storing it in 137 a variable, and accessing its attributes. This was the part of Hugo theming 138 that really required me to stop and build a better mental model of the site 139 generation process. 140 141 ## That’s it 142 143 I hope this is useful to someone else!