Jekyll - generate a post twice; once with layout, and once as raw html

Hello Jekyll Community! First poster here.

I want to make a change to my blog so that on the front page, each post can be loaded into a dialog-like element using .fetch(), but you can still ‘Read more’ to go to the full-page blog post.

The way I envision this working is that posts would be generated to the output as usual but also a second, raw HTML copy could be generated to another directory (like /raw/)

I’m hoping there is either a vanilla Jekyll feature to do this through config, or else a known plugin.

My backup plan is to either write a generator (I’m not a Ruby programmer but I can try), or migrate to 11ty.

I’ve looked at this thread: How can I display a raw HTML or MD file without Jekyll processing it? So that a visitor can see the raw HTML contents? - Help - Jekyll Talk (jekyllrb.com) but that’s not quite what I want, as I’d like another file-per-post rather than embedding a single post into my content.

Thanks in advance for your thoughts and ideas!

(Crossposted to StackOverflow)

Hello @stegriff
FYI, there is no vanilla Jekyll feature that lets you do this.

However, out of curiosity, is your source-repo private?
If not, why not just provide a link to your public repository somewhere on the rendered page?


Update:

Oh! I think I misinterpreted your use-case on the first read…
So, scratch that part about link to public repo.

You’ll definitely need a generator plugin for this. Best you write one yourselves.
You’d need to first subclass Jekyll::Document and override the method :place_in_layout? to always return false. Then initialize your generated post(s) as (an) instance(s) of the subclass.
Don’t forget to assign a new URL to your generated post(s).

1 Like

Thanks very much for the pointers on writing the generator! I will weigh this up against migrating to something I’m more familiar with extending.

I’ll hang around in case anyone else has an idea or plugin recommendation…

Are your posts heavy in size? I am guessing not.

A post will be mostly text I think. And if it is heavy in images, you can lazy load those when they are scrolled into view.

My suggestion is load the summary and the long content all on one page. With display: none in css to hide the long content

Then use JS to make the visible invisible and vice versa.


What is the intention? I would rather load the entire post without read more button. And have a list of posts with a description for each. Jekyll does that well and uses the excerpt attribute to make that content.

Without a plugin to make 2 files for every post…

Another approach would be to make an api file which contains expanded content for all posts

So each post will just show the heading and post.excerpt

And when you click the Read Mlre button, you can request posts.json and then get the post content you need and display it.

You can also cache that request to avoid reloading each time.

1 Like

Thanks for the suggestion. I don’t want to load all post content as I have over 200 posts and many do contain images, so this would be a massive hit :smile:

Sorry, I could have been clearer about this.

I want to rework my site at Blog Index - SteGriff so that it is more like Kicks Condor

I’m going to start putting “micro” content on there – tweet-length blog posts, which just appears in the stream, as well as longer posts which appear in the stream as an excerpt and can be maximised.

Yes, good idea, I have also considered this and wasn’t sure how the implementation would work. Thank you very much for sharing your code snippet. :smiley:

1 Like

If all you want is a page that summarizes all posts using titles and excerpts, then no need to go and duplicate posts.

The standard jekyll blog set up does this.

See the Posts list on the homepage of this demo site of mine and check the code to see how that is done.

No need for Read more. It is clear from the UI that clicking on the title of a post preview will take you to another page that has the whole post.


Also putting your entire posts collection in a single JSON file might not be as big as you think as it’s all data and no html. And images will not take up space as images because they are just URLs.

I like to think of blog sites as having two unique displays. One is the type where you see the list of posts, and if you are interested in one, you select it, and the post expands in-line. Those sites are often painful to use, because it is hard to share a link if you never leave the page, and it can be clunky to use.

The other type, which is the more common, and what I think you are asking for is one where you see the list of posts (one web page) and when you select the post’s link, you get to read the post (another web page).

I think you are looking for the latter, and if that is the case you do not have to create some raw version of a file just to see a bit of text from the post. From what I am reading, this is your request:

  1. You want a web page that lists your blog posts
  2. In that blog post list, you want to display a preview of some text in the post, which we refer to as an excerpt
  3. The excerpt could contain some code or html formatting, so you want to remove all traces of that (hence the “raw” text request)
  4. When someone selects the blog post from the list, a new blog page opens up and displays the blog as you would expect

Is that correct? If so, here is how to do it…

Step 1: Set up your _config.yml file

In your _config.yml file, add the following line wherever you like:

excerpt_separator: <!--more-->

If you also want to use excerpts in pages (ot just posts), you can add this line as well:

page_excerpts: true

If you want to get the first sentence in a post, add this to your _config.yml instead of the text:

excerpt_separator: .

Finally, if you omit the excerpt_separator item from your _config.yml file altogether, then Jekyll will default to getting the first paragraph. Most people like to use the <!--more--> option because they have control over what the reader will see.

Aside: What is this <!--more--> business?

