How do I get only the title & url? (Need to avoid a dependency cycle)

Skip to first unread message

Sep 28, 2015, 8:21:56 PM9/28/15
to hakyll
I have a box of icons that link to areas of expertise. I use these on /, but I also want to use them on every individual expertise (expertise/*.markdown). To generate them in index.markdown, I need:
      exps <-  loadAll "expertise/*.markdown"

But this will not work when generating "expertise/*.markdown", because it will create a dependency cycle.

How can I include my expertise-list in the expertise/*.markdowns? I only need the title and url of each expertise, so maybe there's a way to make them and not the body?

Here is the relevant code (it's short):
  /index.markdown and expertise/*.markdown:

Any help would be awesome. Right now I generate the icons for /, and just copy the generated src into the expertise template, which is beyond stupid.

Jasper Van der Jeugt

Oct 1, 2015, 6:29:32 AM10/1/15

There are two approaches to do this.

1. Compile the items twice, using different versions [1]. One version is
actually shown on your site, and the other version is just for
extracting the info you need in the actual version.

In this case, however, since you don't need the page body, there is a
much simpler approach:

2. Just get the metadata for all items using `getMatches`/`getMetadata`.
I took the following snippet from the example site generated by

match "posts/*" $ do
route $ setExtension "html"
compile $ pandocCompiler
>>= loadAndApplyTemplate "templates/post.html" postCtx
>>= loadAndApplyTemplate "templates/default.html" postCtx
>>= relativizeUrls

Let's show how you can grab the metadata here:

match "posts/*" $ do
route $ setExtension "html"
compile $ do
posts <- getMatches "posts/*"
metadatas <- mapM getMetadata posts

-- Do something with metadatas here to put it in `postCtx`.

>>= loadAndApplyTemplate "templates/post.html" postCtx
>>= loadAndApplyTemplate "templates/default.html" postCtx
>>= relativizeUrls

This should be easily adapted to your site?


Hope this helps,
> --
> You received this message because you are subscribed to the Google Groups "hakyll" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to
> For more options, visit

Oct 5, 2015, 10:10:54 AM10/5/15
to hakyll,
Thank you!

The second approach seems sound. I have a function for converting every expertise/*.markddown to HTML:

mdToHtml :: String -> Rules ()
mdToHtml t = do

  route $ setExtension "html"
  compile $ pandocCompiler
    >>= loadAndApplyTemplate (fromFilePath $ "templates/" ++ t ++ ".markdown")
                             (defaultContext <> fixAmpField)
    >>= renderPandoc
    >>= loadAndApplyTemplate "templates/default.html" defaultContext
    >>= relativizeUrls

I can get the metadata in here by doing:

  compile $ do
    ms <- getMatches (fromGlob $ t ++ "/*")
    md <- mapM getMetadata ms

... before the pandocCompiler. But I don't understand what I need to do to be able to use:


... in expertise/*.markdown.

I need $expertise$ to be generated with $title$ and $url. I thought I could do something like this (albeit cleaner):

    let ctx = listField t (defaultContext <> fixAmpField)
                          (return ((fromMaybe "" . M.lookup "title") <$> md)
                        <> return ((fromMaybe "" . M.lookup "url")   <$> md))
           <> defaultContext

But that says that it couldn't match [Char] with Hakyll.Core.Item.Item String (on md).

Maybe this is the wrong approach altogether though. I just need $expertise$ so that I can use it like this:

<div class="icon">
<a style="text-decoration: none;" href="$url$">
<img src="/images/$fixAmp(title)$-icon.svg" width="64vmin" class="inactive">
<img src="/images/$fixAmp(title)$-icon-active.svg" width="64vmin" class="active">

... in /templates/expertise-list.markdown.

Any ideas?

Oct 8, 2015, 8:29:26 AM10/8/15
to hakyll,
By the way, I was able to make it work just fine using versions. That's, as you observed, a bit of an overkill though.

Robin Powell

Dec 30, 2020, 12:10:11 AM12/30/20
to hakyll
Sorry to necro an old thread :), but I had some surprise trouble with the first approach and I thought people might find my learnings helpful:
Reply all
Reply to author
0 new messages