how to fetch the frontmatter of any hugo markdown page (not just _index.md) - hugo

I'm trying to write a shortcode for my hugo site that fetches the title parameter of page.
I have a directory structure like this:
content
├── workshops
│   ├── foo
│   │   └── _index.md
│   ├── bar.md
This works perfectly:
{{ with .Site.GetPage "home" "workshops/foo"}}
{{ .Params.Title }}
{{ end }}
And this one consistently comes up blank (even though there is a title in the markdown).
{{ with .Site.GetPage "home" "workshops/bar"}}
{{ .Params.Title }}
{{ end }}
My question is: How so I get the title of a standalone page?
I've tried a bunch of different combinations of things and I'm just not coming right. I've tried reading the docs and they are horribly convoluted on this point.

I have a solution! I wrote a little Python3.7 script to make directories and move and rename markdown files and just ran it over my entire contents directory. This solved my problem but is a bit of a hack...
import logging
import os
from pathlib import Path
def fixup(path):
location = Path(path)
assert location.is_dir(), location
for child in location.iterdir():
if child.is_dir():
fixup(child)
else:
fix_file(child)
def fix_file(file_path):
name = file_path.name
if not name.endswith(".md"):
# we only care about markdown files.
return
check_metadata(file_path)
if name.startswith("_index."):
# looks good
return
# make a directory with the same name as the file (without the extension)
suffix = ''.join(file_path.suffixes)
prefix = name[: -len(suffix)]
new_dir = file_path.parent / prefix
new_dir.mkdir()
new_path = new_dir / f"_index{suffix}"
file_path.rename(new_path)
def check_metadata(file_path):
""" given the path to a markdown file, make sure that the frontmatter includes
the required metadata
"""
# TODO
# required = ['title']
# allowed = ['pre', 'weight', 'ready']
if __name__ == '__main__':
fixup('content')

Two differences:
Use the global site variable
Just pass the page name as the argument
{{ with site.GetPage "workshops/bar" }}
{{ .Title }}
{{ end }}

Related

Shake: depend on rules from Shakefile in subdirectory?