Your Jekyll website generates html pages. HTML is essentially a programming language and as with all programming languages, developers want to write comments in their code. Comments are things the software developer can write in HTML without them displaying on the web browser. To write a comment in HTML, you type <!-- whatever text you want -->.

At some point in time, people realized their websites got more traffic by displaying a little excerpt of an article (it also provided a nice little search engine boost). Unfortunately, HTML does not provide that functionality out of the box. There is no way to say “this is a blog post and stop displaying text here.”.

By using the ability to add comments in HTML, someone (I do not know who), came up with using what some call the “more tag”. You simply type <!--more--> anywhere in your blog post, and the website generator (Jekyll, Wordpress, etc), can do something with it.

What that means is <!--more--> is really just a comment you can type in a web page, but it is widely accepted that it is a way to define an excerpt for a blog post. If, one day, you move from Jekyll to another site generator, there is a very good chance it is supported and therefore your posts are likely more portable. You mileage will vary, as they say :slight_smile:

Step 2: Restart Jekyll

If you were running Jekyll while modifying the _config.yml file, do not forget to stop and restart because even if you use the --livereload option, the _config.yml file requires a restart.

Step 3: Create (or update) at least one blog post

If this is the first time you are working with the site, create at least one post. If you have posts on your site already, update them to include our new <!--more--> feature, like this:

File: /_posts/2021-11-09-pumpkin-cheesecake-recipe.markdown

---
layout: post
date: 2021-11-09 16:12:05 -0800
title: "Pumpkin cheesecake recipe"
---
Ahhh, the fall! A time to dust off those deep warming aromatic spices. Today, I am going to share my New York-style cheesecake recipe, but with a twist. We are going to use <strong>freshly roasted pumpkin</strong>, allspice, and some cinnamon. <!--more-->Your house will smell great for days, and you will be eager for a workout!

Here are the ingredients:
Rest of the blog post...

If you are running Jekyll, you can go to the post and it will look something like this:

Notice how I put some HTML formatting in the post, using the <strong> html tag? We want the text to format properly when viewing the post. However, we want to remove that when we display the excerpt to show it as “raw” text as you requested. I will show you how to address that in the next step.

Step 4: Create the blog list

You can create a list of blog posts wherever you want so that I will provide a basic example here.

In the root folder of your site, create a file and call it myposts.html.

File: /myposts.html

---
layout: default
---
<h2>Blog posts</h2>
{%- assign posts = site.posts -%}
{%- for post in posts -%}
    <a href="{{- post.url | relative_url -}}">{{ post.title }}</a>
    <p>
    {% comment %} Display the post's excerpt, remove html, remove leading or trailing white space {% endcomment %}
    {%- if post.excerpt -%}
        {{ post.excerpt | strip_html | lstrip | rstrip }}    
    {%- endif -%}
    <p>
{%- endfor -%}

That code will build the html page that displays the list of posts, along with the excerpt. While it may not be completely necessary, the code to display the excerpt is located within an if block, so if there is no excerpt to display, we just skip attempting to display it.

I am using three Liquid filters on the excerpt before it displays:

strip_html removes any html, such as that <strong> tag, giving you the “raw text” you were asking for.

lstrip and rstrip removes any leading or trailing spaces, which commonly occur in blog posts. You can add more filters if you see any other discrepencies on your site.

This is what the list of blog posts will look like (well, blog post, singular in my example):

Note two important things here:

  1. The words “freshly roasted pumpkin” display as regular (raw) text. The text is not bold as it is in the post, nor does the <strong> tag appear.
  2. The last sentence with the text “Your house will smell great for days, and you will be eager for a workout!” does not display. That is because you placed the <!-more-> text just prior to writing that sentence

Reading

You can read more about post excerpts in the official Jekyll documentation. Note that you can do one-off excerpts at the post level, but I would avoid that if possible since it will make your code more complicated.

As I mentioned ealier, you can also use page excerpts. Here is some additional reading on how to set that up:

Liquid filters can be used to modify text. My little strip_html option is an excellent use case for removing code. However, there are many more filters. Here are the Jekyll docs for the filters:

In my experience, Jekyll supports most Liquid filters, so if you have any more requirements to make the text look “raw” see if you can find what you need in the official Shopify Liquid documentation here:

Hope this helps!

1 Like

I think this might have to be

if post.excerpt and post.excerpt != ''

In general, if an attribute is set, then it passes the first check. But it might be an empty string.

So I used that for say page.description

I don’t know how the excerpt works though because it is set dynamically by Jekyll and not explicitly in the frontmatter

though I suppose you could always add it if you want

---
excerpt: My excerpt.
---

My excerpt. And the rest of the body.

In two paragraphs.

Jekyll supports per-post excerpt separators. It looks like this:

---
excerpt_separator: <!--more-->
---

I don’t recommend this method, because it would be hard to manage.