just a barebones solution would be the following:
package main
import (
"fmt"
"os"
"text/template"
)
func main() {
//read in one go the header, footer and all your other tmpls.
//append to that slice every time the relevant content that you want rendered.
alltmpls := []string{"./layouts/header.tmpl", "./layouts/footer.tmpl", "./users/index.tmpl"}
templates, err := template.ParseFiles(alltmpls...)
t := templates.Lookup("header.tmpl")
t.ExecuteTemplate(os.Stdout, "header", nil)
t = templates.Lookup("index.tmpl")
t.ExecuteTemplate(os.Stdout, "index", nil)
t = templates.Lookup("footer.tmpl")
t.ExecuteTemplate(os.Stdout, "footer", nil)
}
in reality you would want a function that returns a slice of the appropriate files to populate the alltmpls variable. It should scan your directories and get all files from there to pass to ParseFiles() and then proceed to call the Lookup and ExecuteTemplate steps for every template.
Taking this idea further, i would create a new type that would embed a template (or a slice of templates) to be annotated by a header and a footer.
type hftemplate struct {
template.Template
header, footer *template.Template
}
func (h *hftemplate) ExecuteTemplate(wr io.Writer, name string, data interface{}) error {
h.header.ExecuteTemplate(wr, "header", nil)
err := h.ExecuteTemplate(wr, name, data)
h.footer.ExecuteTemplate(wr, "footer", nil)
return err
}
and of course you can turn that struct embedding into a fully fledged field of []Template to do multiple ExecuteTemplates between the header and the footer.