For a while there’s been some confusion around the best way to create new standalone pages in a plug-in and link them from a blog’s navigation (Hugo menu). While @sod’s new Search Space plug-in is in beta, I thought this might be a good opportunity to revisit this question and see if anyone has feedback about improvements we could make.
To summarize, a plug-in can create new pages, and when it does it has the option to automatically include it in a menu using Hugo front matter, or leave it up to the user to create a page redirect. Including the page automatically is restrictive, but pages that redirect somewhere don’t have a good UI currently. (It requires adding the full URL as the page content.)
I can think of a few ways to solve this:
Improve the page/redirect UI. Maybe we should do this anyway.
Add a plug-in setting that will show a checkbox to include the page the plug-in provides in the menu.
Add a plug-in setting that exposes which pages it will create, and let Micro.blog provide some kind of UI for the user to choose from that when updating the navigation. Might be similar to how WordPress links to named pages in a menu.
Oh, yes, I’m all for this! @manton and I talked about this over mail back in February. I’m including my initial letter here for a bit of background and my proposal for how this could work.
Hey Manton,
Here are my thoughts spurred by the discussion about pages from plug-ins in the menu. It makes sense to ship pages to the end-user for many plug-ins, like my own Surprise me!, Search page by renowned Manton Reece, and Amit’s Posts Stats.
Generally, people like stuff that “just works”. So I would gladly just tuck the Surprise me! page in the menu for them. Except I don’t, because:
What if the blog is in another language, and the owner wants to change the page name?
Or maybe they want to rearrange the order of the menu.
Some people don’t want that thing in the menu at all.
So instead, I just ship the page, and it’s up to the person installing the plug-in to add the page to the menu if they want. The problem is that’s not intuitive, and one might end up causing infinite redirect.
Maybe it could work like this? For example, plug-in developers adds the following frontmatter to their page:
Not sure if it should remove the page or keep it, but we can work that out.
My gut tells me the page should disappear from the list. But it could be a soft delete. When someone troubleshoots a plug-in or starts from scratch (uninstalls everything), it’s nice if the old page bounces back. Especially if the person had additional content on the page.
But it might break expectations in some cases. Maybe these pages should have a Reset button instead of a delete button? When tapped, you delete the page from the database (is that how it works?) and create a new entry.
I’m also reworking the Archive and Photos pages so they are more similar to other pages, not using output formats, so all these might be good to release at the same time.
Could Archive and Photos be content of the default theme or a first-part plug-in? Maybe that’s what meant by rework. That way, you don’t need different implementations, and users will get the same experience for every special page in Micro.blog.
Yeah, this is a much-needed improvement. I have got a lot of feedback about showing/hiding pages (those of plug-ins and non-plug-ins). So, we know there’s scope for improvement.
Specifically for plug-ins, I believe the plugin.json is the best place for such a setting as this information is for Micro.blog to identify a new page being added. Something on the lines of say.
"pages": [
"/contents/stats.md"
]
Micro.blog can then parse the page for details and populate it in the pages list. A user can then reorder or hide it. I like the flow proposed by@sod around this.
I think if I understand this right, it’s related to some challenges I’ve had in my theme that led to this template code that I barely remember writing in some kind of fugue state:
{{ range $menuitem := .Site.Params.Menu }}
<li>
<a class="{{ if eq .URL $url }}active{{ end }}"
href="{{ index $menuitem "url" }}">
{{ index $menuitem "name" }}
</a>
</li>
{{ end }}
{{ with site.Menus.main }}
{{ range . }}
<a class="{{ if eq .URL $url }}active{{ end }}" href="{{ .URL }}">
{{ .Name }}
</a>
{{ end }}
{{ end }}
I did this to support Micro.blog generated pages while allowing my site config to set other menu items:
I have never loved this solution, and I also seem to remember trying to not override things quite this way, but having trouble plugging into where Micro.blog wanted me to store this information.
Overall, I think there should be something similar to the setup for custom JS or custom CSS:
{{- if isset .Site.Params "customjs" -}}
{{- range .Site.Params.customJS }}
<script src="{{ $.Site.BaseURL }}{{ . }}"></script>
{{- end }}
{{- end }}
So a plugin can supply something that is merged into .Site.Params.customPages and perhaps there’s something else like .Site.Params.Pages for MB generated pages. This makes both sets of data easy to add to and easy to access for theme developers to support.
I wonder if a “pages” field in the config.json would be necessary, since Micro.blog could just look at any file in “/contents”… If there wasn’t a “menu” field in the front matter, Micro.blog would ignore it for the purposes of the UI. It does require more parsing and fiddling with front matter than Micro.blog normally needs to do, though.