Quick tip: How to capture and replace newlines in liquid for Jekyll/GitHub Pages
Tags: jekyll, github, markdown
Published: 2020-12-17 12:34:09

---
title: Quick tip: How to capture and replace newlines in liquid for Jekyll/GitHub Pages
published: true
description: How to capture and replace newlines newlines in Markdown/Liquid
tags: jekyll, github, markdown
---

As part of the re-write of [The Developer Advocacy Handbook](https://developer-advocacy.com) I needed to have `blockquotes` with different classes. 

![Fact display in the book](https://dev-to-uploads.s3.amazonaws.com/i/oyh2r2vrpmsnrds2qz65.png)

With GitHub Pages markdown you can do that using the > notation:

``` markdown
> **Fact:** There are no bad students or a bad audience --
only bad workshops and talks. Your mood, dedication and
enthusiasm do become those of the audience -- 
if you are not happy, they won\'t be happy. 
```

The problem was that I couldn't add CSS classes to the `blockquote` elements so I can show them in different styles. I wanted four of them: example, fact, warning and tip. 

The good news is that even without any styling using the `strong` name should make it obvious. But as there is no text content selector in CSS I couldn't rely on that to change the `blockquote` element. 

## First solution: JavaScript

The first thing I thought was to use JavaScript to apply the classes, which is pretty straight forward:

``` Javascript
let bqs = document.querySelectorAll('blockquote');
  bqs.forEach(b => {
  b.className = b.
    querySelector('strong').
      innerText.
        toLowerCase().
          replace(':','');
});
```
This, however, felt dirty and I wanted to use the system itself to do that task. 

## Moving to liquid

So I wrote a liquid include to convert the HTML before rendering. In my layout template, this works by replacing the `{{ content }}` with `{% include blockquotes.html html=content %}`.

In the `blockquotes.html`, I thought it'd be easy to do a search and replace. Alas, there is the issue that liquid only does string replacement and doesn't know any regular expressions. 

The HTML generated from the markdown has a linebreak in it:

``` HTML
<blockquote>
  <p><strong>Fact:</strong> There are no bad students … </p>
</blockquote>
```

This is where it didn't get fun. The replace filter doesn't allow you to concatenate strings and doesn't know the concept of `\n`. So, I tried to use `newline_to_br` together with `strip_newlines` and then replace the `<br />` but it was messy.

Turns out, the main trick was to capture a newline in liquid and assemble the string to replace using that one.

``` 
{% capture newline %}
{% endcapture %}
{% capture tip %}<blockquote>{{newline}}  <p><strong>Tip:</strong>{% endcapture%}
{% capture example %}<blockquote>{{newline}}  <p><strong>Example:</strong>{% endcapture%}
{% capture warning %}<blockquote>{{newline}}  <p><strong>Warning:</strong>{% endcapture%}
{% capture fact %}<blockquote>{{newline}}  <p><strong>Fact:</strong>{% endcapture%}

{% assign newhtml = include.html | 
  replace: tip, '<blockquote class="tip"><p><strong>Tip:</strong>' |
  replace: example, '<blockquote class="example"><p><strong>Example:</strong>' |
  replace: warning, '<blockquote class="warning"><p><strong>Warning:</strong>' |
  replace: fact, '<blockquote class="fact"><p><strong>Fact:</strong>' 
%}
{{ newhtml }}
```

This works fine. Seems superfluous, but it is a way. It might be that there is a much simpler way as I am new to this world, having used PHP before the build the old version of the book. Got a better option? Tell me :)