jaspervdj / hakyll

A static website compiler library in Haskell
jaspervdj.be/hakyll
Other
2.67k stars 410 forks source link

body field in for loop loops over the whole html #559

Open diegovdc opened 6 years ago

diegovdc commented 6 years ago

I was playing with the example at templates/post-list.html, and I was trying to print the body of the post, however, it did not only print the body of the post, but the whole html.

This:

<ul>
    $for(posts)$
        <li>
            <a href="$url$">$title$</a> - $date$
        </li>
        $body$
    $endfor$
</ul>

Gets rendered into this:

<ul>  
        <li>
            <a href="./posts/2015-12-07-tu-quoque.html">Tu Quoque</a> - December  7, 2015
        </li>
        <!doctype html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <meta http-equiv="x-ua-compatible" content="ie=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>My Hakyll Blog - Tu Quoque</title>
        <link rel="stylesheet" href="../css/default.css" />
    </head>
    <body>
        <div id="header">
            <div id="logo">
                <a href="../">My Hakyll Blog</a>
            </div>
            <div id="navigation">
                <a href="../">Home</a>
                <a href="../about.html">About</a>
                <a href="../contact.html">Contact</a>
                <a href="../archive.html">Archive</a>
            </div>
        </div>

        <div id="content">
            <h1>Tu Quoque</h1>
            <div class="info">
    Posted on December  7, 2015

        by Julius

</div>
        </div>

        <div id="footer">
            Site proudly generated by
            <a href="http://jaspervdj.be/hakyll">Hakyll</a>
        </div>
    </body>
</html>

        <li>
            <a href="./posts/2015-11-28-carpe-diem.html">Carpe Diem</a> - November 28, 2015
        </li>

... and it goes on

Am I doing something wrong?

dunnl commented 6 years ago

This is the expected behavior. Take a look at this tutorial: https://jaspervdj.be/hakyll/tutorials/05-snapshots-feeds.html

The relevant snippet here is

posts <- recentFirst =<< loadAll "posts/*"
let archiveCtx =
    listField "posts" postCtx (return posts) `mappend`
...

You probably know that listField is going to take each Item it's fed, and within the body of the for loop, apply postCtx to determine the value of the keys. The issue is that by loading the posts, you are actually loading the final compiled content, so that's what $body$ refers to.

As mentioned in the tutorial, you can resolve this problem by taking a Snapshot early on within the post compiler, and replacing load with loadAllSnapshots inside the archive compiler.

silky commented 5 years ago

thanks for the hint @dunnl, but i'm struggling to see how to make this work.

like, how can i define a new field, called content that has the body of the posts in them?

that is, the problem i'm having is as the original poster; that i just want a variable for the $body$ of the blog post. maybe i'm wrong, but the tutorial you show is for saving the rendered template of that post, and then using that as the iterable over which to run the atom generating, or such.

the problem i have is different - i just want to be able to print the blog body in a for loop.

-- edit: turns out it works now, for reasons i don't understand. :shrug:

dunnl commented 5 years ago

@silky I think you will find it is a matter of at what point you take the snapshot. The snippet above is certainly going to give you the "final output" but if you use 'loadAllSnapshots' instead of 'loadAll' you're going to get you what you fed into the snapshot. If you do this early enough you should be able to get to the most raw content.

Final thought: you might also have an issue with what Context you are using. I forget entirely how Hakyll works but I recall this being a sensitive thing. If your context is defined to have two fields called content then one of them takes precedence over the other. Stuff like that. listField takes a Context parameter too so that's one way this stuff can bite you.