diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,10 @@
 # Changelog for Shakebook
 
+## (v0.3.1.0)
+
+* Add `withContent` lens.
+* Add lifted version of `flattenMeta` from `Slick.Pandoc`.
+
 ## (v0.3.0.0)
 
 * Upgrade to [shake-plus](https://hackage.haskell.org/package/shake-plus) v0.1.3.0
diff --git a/shakebook.cabal b/shakebook.cabal
--- a/shakebook.cabal
+++ b/shakebook.cabal
@@ -4,10 +4,10 @@
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: f81a7404b32b789b39558cf48d2e50ddc9bd75801d00397bc72ecafb45ddce2d
+-- hash: 57aeb1237df591d9d22b7ea05fc33ead1a5892537f1cc077b6f2df5853ada8d7
 
 name:           shakebook
-version:        0.3.0.1
+version:        0.3.1.0
 synopsis:       Shake-based technical documentation generator; HTML & PDF
 description:    Shakebook is a documentation generator aimed at covering all the bases for mathematical, technical and scientific diagrams and typesetting. Shakebook provides combinators for taking markdown files and combining them into documents, but allowing the user to control how. Shakebook provides general combinators for templating single pages, cofree comonads for representing tables of contents, and zipper comonads for representing pagers.
 category:       Web
diff --git a/src/Shakebook/Conventions.hs b/src/Shakebook/Conventions.hs
--- a/src/Shakebook/Conventions.hs
+++ b/src/Shakebook/Conventions.hs
@@ -3,8 +3,7 @@
 
 module Shakebook.Conventions (
   -- * Lenses
-  viewContent
-, viewPostTime
+  viewPostTime
 , viewPostTimeRaw
 , viewSrcPath
 , viewTags
@@ -69,10 +68,6 @@
 import           Shakebook.Data
 import           Text.Pandoc.Highlighting
 
-
--- | View the "content" field of a JSON Value.
-viewContent :: Value -> Text
-viewContent = view (key "content" . _String)
 
 -- | View the "date" field of a JSON Value as a UTCTime.
 viewPostTime :: Value -> UTCTime
diff --git a/src/Shakebook/Data.hs b/src/Shakebook/Data.hs
--- a/src/Shakebook/Data.hs
+++ b/src/Shakebook/Data.hs
@@ -13,7 +13,6 @@
 import           RIO                        hiding (Lens', lens, view)
 import qualified RIO.Text                   as T
 import           Shakebook.Pandoc
-import           Slick.Pandoc
 import           Text.Pandoc
 import           Within
 
@@ -55,6 +54,14 @@
 instance HasLogFunc ShakebookEnv where
   logFuncL = lens logFunc undefined
 
+-- | View the "content" field of a JSON value.
+viewContent :: Value -> Text
+viewContent = view (key "content" . _String)
+
+-- | Add "content" field from input Text.
+withContent :: Text -> Value -> Value
+withContent = withStringField "content"
+
 -- | View the "src-path" field of a JSON Value.
 viewSrcPath :: Value -> Text
 viewSrcPath = view (key "src-path" . _String)
@@ -114,8 +121,8 @@
 generateSupposedUrl :: MonadThrow m => Path Rel File -> m (Path Abs File)
 generateSupposedUrl srcPath = (leadingSlash </>) <$> withHtmlExtension srcPath
 
-enrichSupposedUrl :: (MonadReader r m, HasSbConfig r, MonadThrow m) => Value -> m Value
-enrichSupposedUrl v = view sbConfigL >>= \SbConfig{..} -> do
+enrichSupposedUrl :: MonadThrow m => Value -> m Value
+enrichSupposedUrl v = do
   x <- parseRelFile $ T.unpack $ viewSrcPath v
   y <- generateSupposedUrl x
   return $ withUrl (T.pack . toFilePath $ y) v
@@ -129,14 +136,14 @@
                   -> m Value
 loadMarkdownAsJSON srcPath = view sbConfigL >>= \SbConfig{..} -> do
   pdoc@(Pandoc meta _) <- readMDFileWithin sbMdRead srcPath
-  meta' <- liftAction $ flattenMeta (writeHtml5String sbHTWrite) meta
+  meta' <- flattenMeta (writeHtml5String sbHTWrite) meta
   needPandocImagesIn sbOutDir pdoc
   outText <- runPandocA $ writeHtml5String sbHTWrite pdoc
-  let docData = meta' & _Object . at "content" ?~ String outText
-  supposedUrl <- liftIO $ (leadingSlash </>) <$> withHtmlExtension (extract srcPath)
+  supposedUrl <- generateSupposedUrl (extract srcPath)
   return $ sbGlobalApply
+         . withContent outText
          . withSrcPath (T.pack . toFilePath $ extract srcPath)
-         . withUrl (T.pack . toFilePath $ supposedUrl) $ docData
+         . withUrl (T.pack . toFilePath $ supposedUrl) $ meta'
 
 immediateShoots :: Cofree [] a -> [a]
 immediateShoots(_ :< xs) = extract <$> xs
diff --git a/src/Shakebook/Pandoc.hs b/src/Shakebook/Pandoc.hs
--- a/src/Shakebook/Pandoc.hs
+++ b/src/Shakebook/Pandoc.hs
@@ -9,14 +9,17 @@
 , progressivelyDemoteHeaders
 , replaceUnusableImages
 , prefixAllImages
+, flattenMeta
 ) where
 
 import Control.Comonad.Cofree
+import Data.Aeson
 import Development.Shake.Plus
 import RIO
 import qualified RIO.ByteString.Lazy as LBS
 import qualified RIO.Text as T
 import Path
+import qualified Slick.Pandoc
 import Text.Pandoc.Class
 import Text.Pandoc.Definition
 import Text.Pandoc.Readers
@@ -89,3 +92,6 @@
 prefixAllImages dir = walk handleImages where
   handleImages (Image attr ins (src, txt)) = Image attr ins ((T.pack $ toFilePath dir) <> "/" <> src, txt)
   handleImages x = x
+
+flattenMeta :: MonadAction m => (Pandoc -> PandocIO Text) -> Meta -> m Value
+flattenMeta opts meta = liftAction $ Slick.Pandoc.flattenMeta opts meta
