Prevent Markdownify to strip first p tags

How would I prevent that Markdownify is stripping the first paragraph tag.?

You currently cannot:

@bep mmm.

Is there any workaround at the moment? Really need this feature for a client website. The website is launching this month.

I’m willing to sponsor the issue with a small amount

If this is a relatively new problem, could you not use an older version of Hugo that was built before it was introduced?

It is as old as markdownify itself. The current workaround is, of course, to wrap the result in p tags manually, if that is what you want. But I don’t remember the details of that issue.

Wrapping p tags manually works if you have only one paragraph in you markdown content. But when you have 2 or more p tags you get invalid html content.

There seem to be some discussion about what the best solution to this is. Cast your vote here (bottom of issue):

Just discovered this invented-here behavior of stripping <p> tags when the content is only one line. I have this line in my single.html template:

{{ .Content | markdownify }}

But when the content of an item has only one line, there is no <p> tag added, and the style of the single template breaks.

On closer inspection, I see that I am also guilty of using the no-paragraph markdownify, earlier in the same template:

<h1>{{ .Title | markdownify }}</h1>

Therefore, I’m voting for @fritzmg suggestion, moving the special paragraph-ignoring behavior-- this is an exception to the syntax published at --to a new helper that strips paragraphs. My new template would look like this:

<h1>{{ .Title | markdownify | inline }}</h1>
{{ .Content | markdownify }}

Yes, it’ll necessitate refactoring of templates built for previous versions of Hugo. But that’s a side effect of the original mistake of inventing new behavior for something as ubiquitous as Markdown.

1 Like

This is what I use in quite many layout files and shortcodes:

{{ if in (string .Inner) "\n\n" }}
  {{ .Inner | markdownify }}
{{ else }}
  <p>{{ .Inner | markdownify }}</p>
{{ end }}

Thanks @Grob. I’ve created a PR to document this behaviour.

This is what I use in quite many layout files and shortcodes:

There’s also @imjasonmiller’s solution:

{{ $markdown := .intro | markdownify }}

{{ if not ( strings.Contains $markdown "<p>" ) }}
    <p>{{ $markdown }}</p>
{{ else }}
    {{ $markdown }}
{{ end }}

However, both of these suffer from the same issue, which is that they work fine with a plain sentence, but will break with headings. That is, puttting the solution in a shortcode called markdownifyshortcode, and

{{ "# heading" | markdownifyshortcode }}

will output invalid HTML.

<p><h1 id="test">test</h1></p>.

Here’s a solution that should work for most scenarios - it will add missing <p> tags if there’s no <p> or <h1,2,3,...> tags but will ignore other tags such as <span> or <em>:

{{- $markdown := .Inner | markdownify -}}

{{ if not ( findRE "<[h|p][^>]*>" $markdown ) }}
    <p>{{ $markdown }}</p>
{{ else }}
    {{ $markdown }}
{{ end }}
1 Like

Thanks for sharing your code.

Good point. This was never a problem in my use case because I never used a shortcode for a single lined heading.

I hope that Goldmark will resolve this issue completely.

1 Like

Well, I’m not intending to do that either. But I just know that if I don’t do this, in six months time I’ll end doing it, forgetting about all this, and then having to go through this whole process again to remind myself.

Better to future proof my shortcode now.

Here’s the workaround I used in my shortcode template:

    {{ .Inner | printf "%s\n\n<p></p>" | markdownify | replaceRE "\n*<p></p>\n*$" "" | safeHTML }}

It’s not optimal, but should work fine no matter what markup is contained in the content.


Since this was a widespread topic (there are a few more threads and issues on GitHub about it), I just wanted to mention that this problem is now solved and no more hacks are needed.

So please excuse that I am posting to this older thread.

This is an easy example of a blockquote shortcode:

{{ $optBlock := dict "display" "block" }}
  {{ with .Inner }}
    {{ . | $.Page.RenderString $optBlock }}
  {{ end }}
  {{ with .Get "author" }}
    <footer>{{ . | $.Page.RenderString }}</footer>
  {{ end }}

Notice that the first .RenderString produces a block element, whereas the second one default to inline.

Read more about .RenderString.

Wishing you a merry Christmas.