Parenthesis in image caption is jackin' things up

The use of parenthesis in a caption is confusing Kirby. I understand why. Consider the following.

(image: lobster-boat-blockade.jpg caption: From Left to Right: Jay O'Hara (holding photo), Attorney Matt Pawa (speaking to reporters))

The parenthesis in the caption are closing the “shortcode”. I could tell the client to use brackets, but that’s just another thing they have to remember. I’d be nice if the “shortcodes” could use some other less common character to open and close them.

Are there any workarounds for this?

1 Like

Unfortunately, there still is no way to escape parenthesis inside Kirbytags, at least not any I know of. So, you can’t use parenthesis inside Kirbytags. A work around would be to use some other characters like square brackets and replace those with a Kirbytext post filter, but as you said, it’s more difficult for clients to remember.

This issue has come up a few times before and there was a fix, but that fix was removed again because it wasn’t reliable.

See this topic for workarounds and discussion.

See also this post

This is not working with Kirby 3. Any suggestion?

Thanks

OK I solve it by adding caption meta field to image so image kirbytag get it from…

So I’m not sure this is the most efficient way of doing it but this solution seems to be working in my tests

# Fix the () nested inside the kirbytags
'kirbytags:before' => function ($text, array $data = [], array $options = []) {

    // KirbyTags have not been parsed
    $text = preg_replace_callback('/\((?:[^()]+|(?R))*+\)/', function ($matches) {
        
        // Loop through each tag and perform a second serach
        foreach ($matches as $match) :

            // First trim the () at the beginning and at the end
            $match = substr($match , 1 , -1);

            // Then look for () inside the string and replace them with another character
            $match = str_replace('(', '⎣', $match);
            $match = str_replace(')', '⎦', $match);

            // Add back the two () at the beginning and the end
            $match = "({$match})";

            // Return the string
            return $match;

        endforeach;

        # Return al the kirbytags
        return $matches;

    }, $text);

    return $text;
},

# Add back the () we swapped previously
'kirbytags:after' => function ($text, array $data = [], array $options = []) {

    $text = preg_replace_callback('/\⎣|\⎦/', function ($matches) {
        
        // Loop through each tag and swap the characters
        foreach ($matches as $match) :

            // Swap back the correct ()
            $match = ($match == "⎣" ) ? "(" : ")";
            
            // Return the string
            return $match;

        endforeach;

        # Return al the kirbytags
        return $matches;

    }, $text);

    return $text;
},

Pretty sure it can be improved though

1 Like

How/Where did you include this snippet? I tried as a plugin but couldn’t get it to work (new to Kirby!)

@parislettau Which version of Kirby are you using? The solution in this thread is for Kirby 2 and the syntax and way to include plugins has changed.

@texnixe thanks for quick response! I’m using Kirby 3 – is there a solution for Kirby 3?

For Kirby 3 you can use a kirbytags:before hook:

For example, you could add this hook in config.php:

 'hooks' => [
        'kirbytags:before' => function ($text, $data, $options) {
               // KirbyTags have not been parsed
    $text = preg_replace_callback('/\((?:[^()]+|(?R))*+\)/', function ($matches) {
        
        // Loop through each tag and perform a second serach
        foreach ($matches as $match) :

            // First trim the () at the beginning and at the end
            $match = substr($match , 1 , -1);

            // Then look for () inside the string and replace them with another character
            $match = str_replace('(', '⎣', $match);
            $match = str_replace(')', '⎦', $match);

            // Add back the two () at the beginning and the end
            $match = "({$match})";

            // Return the string
            return $match;

        endforeach;

        # Return al the kirbytags
        return $matches;

    }, $text);

    return $text;
        }
    ]

(not tested)

Alternatively, you can register this hook in a plugin.

Perfect, thank you so much @texnixe

I made one small change to replace each $match with square brackets (which then render as round brackets) instead of the '⎣' and '⎦' characters:

So for anyone interested my final plugin in site/plugins/kirby-captions-brackets/index.php (which is working after some brief testing) is:

<?php

 Kirby::plugin('alias/kirby-captions-brackets', [
  
  'hooks' => [
        'kirbytags:before' => function ($text, $data, $options) {
               // KirbyTags have not been parsed
    $text = preg_replace_callback('/\((?:[^()]+|(?R))*+\)/', function ($matches) {
        
        // Loop through each tag and perform a second serach
        foreach ($matches as $match) :

            // First trim the () at the beginning and at the end
            $match = substr($match , 1 , -1);

            // Then look for () inside the string and replace them with another character
            $match = str_replace('(', '[', $match);
            $match = str_replace(')', ']', $match);

            // Add back the two () at the beginning and the end
            $match = "({$match})";

            // Return the string
            return $match;

        endforeach;

        # Return al the kirbytags
        return $matches;

    }, $text);

    return $text;
        }
    ]

]);