diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,14 @@
 # ChangeLog for yesod-core
 
+## 1.6.18
+
+* Add functions for setting description and OG meta [#1663](https://github.com/yesodweb/yesod/pull/1663)
+
+* Use `DeriveLift` to implement the `Lift` instances for `ResourceTree`,
+  `Resource`, `Piece`, and `Dispatch`. Among other benefits, this provides
+  implementations of `liftTyped` on `template-haskell-2.16` (GHC 8.10) or
+  later. [#1664](https://github.com/yesodweb/yesod/pull/1664)
+
 ## 1.6.17.3
 
 * Support for `unliftio-core` 0.2
diff --git a/src/Yesod/Core/Widget.hs b/src/Yesod/Core/Widget.hs
--- a/src/Yesod/Core/Widget.hs
+++ b/src/Yesod/Core/Widget.hs
@@ -8,6 +8,8 @@
 {-# LANGUAGE MultiParamTypeClasses #-}
 {-# LANGUAGE TypeSynonymInstances #-}
 {-# LANGUAGE UndecidableInstances #-}
+{-# LANGUAGE QuasiQuotes #-}
+
 -- | Widgets combine HTML with JS and CSS dependencies with a unique identifier
 -- generator, allowing you to create truly modular HTML components.
 module Yesod.Core.Widget
@@ -29,6 +31,10 @@
       -- ** Head of page
     , setTitle
     , setTitleI
+    , setDescription
+    , setDescriptionI
+    , setOGType
+    , setOGImage
       -- ** CSS
     , addStylesheet
     , addStylesheetAttrs
@@ -160,17 +166,82 @@
 instance ToWidgetHead site Html where
     toWidgetHead = toWidgetHead . const
 
--- | Set the page title. Calling 'setTitle' multiple times overrides previously
--- set values.
+-- | Set the page title.
+--
+-- Calling @setTitle@ or @setTitleI@ multiple times overrides previously set
+-- values.
+--
+-- SEO Notes:
+--
+--    * Title tags are the second most important on-page factor for SEO, after
+--      content
+--    * Every page should have a unique title tag
+--    * Start your title tag with your main targeted keyword
+--    * Don't stuff your keywords
+--    * Google typically shows 55-64 characters, so aim to keep your title
+--      length under 60 characters
 setTitle :: MonadWidget m => Html -> m ()
 setTitle x = tell $ GWData mempty (Last $ Just $ Title x) mempty mempty mempty mempty mempty
 
--- | Set the page title. Calling 'setTitle' multiple times overrides previously
--- set values.
+-- | Set the localised page title.
+--
+-- n.b. See comments for @setTitle@
 setTitleI :: (MonadWidget m, RenderMessage (HandlerSite m) msg) => msg -> m ()
 setTitleI msg = do
     mr <- getMessageRender
     setTitle $ toHtml $ mr msg
+
+-- | Add description meta tag to the head of the page
+--
+-- Google does not use the description tag as a ranking signal, but the
+-- contents of this tag will likely affect your click-through rate since it
+-- shows up in search results.
+--
+-- The average length of the description shown in Google's search results is
+-- about 160 characters on desktop, and about 130 characters on mobile, at time
+-- of writing.
+--
+-- Source: https://www.advancedwebranking.com/blog/meta-tags-important-in-seo/
+--
+-- @since 1.6.18
+setDescription :: MonadWidget m => Text -> m ()
+setDescription description =
+    toWidgetHead $ [hamlet|<meta name=description content=#{description}>|]
+
+-- | Add translated description meta tag to the head of the page
+--
+-- n.b. See comments for @setDescription@.
+--
+-- @since 1.6.18
+setDescriptionI
+  :: (MonadWidget m, RenderMessage (HandlerSite m) msg)
+  => msg -> m ()
+setDescriptionI msg = do
+    mr <- getMessageRender
+    toWidgetHead $ [hamlet|<meta name=description content=#{mr msg}>|]
+
+-- | Add OpenGraph type meta tag to the head of the page
+--
+-- See all available OG types here: https://ogp.me/#types
+--
+-- @since 1.6.18
+setOGType :: MonadWidget m => Text -> m ()
+setOGType a = toWidgetHead $ [hamlet|<meta name="og:type" content=#{a}>|]
+
+-- | Add OpenGraph image meta tag to the head of the page
+--
+-- Best practices:
+--
+--    * Use custom images for shareable pages, e.g., homepage, articles, etc.
+--    * Use your logo or any other branded image for the rest of your pages.
+--    * Use images with a 1.91:1 ratio and minimum recommended dimensions of
+--      1200x630 for optimal clarity across all devices.
+--
+-- Source: https://ahrefs.com/blog/open-graph-meta-tags/
+--
+-- @since 1.6.18
+setOGImage :: MonadWidget m => Text -> m ()
+setOGImage a = toWidgetHead $ [hamlet|<meta name="og:image" content=#{a}>|]
 
 -- | Link to the specified local stylesheet.
 addStylesheet :: MonadWidget m => Route (HandlerSite m) -> m ()
diff --git a/src/Yesod/Routes/TH/Types.hs b/src/Yesod/Routes/TH/Types.hs
--- a/src/Yesod/Routes/TH/Types.hs
+++ b/src/Yesod/Routes/TH/Types.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE DeriveFunctor #-}
-{-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE DeriveLift #-}
 -- | Warning! This module is considered internal and may have breaking changes
 module Yesod.Routes.TH.Types
     ( -- * Data types
@@ -21,7 +21,7 @@
 data ResourceTree typ
     = ResourceLeaf (Resource typ)
     | ResourceParent String CheckOverlap [Piece typ] [ResourceTree typ]
-    deriving (Show, Functor)
+    deriving (Lift, Show, Functor)
 
 resourceTreePieces :: ResourceTree typ -> [Piece typ]
 resourceTreePieces (ResourceLeaf r) = resourcePieces r
@@ -31,10 +31,6 @@
 resourceTreeName (ResourceLeaf r) = resourceName r
 resourceTreeName (ResourceParent x _ _ _) = x
 
-instance Lift t => Lift (ResourceTree t) where
-    lift (ResourceLeaf r) = [|ResourceLeaf $(lift r)|]
-    lift (ResourceParent a b c d) = [|ResourceParent $(lift a) $(lift b) $(lift c) $(lift d)|]
-
 data Resource typ = Resource
     { resourceName :: String
     , resourcePieces :: [Piece typ]
@@ -42,24 +38,17 @@
     , resourceAttrs :: [String]
     , resourceCheck :: CheckOverlap
     }
-    deriving (Show, Functor)
+    deriving (Lift, Show, Functor)
 
 type CheckOverlap = Bool
 
-instance Lift t => Lift (Resource t) where
-    lift (Resource a b c d e) = [|Resource a b c d e|]
-
 data Piece typ = Static String | Dynamic typ
-    deriving Show
+    deriving (Lift, Show)
 
 instance Functor Piece where
     fmap _ (Static s)  = Static s
     fmap f (Dynamic t) = Dynamic (f t)
 
-instance Lift t => Lift (Piece t) where
-    lift (Static s)  = [|Static  $(lift s)|]
-    lift (Dynamic t) = [|Dynamic $(lift t)|]
-
 data Dispatch typ =
     Methods
         { methodsMulti :: Maybe typ -- ^ type of the multi piece at the end
@@ -69,16 +58,11 @@
         { subsiteType :: typ
         , subsiteFunc :: String
         }
-    deriving Show
+    deriving (Lift, Show)
 
 instance Functor Dispatch where
     fmap f (Methods a b) = Methods (fmap f a) b
     fmap f (Subsite a b) = Subsite (f a) b
-
-instance Lift t => Lift (Dispatch t) where
-    lift (Methods Nothing b) = [|Methods Nothing $(lift b)|]
-    lift (Methods (Just t) b) = [|Methods (Just $(lift t)) $(lift b)|]
-    lift (Subsite t b) = [|Subsite $(lift t) $(lift b)|]
 
 resourceMulti :: Resource typ -> Maybe typ
 resourceMulti Resource { resourceDispatch = Methods (Just t) _ } = Just t
diff --git a/yesod-core.cabal b/yesod-core.cabal
--- a/yesod-core.cabal
+++ b/yesod-core.cabal
@@ -1,5 +1,5 @@
 name:            yesod-core
-version:         1.6.17.3
+version:         1.6.18
 license:         MIT
 license-file:    LICENSE
 author:          Michael Snoyman <michael@snoyman.com>
