Franklin.jl Dynamically Loading and Suppressing Pages

There are two separate but slightly related problems. First, I have a directory called posts containing markdown files to be displayed. I would like to keep some of these markdown files in the folder, but suppress them during deployment. Now there is the ignore list in config.md, but I do not wish to add all of these files to the array as it gets cumbersome. Preferably, I could assign a local variable - say publish=true - to each page and let Franklin ignore these pages during the build process.

I attempted an alternative solution which is to move the posts folder to _assets but stumbled into my second issue. Since posts is now in _assets, there are no issues with hiding pages, but pages that should be published end up getting suppressed as well. Given a markdown file in some location possibly outside of Franklin’s purview, how can I tell Franklin that I would like to create a web link at /path with the contents of the file displayed there?

am I interpreting your question correctly saying that you’d ideally like a draft mode where a page.md with

+++
draft = true
+++

# This is a post currently being written but not yet for deployment

Partial content...

would show locally when you run serve but not at deployment time? If so, I could see this being useful so kindly open an issue and I’ll try to get that in.

For your second question, whatever is in _assets is basically copied “as is” by Franklin without any attempt at conversion. I don’t think it’s a good path in your case (you could run a hfun function that would read your md files, check if they have the draft or publish page variable and generate the output but might as well have that in Franklin then)

2 Likes

you could run a hfun function that would read your md files, check if they have the draft or publish page variable and generate the output but might as well have that in Franklin then

So if I were to do this, I’m still not sure how to go about it. If _posts is a directory hidden from Franklin, I imagine I can do something like this:

function hfun_list_posts()
root = Franklin.PATHS[:folder]
pages = String[]
cd(root) do
    foreach(((r, dirs, fs),) ->  if (length(dirs) == 0) append!(pages, joinpath.(r, fs)) end, walkdir("./_posts")
end

filter!(x->!pagevar(x, "draft", false), pages)

generate_pages(pages)

The part that is unclear still is generating the output page. For example, how would I specify associating _posts/post1.md to path root/posts/post1?

I’ll look into adding the draft stuff shortly.

To answer your question specifically, you could use Franklin.form_output_path(base, relative, :md) where base would just be Franklin.PATHS[:folder] and relative would be joinpath("_posts", "one_of_your_post.md")

I don’t recommend going this road though as it uses internal stuff and it’s likely you’ll get papercuts. You have two alternatives (1) you wait until I’ve gotten this draft thing in somewhat cleanly or (2) you use the on_write functionality; this is a on_write = (a, b) -> fun(a, b) argument which can be passed to serve and optimize which takes the fully generated HTML (argument a) and the dictionary of local variables (argument b) and lets you apply some logic. It’s called as the last step in converting and writing a single .md file.

This should work:

# definition of removedraft so you can later call
# optimize(...; on_write = removedraft)

function removedraft(_, locvars)
  # you actually don't care about the first argument (full html)
  # all you want is to remove the output page if 
  #  (0) we're in the final loop (deployment / build stage)
  #  (1) it exists
  #  (2) it corresponds to a draft page

  Franklin.FD_ENV[:FINAL_PASS] || return
  relative_path = locvars["fd_rpath"].first   # e.g. _posts/abc.md
  relative_url = locvars["fd_url"].first      # e.g. /posts/abc/index.html
  
  output_path = joinpath("__site", split(relative_url, '/')...)
  isfile(output_path) || return

  haskey(locvars, "draft") || return
  locvars["draft"].first || return

  # now we have a file that exists, and that is a draft, nuke it
  println("removing $output_path")
  rm(output_path)
  return
end

Running serve(...) normally on your local machine will show everything, and on your deployment script you could put this removedraft function and pass it to the optimize(...; on_write=removedraft) call.

in case others find this, a small patch (0.10.89) added the draft mode:

+++
draft = true
+++

# Some header

Your partial content that you want to see locally but not when deployed.
1 Like