summaryrefslogtreecommitdiff
path: root/src/Hakyll/Web/Redirect.hs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Hakyll/Web/Redirect.hs')
-rw-r--r--src/Hakyll/Web/Redirect.hs82
1 files changed, 82 insertions, 0 deletions
diff --git a/src/Hakyll/Web/Redirect.hs b/src/Hakyll/Web/Redirect.hs
new file mode 100644
index 0000000..ead56fe
--- /dev/null
+++ b/src/Hakyll/Web/Redirect.hs
@@ -0,0 +1,82 @@
+-- | Module used for generating HTML redirect pages. This allows renaming pages
+-- to avoid breaking existing links without requiring server-side support for
+-- formal 301 Redirect error codes
+module Hakyll.Web.Redirect
+ ( Redirect (..)
+ , createRedirects
+ ) where
+
+import Control.Applicative ((<$>))
+import Control.Monad (forM_)
+import Data.Binary (Binary (..))
+import Hakyll.Core.Compiler
+import Hakyll.Core.Identifier
+import Hakyll.Core.Routes
+import Hakyll.Core.Rules
+import Hakyll.Core.Writable (Writable (..))
+
+-- | This function exposes a higher-level interface compared to using the
+-- 'Redirect' type manually.
+--
+-- This creates, using a database mapping broken URLs to working ones, HTML
+-- files which will do HTML META tag redirect pages (since, as a static site, we
+-- can't use web-server-level 301 redirects, and using JS is gross).
+--
+-- This is useful for sending people using old URLs to renamed versions, dealing
+-- with common typos etc, and will increase site traffic. Such broken URLs can
+-- be found by looking at server logs or by using Google Webmaster Tools.
+-- Broken URLs must be valid Haskell strings, non-URL-escaped valid POSIX
+-- filenames, and relative links, since they will be defined in a @hakyll.hs@
+-- and during generation, written to disk with the filename corresponding to the
+-- broken URLs. (Target URLs can be absolute or relative, but should be
+-- URL-escaped.) So broken incoming links like <http://www.gwern.net/foo/> which
+-- should be <http://www.gwern.net/foobar> cannot be fixed (since you cannot
+-- create a HTML file named @"foo/"@ on disk, as that would be a directory).
+--
+-- An example of a valid association list would be:
+--
+-- > brokenLinks = [("/Black-market archive", "/Black-market%20archives")]
+--
+-- In which case the functionality can then be used in `main` with a line like:
+--
+-- > createRedirects brokenLinks
+--
+-- The on-disk files can then be uploaded with HTML mimetypes
+-- (either explicitly by generating and uploading them separately, by
+-- auto-detection of the filetype, or an upload tool defaulting to HTML
+-- mimetype, such as calling @s3cmd@ with @--default-mime-type=text/html@) and
+-- will redirect browsers and search engines going to the old/broken URLs.
+--
+-- See also <https://groups.google.com/d/msg/hakyll/sWc6zxfh-uM/fUpZPsFNDgAJ>.
+createRedirects :: [(Identifier, String)] -> Rules ()
+createRedirects redirects =
+ forM_ redirects $ \(ident, to) ->
+ create [ident] $ do
+ route idRoute
+ compile $ makeItem $! Redirect to
+
+-- | This datatype can be used directly if you want a lower-level interface to
+-- generate redirects. For example, if you want to redirect @foo.html@ to
+-- @bar.jpg@, you can use:
+--
+-- > create ["foo.html"] $ do
+-- > route idRoute
+-- > compile $ makeItem $ Redirect "bar.jpg"
+data Redirect = Redirect
+ { redirectTo :: String
+ } deriving (Eq, Ord, Show)
+
+instance Binary Redirect where
+ put (Redirect to) = put to
+ get = Redirect <$> get
+
+instance Writable Redirect where
+ write path = write path . fmap redirectToHtml
+
+redirectToHtml :: Redirect -> String
+redirectToHtml (Redirect working) =
+ "<!DOCTYPE html><html><head><meta charset=\"utf-8\"/><meta name=\"generator\" content=\"hakyll\"/>" ++
+ "<meta http-equiv=\"refresh\" content=\"0; url=" ++ working ++
+ "\"><link rel=\"canonical\" href=\"" ++ working ++
+ "\"><title>Permanent Redirect</title></head><body><p>The page has moved to: <a href=\"" ++ working ++
+ "\">this page</a></p></body></html>"