summaryrefslogtreecommitdiff
path: root/web/tutorials
diff options
context:
space:
mode:
Diffstat (limited to 'web/tutorials')
-rw-r--r--web/tutorials/05-snapshots-feeds.markdown90
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
+```