diff --git a/dynamic_page.go b/dynamic_page.go index 32b9f3d..c8cbce1 100644 --- a/dynamic_page.go +++ b/dynamic_page.go @@ -129,8 +129,8 @@ func (p *DynamicPage) DebugVariables() VariableMap { // Write applies Liquid and Markdown, as appropriate. func (p *DynamicPage) Write(w io.Writer) (err error) { - p.site.ConfigureLiquid() - body, err := helpers.ParseAndApplyTemplate(p.Content, p.TemplateVariables()) + config := p.site.LiquidConfiguration() + body, err := helpers.ParseAndApplyTemplate(p.Content, p.TemplateVariables(), config) if err != nil { err = &os.PathError{Op: "Liquid Error", Path: p.Source(), Err: err} return @@ -138,7 +138,7 @@ func (p *DynamicPage) Write(w io.Writer) (err error) { if p.Site().IsMarkdown(p.relpath) { body = blackfriday.MarkdownCommon(body) - body, err = p.applyLayout(p.frontMatter, body) + body, err = p.applyLayout(p.frontMatter, body, config) if err != nil { return } diff --git a/helpers/liquid.go b/helpers/liquid.go index 6426aba..0fc39ff 100644 --- a/helpers/liquid.go +++ b/helpers/liquid.go @@ -4,6 +4,7 @@ import ( "bytes" "github.com/acstech/liquid" + "github.com/acstech/liquid/core" ) // RenderTemplate is a wrapper around liquid template.Render that turns panics into errors @@ -23,8 +24,8 @@ func RenderTemplate(template *liquid.Template, variables map[string]interface{}) } // ParseAndApplyTemplate parses and then renders the template. -func ParseAndApplyTemplate(bs []byte, variables map[string]interface{}) ([]byte, error) { - template, err := liquid.Parse(bs, nil) +func ParseAndApplyTemplate(bs []byte, variables map[string]interface{}, config *core.Configuration) ([]byte, error) { + template, err := liquid.Parse(bs, config) if err != nil { return nil, err } diff --git a/layout.go b/layout.go index bca5b9b..87785f6 100644 --- a/layout.go +++ b/layout.go @@ -10,6 +10,7 @@ import ( "github.com/osteele/gojekyll/helpers" "github.com/acstech/liquid" + "github.com/acstech/liquid/core" ) // FindLayout returns a template for the named layout. @@ -42,10 +43,10 @@ func (s *Site) FindLayout(base string, fm *VariableMap) (t *liquid.Template, err if err != nil { return } - return liquid.Parse(content, nil) + return liquid.Parse(content, s.LiquidConfiguration()) } -func (p *DynamicPage) applyLayout(frontMatter VariableMap, body []byte) ([]byte, error) { +func (p *DynamicPage) applyLayout(frontMatter VariableMap, body []byte, config *core.Configuration) ([]byte, error) { for { layoutName := frontMatter.String("layout", "") if layoutName == "" { diff --git a/site.go b/site.go index a2c2f70..6397e27 100644 --- a/site.go +++ b/site.go @@ -1,14 +1,18 @@ package main import ( + "io" "io/ioutil" "os" + "path" "path/filepath" "strings" "time" + "github.com/acstech/liquid" + "github.com/acstech/liquid/core" "github.com/osteele/gojekyll/helpers" - "github.com/osteele/gojekyll/liquid" + liquidHelper "github.com/osteele/gojekyll/liquid" ) // Site is a Jekyll site. @@ -21,8 +25,9 @@ type Site struct { Variables VariableMap Paths map[string]Page // URL path -> Page - config SiteConfig - sassTempDir string + config SiteConfig + liquidConfiguration *core.Configuration + sassTempDir string } // NewSite creates a new site record, initialized with the site defaults. @@ -100,11 +105,14 @@ func (s *Site) LayoutsDir() string { func (s *Site) ReadFiles() error { s.Paths = make(map[string]Page) + walkFn := func(name string, info os.FileInfo, err error) error { if err != nil { return err } + relname, err := filepath.Rel(s.Source, name) if err != nil { + panic(err) } switch { case info.IsDir() && s.Exclude(relname): @@ -112,6 +120,8 @@ func (s *Site) ReadFiles() error { case info.IsDir(), s.Exclude(relname): return nil } + defaults := s.GetFrontMatterDefaults(relname, "") + p, err := ReadPage(s, nil, relname, defaults) if err != nil { return err } @@ -141,8 +151,25 @@ func (s *Site) initTemplateAttributes() { } } -func (s *Site) ConfigureLiquid() { - liquid.SetFilePathURLGetter(s.GetFileURL) +// LiquidConfiguration configures the liquid tags with site-specific behavior. +func (s *Site) LiquidConfiguration() *core.Configuration { + if s.liquidConfiguration != nil { + return s.liquidConfiguration + } + liquidHelper.SetFilePathURLGetter(s.GetFileURL) + includeHandler := func(name string, writer io.Writer, data map[string]interface{}) { + name = strings.TrimLeft(strings.TrimRight(name, "}}"), "{{") + filename := path.Join(s.Source, s.config.IncludesDir, name) + template, err := liquid.ParseFile(filename, s.liquidConfiguration) + if err != nil { + panic(err) + } + template.Render(writer, data) + } + s.liquidConfiguration = liquid.Configure().IncludeHandler(includeHandler) + return s.liquidConfiguration +} + // GetFrontMatterDefaults implements https://jekyllrb.com/docs/configuration/#front-matter-defaults func (s *Site) GetFrontMatterDefaults(relpath, typename string) (m VariableMap) { for _, entry := range s.config.Defaults { diff --git a/site_config.go b/site_config.go index b985b16..9664df5 100644 --- a/site_config.go +++ b/site_config.go @@ -9,6 +9,7 @@ type SiteConfig struct { Source string Destination string LayoutsDir string `yaml:"layouts_dir"` + IncludesDir string `yaml:"includes_dir"` Collections map[string]VariableMap // Handling Reading