diff options
Diffstat (limited to 'web/tutorials/05-snapshots-feeds.markdown')
-rw-r--r-- | web/tutorials/05-snapshots-feeds.markdown | 90 |
1 files changed, 89 insertions, 1 deletions
diff --git a/web/tutorials/05-snapshots-feeds.markdown b/web/tutorials/05-snapshots-feeds.markdown index d113aa2..230a703 100644 --- a/web/tutorials/05-snapshots-feeds.markdown +++ b/web/tutorials/05-snapshots-feeds.markdown @@ -22,7 +22,10 @@ myFeedConfiguration = FeedConfiguration } ``` -Now, we'll create the actual feed. +Simple feed rendering +--------------------- + +Now, let's look at how we actually create a feed. Two functions are available: ```haskell renderAtom :: FeedConfiguration @@ -37,3 +40,88 @@ renderRss :: FeedConfiguration -> [Item String] -> Compiler (Item String) ``` + +As you can see, they have exactly the same signature: we're going to use +`renderAtom` in this tutorial, but it's trivial to change this to an RSS feed. + +```haskell +create ["atom.xml"] $ do + route idRoute + compile $ do + let feedCtx = postCtx `mappend` + constField "description" "This is the post description" + + posts <- take 10 . recentFirst <$> loadAll "posts/*" + renderAtom myFeedConfiguration feedCtx posts +``` + +There we go! We simply take the 10 last posts and pass them to `renderAtom`, +with our configuration and a `Context`. + +It's a bit of a problem that we don't have a description for our posts, and the +Atom/RSS feed renderer requires this. One option is to add a `description: Foo` +header to our all posts. However, the description is the body text as it appears +in most RSS readers, so we would prefer to include the entire content of the +posts here. + +Snapshots +--------- + +This poses a problem: if we just `load` all posts and take their content: we get +the *finished, processed* content. This means all templates have been applied at +that point (including `templates/default.html`). We don't want to include our +entire site with navigation in the RSS feed, but rather just the post HTML. + +Snapshots provide a solution to this problem. They allow you to save an `Item` +at any point during its compilation, so you can `load` it later. Let's apply +this to our concrete problem. + +```haskell +match "posts/*" $ do + route $ setExtension "html" + compile $ pandocCompiler + >>= loadAndApplyTemplate "templates/post.html" postCtx + >>= loadAndApplyTemplate "templates/default.html" postCtx + >>= relativizeUrls +``` + +now becomes: + +```haskell +match "posts/*" $ do + route $ setExtension "html" + compile $ pandocCompiler + >>= loadAndApplyTemplate "templates/post.html" postCtx + >>= saveSnapshot "content" + >>= loadAndApplyTemplate "templates/default.html" postCtx + >>= relativizeUrls +``` + +The `saveSnapshot` function is really simple: it takes an item and returns the +same item, after saving it. This return value makes it easier to use +`saveSnapshot` in a chain of compilers as we did in the above example, but you +can discard it if you want. + +```haskell +type Snapshot = String + +saveSnapshot :: (Typeable a, Binary a) + => Snapshot -> Item a -> Compiler (Item a) +``` + +Including the post body +----------------------- + +With this modification, we can update our Atom code. Instead of loading the +compiled posts, we just load their content (i.e. the snapshot we just took). + +We update the `Context` to map `$description$` to the post body, and we're done! + +```haskell +create ["atom.xml"] $ do + route idRoute + compile $ do + let feedCtx = postCtx `mappend` bodyField "description" + posts <- take 10 . recentFirst <$> loadAllSnapshots "posts/*" "content" + renderAtom myFeedConfiguration feedCtx posts +``` |