func RouteContent(siteRouters SiteRouters, defaultRouters SiteRouters) {
	for site, subRouter := range siteRouters {
		subRouter.HandleFunc("/content/view/{id}", func(w http.ResponseWriter, r *http.Request) {
			r = setVar(r, "site", mux.CurrentRoute(r).GetName())
			HandleContent(w, r)
		}).Name(site)
		subRouter.MatcherFunc(niceurl.ViewContentMatcher).HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			r = setVar(r, "site", mux.CurrentRoute(r).GetName())
			HandleContent(w, r)
		}).Name(site)
	}
	for site, router := range defaultRouters {
		router.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
			r = setVar(r, "site", mux.CurrentRoute(r).GetName())
			handleRoot(w, r)
		}).Name(site)
		router.HandleFunc("", func(w http.ResponseWriter, r *http.Request) {
			r = setVar(r, "site", mux.CurrentRoute(r).GetName())
			handleRoot(w, r)
		}).Name(site)
	}
}
Handle contents after initialization
package sitekit
import (
	"context"
	_ "embed"
	"errors"
	"fmt"
	"io"
	"net/http"
	"strconv"
	"strings"
	"github.com/digimakergo/digimaker/core/contenttype"
	"github.com/digimakergo/digimaker/core/log"
	"github.com/digimakergo/digimaker/core/permission"
	"github.com/digimakergo/digimaker/core/query"
	"github.com/digimakergo/digimaker/core/util"
	"github.com/digimakergo/digimaker/sitekit/niceurl"
	"github.com/flosch/pongo2"
	"github.com/gorilla/mux"
)
var mainTemplate []byte
var siteSettings = map[string]SiteSettings{}
var siteIdentifiers = []string{}
type SiteSettings struct {
	Site            string
	TemplateBase    string
	TemplateFolders []string
	RootContent     contenttype.ContentTyper
	DefaultContent  contenttype.ContentTyper
	Host            string
	Path            string
}
func GetSiteSettings(identifier string) SiteSettings {
	return siteSettings[identifier]
}
func GetSites() []string {
	return siteIdentifiers
}
func SetSiteSettings(identifier string, settings SiteSettings) {
	siteSettings[identifier] = settings
	siteIdentifiers = append(siteIdentifiers, identifier)
}
func LoadSite(siteConfig map[string]interface{}) error {
	siteIdentifier := siteConfig["identifier"].(string)
	if _, ok := siteConfig["template_folder"]; !ok {
		return errors.New("Need template_folder setting.")
	}
	templateFolder := util.InterfaceToStringArray(siteConfig["template_folder"].([]interface{}))
	if _, ok := siteConfig["root"]; !ok {
		return errors.New("Need root setting.")
	}
	root := siteConfig["root"].(int)
	rootContent, err := query.FetchByID(context.Background(), root)
	if err != nil {
		return fmt.Errorf("Root doesn't exist: %w", err)
	}
	if _, ok := siteConfig["default"]; !ok {
		return errors.New("Need default setting.")
	}
	defaultInt := siteConfig["default"].(int)
	var defaultContent contenttype.ContentTyper
	if defaultInt == root {
		defaultContent = rootContent
	} else {
		defaultContent, err = query.FetchByID(context.Background(), defaultInt)
		if err != nil {
			return fmt.Errorf("Default doesn't exist: %w", err)
		}
	}
	host := siteConfig["host"].(string)
	path := ""
	if _, ok := siteConfig["path"]; ok {
		path = siteConfig["path"].(string)
	}
	siteSettings := SiteSettings{
		Site:            siteIdentifier,
		TemplateBase:    templateFolder[0],
		TemplateFolders: templateFolder,
		RootContent:     rootContent,
		DefaultContent:  defaultContent,
		Host:            host,
		Path:            path}
	SetSiteSettings(siteIdentifier, siteSettings)
	log.Info("Site settings loaded: " + siteIdentifier)
	return nil
}
func HandleContent(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	id, _ := strconv.Atoi(vars["id"])
	sitePath := GetSitePath(r)
	site := vars["site"]
	ctx := r.Context()
	err := OutputContent(w, id, site, sitePath, ctx)
	if err != nil {
		log.Error(err.Error(), "template", r.Context())
		requestID := log.GetContextInfo(ctx).RequestID
		http.Error(w, "Error occurred. request id: "+requestID, http.StatusInternalServerError)
	}
}
func GetSitePath(r *http.Request) string {
	sitePath := ""
	vars := mux.Vars(r)
	if path, ok := vars["path"]; ok {
		sitePath = path
	}
	result := strings.TrimSuffix(sitePath, "/")
	return result
}
func handleRoot(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	site := vars["site"]
	defaultContent := siteSettings[site].DefaultContent
	defaultContentID := defaultContent.GetLocation().ID
	vars["id"] = strconv.Itoa(defaultContentID)
	r = mux.SetURLVars(r, vars)
	HandleContent(w, r)
}
func setVar(r *http.Request, key string, value string) *http.Request {
	vars := mux.Vars(r)
	vars[key] = value
	r = mux.SetURLVars(r, vars)
	return r
}
type SiteRouters map[string]*mux.Router
func GetSiteRouters(r *mux.Router) (SiteRouters, SiteRouters) {
	sites := GetSites()
	subRouters := SiteRouters{}
	defaultRouters := SiteRouters{}
	for _, identifier := range sites {
		settings := GetSiteSettings(identifier)
		host := settings.Host
		path := settings.Path
		var subRouter *mux.Router
		if path != "" {
			subRouter = r.Host(host).PathPrefix("/{path:" + path + "}/").Subrouter()
			defaultRouter := r.Host(host).PathPrefix("/{path:" + path + "}").Subrouter()
			defaultRouters[identifier] = defaultRouter
		} else {
			subRouter = r.Host(host).Subrouter()
			defaultRouters[identifier] = subRouter
		}
		subRouters[identifier] = subRouter
	}
	return subRouters, defaultRouters
}