I've got a project that looks something like this:
.
├── pyproject.toml
├── server.py
├── Shakefile.hs
└── ui
├── index.ts
└── Shakefile.hs
ui/Shakefile.hs contains something to the effect of:
import Development.Shake
main = shakeArgs shakeOptions $ do
want ["dist/index.js"]
"dist/index.js" %> \out -> do
need ["index.ts"]
cmd "tsc --outFile" [out]
and the root Shakefile.hs looks like:
import Development.Shake
main = shakeArgs shakeOptions $ do
want ["dist/server.tar"]
"dist/server.tar" %> \out -> do
need ["ui/dist/index.js", "server.py"]
cmd "tar cf" [out, "ui/dist/index.js", "server.py"]
Question: how should I model dist/server.tar's dependency on ui/dist/index.js?
My first guess was simply to add a rule specifying how to build ui/dist/index.html relative to the project root, with the action being to simply call shake (so that I don't have to keep the recipes in sync):
-- added to ./Shakefile.hs
"ui/dist/index.js" %> \_ -> do
cmd "stack exec shake -- -C ui dist/index.js"
BUT, considering the Shake paper cites Recursive Make Considered Harmful, I'm near certain this isn't the way to go.
Is there a way to import rules from another Shakefile? Can vanilla Haskell's import system be used to implement something like this? In either case, how could we (automatically?) translate rules and actions using paths relative to the child directory to be correct relative to the parent?
In general, I'm wondering about Shake's applicability to monorepos, and about the composability of different Shake-based build systems (i.e. Shakefiles from different internal projects).
Thanks for your consideration!

adding a page bundle with `hugo new`

I can add a new page with hugo new posts/new-page. But I want to add a page bundle. None of the following work
hugo new posts/2021/10/new-page creates a single new-page.md
hugo new posts/2021/10/new-page/ does the same as above
hugo new posts/2021/10/new-page/index.md works, kind. It creates index.md in the correct path and populates index.md with the archetypes/default.md except, it set the title to index instead of new page
so, how can I add a page bundle with hugo new
You can achieve that using Archetypes , quoting from the docs:
Since Hugo 0.49 you can use complete directories as archetype templates.
in the archetypes/ folder create a new folder named post-bundle/
inside it create a new file index.md
archetypes/post-bundle/index.md :
---
title: "{{ replace .Name "-" " " | title }}"
date: {{ .Date }}
draft: true
---
Then to create a page bundle:
hugo new --kind post-bundle posts/new-page
Notice: I don't think the approach you're doing to set the date in the url is correct , the above method will give a post with the following Permalink : example.com/posts/new-page you can then do the following to get the desired Permalink:
config.toml :
[permalinks]
posts = '/:year/:month/:title/'
In support of Mossab's answer...
a page bundle has three categories:
Branch,
headless
and leaf.
So if you made a file _index.md - it's a Branch bundle, off-the-bat. So viola that's how you make it with hugo new.
If you want a headless bundle, I believe you first need a leaf bundle, and then add:
headless = true to the front matter.
If you want a lead bundle you create an index.md file at any directory level.
So, I believe my point in this is, the way you do this is:
hugo new _index.md
Or
hugo new index.md
and if you want it headless, you use an archetype with the front matter (as Mossab desribes).
Please let me know if I'm possibly misunderstanding something.

How to get complex data from data folder in Hugo

Having the following file in the data folder:
# data/files.json
{
"test/file1.txt": "abcd/1234567890.txt",
"test/file2.txt": "bcde/1234567890.txt"
}
How do I obtain the value of "test/file1.txt" from the map? For example from this file
// layout/index.ace
= doctype html
html lang={{ .Site.Language.Lang }}
body
p {{ .Site.Data.files.????? }}
This is my environment:
$ go version
go version go1.9.2 linux/amd64
$ hugo version
Hugo Static Site Generator v0.35-DEV linux/amd64 BuildDate:
// layout/index.ace
= doctype html
html lang={{ .Site.Language.Lang }}
body
p {{ index .Site.Data.files "test/file1.txt" }}
does the trick.

How to add a new hugo static page?

From the "getting started" section it seems this should work, but it doesn't.
hugo new site my-site
hugo new privacy.md
hugo server --watch --includeDrafts
curl -L localhost:1313/privacy/index.html
# 404 page not found
curl -L localhost:1313/privacy.html
# 404 page not found
curl -L localhost:1313/privacy/
# 404 page not found
How can I add a new page?
This is the best tutorial how to create static "landing pages" on Hugo: https://discuss.gohugo.io/t/creating-static-content-that-uses-partials/265/19?u=royston
Basically, you create .md in /content/ with type: "page" in front matter, then create custom layout for it, for example layout: "simple-static" in front matter, then create the layout template in themes/<name>/layouts/page/, for example, simple-static.html. Then, use all partials as usual, and call content from original .md file using {{ .Content }}.
All my static (landing) pages are using this method.
By the way, I'm not using hugo new, I just clone .md file or copy a template into /content/ and open it using my iA Writer text editor. But I'm not using Hugo server either, adapted npm-build-boilerplate is running the server and builds.
Just tested OK with this on Hugo 0.13:
hugo new site my-site
cd my-site
hugo new privacy.md
hugo server -w -D
curl -L localhost:1313/privacy/
Note: You have to either use a theme or provide your own layout template to get something more than a blank page. And of course, some Markdown in privacy.md would also make it even nicer.
See http://gohugo.io/overview/introduction for up-to-date documentation.
I had a similar requirement, to add static page (aboutus in this case). Following steps did the trick,
Created an empty file content/aboutus/_index.md
Created aboutus.html page layouts/section/aboutus.html
Make you have some default frontmatter set in archetypes/default.md
# archetypes/default.md
+++
title: "{{ replace .Name "-" " " | title }}"
date: {{ .Date }}
draft: true
+++
And the single layout in layouts/_default/single.html to render some variable or content
# tags to render markdown content
<h1>{{ .Title }}</h1>
<p>{{ .Content }}</p>
<span>{{ .Params.date }}</span>
Now type hugo new privacy.md which will create a new page on the following directory in content/privacy.md
Take "About" as example:
# will create content/about.md
hugo new about.md
Edit about.md and add the last 2 lines, the metadata/front matter looks like:
title: "About"
date: 2019-03-26
menu: "main"
weight: 50
That should work.

Render different static folder based on url request

Using Flask, I can render different templates based on the url. For example :
http://example.com/site1/ ; will render templates/site1/{htmls}
http://example.com/site2/ ; will render templates/site2/{htmls}
This works really great with jinja_loader and a custom Loader, but now I'm stuck with the static files.
The static files depends on the template, so they are located in templates/static/site{0-9}, but of course, I cannot set a jinja_loader on the static_folder parameter because it's not related to Jinja but to Flask.
How can I render the correct static folder based on the current URL?
As an example, here's the loaded code:
Flask(app_name,
static_url_path = '/public',
static_folder = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'templates/static')
)
and in templates/static, I have :
static/
site1/
css/
js/
images/
site2/
css/
js/
images/
etc...
You either have to use explicit paths in your static views:
url_for('static', filename='site1/css/...')
where site1 could be taken from request.path.split('/', 1)[0]:
url_for('static', filename='{}/css/...'.format(request.path.split('/', 1)[0]))
You could create a custom static view:
from flask import request, send_from_directory, current_app, safe_join
import os.path
#app.route('/<site>/static/<path:filename>')
def per_site_static(site, filename):
if site is None:
# pick site from the URL; only works if there is a `/site/` first element.
site = request.path.split('/')[0]
static_folder = safe_join(current_app.static_folder, site)
cache_timeout = current_app.get_send_file_max_age(filename)
return send_from_directory(static_folder, filename,
cache_timeout=cache_timeout)
Then use url_for() to generate urls:
{{ url_for('per_site_static', site=None, filename='css/...') }}
An other interesting alternative is the following :
class GenericStaticFlask(Flask):
def send_static_file(self, filename):
# g.site contains the name of the template path for siteX
return super(GenericStaticFlask, self).send_static_file("%s/%s" % (g.site, filename))
app = GenericStaticFlask(app_name,
static_url_path = '/public',
static_folder = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'templates/static')
)

Resources