Markdown: paragraph on images

In default markdown if I include an image it is always inside a <p>-tag.
My <p>-tag is styled, so that there is a padding on top or bottom.

For my images this rule should be different.

Here is an example, so you can understand:

<p></p>
<p></p>
<p></p>

You have no idea in which Paragraph is the images and in which is the text.
I need something like this:

<p></p>
<div></div>
<p></p>

Or at least

<p></p>
<p class='image'></p>
<p></p>

Is this possible?

Hello dollique,

yes it is. Turn on Markdown Extra Support in the general settings.

Then u can do things like that:

# Heading {.be_special}

Now the heading becomes the class “be_special”. U can also mix markdown and html from now on. The rest u can get from the web. Just found this:

https://michelf.ca/projects/php-markdown/extra/

Hope it was helpfully
npetri

Thanks for the reply.

I already use this, but the class is not written on the <p>-tag but on the <img>-tag inside the <p>-tag.

For my problem I need the class on the <p>-tag!

Did u tried this?

<div markdown="1" class="be_special">
any markdown ...
</div>

Now u can style in css like:

some_class be_special p {
...
fancy styling
...
}

or simple

<p markdown="1" class="be_special">
some text
</>

Hope it is helpful
npetri

This at least is a workaround that does what I want.
If there is no other solution, I will consider using this. But I don’t really want to explain to the content managers how to code…

Thanks anyway!

ikr. maybe u style the blockquote element. this can be used in markdown like this:

>{.be_special} Some text.

This way no1 will have to use html.

I don’t really want to misuse the html-tags, but it would certainly work.

Just a general rule of thumb, but you don’t want to put any style other than some margin on <p> tags.

Yes, but my problem is actually about having margin on <p> where I don’t want it (for images) :wink:

Another option although it’s not optimal, is you can add a class to the image that provides a negative top/bottom margin to offset any paragraph tag.

![](yourimage.jpg?classes=p-offset

and then for your CSS:

.p-offset {
 margin: -15px 0
}

hello everybody,

Sorry to warm up this old threat, but there has been no other solution to the initial issue than the ones provided, right?

unfortunately in my project, it does not always behave the same way.
sometimes the images show up in

tags as described by @dollique, but in other instances (same folder, just different “blog”-post) the images show up without the

-tag (which is what i want).

everything else for both posts looks identical, it really drives me insane.

for what it’s worth: when adding figure text via the Image Captions PlugIn the image is within the tag instead of

.

…not being a developer myself, i am already afraid that adding ?classes=caption "Some Text" for the figure text is too much. so, i feel you.

thanks for any hint. :slight_smile:

g

You could create a simple plugin to remove the <p> tags around your images. Something along these lines (untested):

<?php
namespace Grav\Plugin;

use Grav\Common\Plugin;
use RocketTheme\Toolbox\Event\Event;

class UnwrapPlugin extends Plugin
{
    public static function getSubscribedEvents()
    {
        return [
            'onPluginsInitialized' => ['onPluginsInitialized', 0]
        ];
    }

    public function onPluginsInitialized()
    {
        if ($this->isAdmin()) {
            return;
        }

        $this->enable([
            'onPageContentProcessed' => ['onPageContentProcessed', 0]
        ]);
    }

    public function onPageContentProcessed($event)
    {
        $page = $event['page'];         
        $content = $page->getRawContent();
        $content = preg_replace('/<p>(<img[\w\W]+?\/>)<\/p>/', '$1' ,$content);
        $page->setRawContent($content);
    }
}

@TheDancingCode
thanks for that! I might actually test that at some point, but since I don’t know what i’d be doing but copying code monkey-style, this will unfortunately have to wait until i have more time. but i guess, there is no straight forward solution (or explaination, why it is behaving differently sometimes).

Temporary Solution
btw. when using the Image Caption plugin, they are at least in a <figure> tag which I can use. unfortunatelly only, when i also actually add text or at least a space. which is what i will be doing for now, i guess.

still hoping for that simple fix, though. :wink:

g

I’m also following this topic hoping for an elegant or built-in solution.

I found another workaround, for anyone interested.

With the shortcode-core plugin installed, you can surround the image in a shortcode such as [div] ![my image](my_image.jpg) [/div] or, more appropriately, [figure] ![my image](my_image.jpg) [/figure], avoids the image being surrounded in paragraph tags, and the shortcode tag can be given a class and styled accordingly: [figure class="a_class"].

Not much different than just using HTML, but it’s something— and does allow you to keep using markdown image links.

Another update: I referenced this thread and after tinkering with the php, updated and corrected some of the code to create a working plugin that removes <p> tags from around images.

I’m an amateur, so I’m open to corrections and suggestions here or via github.

1 Like

Update: new url for the plugin that I mentioned in the comment above. I’ve submitted it to Grav for possible inclusion.

@prw, Because you requested some feedback…

First some feedback on the plugin:

  • Have a look at $this->mergeConfig($page), to merge the global config with the page-level config. This will allow you to cleanup some code. See https://learn.getgrav.org/16/plugins/plugin-tutorial#merging-plugin-and-page-configuration

    Beware: Your frontmatter should now use a dash instead of an underscore:

    ---
    unwrap-images:
       process_content: true
    ---
    
  • Code line wrapping seems a bit unusual.

  • $url is never used.

  • Why do you declare $page and $pageobject?

    $page = $event['page'];
    $pageobject = $this->grav['page'];
    
  • Use ‘identical comparisons’:
    if ($processcontent == true) should be if ($processcontent === true) else a value of ‘xxx’ would be considered to be true too.

  • You turn the page content into a DOMDocument and replace the original content with DomDocument::saveHTML(). This will not save the page’s content, but inserts a new DOMDocument into the page.

    The resulting page will therefor become a nested HTML document:

    <!DOCTYPE html>
    <html lang="en">
    <head>
      ...
    </head>
    <body>
       ...
       <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
       <?xml encoding="UTF-8">
       <html>
       <body>
          <!--- the parsed page content -->
       </body>
       </html>
       ...
    </body> 
    </html> 
    
  • Instead of using heavy weight DOMDocument, you might consider trying a regex. The following is a rough example:

    $class = $config['class'];
    
    // Search for <p> and <a> (may not exist)
    $pattern = '/<p>(<a[^>]*>\s*)?';
    // Search <img> tag. Skip when value $class exists anywhere in tag. Regex uses negative lookahead
    $pattern .= $class ? '(<img(?:[^>](?!' . $class . '))*>)' : '(<img[^>]*>)';
    // Search for </a> (it may not exist) and closing </p>
    $pattern .= '(\s*<\/a>\s*)?<\/p>/';
    
    $content = preg_replace($pattern, '$1$2$3', $page->content());
    
    • The regex is about >25 times faster.
    • It saves you approx 25 lines of code.
    • It will currently not work when 2 images are not separated by empty line in Markdown.
    • An <img> containing value of ‘$class’ anywhere inside tag will be skipped.
    • As said… it is a rough example and I’m no professional either. So I make mistakes…

Feedback on submitting a plugin:

I think your willingness to spend time and effort to contribute to the community will be highly appreciated. But, IMHO it also comes with a responsibility. The community trusts plugins to have a certain level of quality and launches production websites using it…

So, I applaud you for asking feedback!

For the time being, you might consider asking the Grav team to hold back the submission of your plugin until your code has been tested thoroughly.

Hope you do not consider this feedback as being negative, but instead as one with a positive intention…

Thanks, @pamtbaau for all that very helpful feedback! I was obviously over-enthusiastic, and probably shouldn’t have submitted the plugin. The code is all just patched together—I only managed to combine and edit stuff based on what I could learn without any real foundational knowledge of php, or twig for that matter.

Regarding the regex, I found multiple comments on stackoverflow warning against using regex to parse HTML. The code I started with used regex, but I switched based on that advice.

I’ll try to understand and implement your suggestions, and suggest to the grav team not to implement my plugin. Thanks again.

Although it’s true that parsing HTML with RegExp generally isn’t a good idea, the pattern we’re looking for is so specific and the markdown output so predictable that it’s really quite safe to use it here.

Have a look at the code I posted earlier. It’s simple, fast and it works.