Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modifying shortcode replacements via event handler? #67

Open
mpdude opened this issue Apr 25, 2018 · 4 comments
Open

Modifying shortcode replacements via event handler? #67

mpdude opened this issue Apr 25, 2018 · 4 comments
Assignees
Labels

Comments

@mpdude
Copy link

mpdude commented Apr 25, 2018

Is it possible to use either Events::FILTER_SHORTCODES or Events::REPLACE_SHORTCODES to modify/extend the replacement string provided by the handler?

I am looking for a way to insert additional HTML (say, a </div>...<div>) around shortcodes. When determining this additional HTML, I'd need to know at lease the shortcode name. And I would like to keep this out of the handler, because it is context/situation specific.

Any pointers?

@mpdude
Copy link
Author

mpdude commented Apr 25, 2018

I may be headed in the wrong direction, but I think this would be straightforward if the ReplacedShortcode contained in the ReplaceShortcodesEvent were not read-only, so that I could just tweak the replacement strings...

@thunderer
Copy link
Owner

Yes, this is one of the use cases for Events::REPLACE_SHORTCODES. Here is a quick example I wrote for you, I hope I understood your problem correctly:

  • create handlers with default handler that just returns the name and content,
  • create REPLACE_SHORTCODES event handler with our replacement mechanism (copied directly from Processor),
  • this mechanism wraps each shortcode replacement in a different HTML tag (see the rewrite method),
  • creates processor with our event handler inside,
  • asserts that the code works as expected at the bottom.
$handlers = new HandlerContainer();
$handlers->setDefault(function(ShortcodeInterface $s) { return $s->getName().$s->getContent(); });

$events = new EventContainer();
$events->addListener(Events::REPLACE_SHORTCODES, new class {
    public function __invoke(ReplaceShortcodesEvent $event)
    {
        $text = $event->getText();
        /** @var ReplacedShortcode $s */
        foreach(array_reverse($event->getReplacements()) as $s) {
            $offset = $s->getOffset();
            $length = mb_strlen($s->getText(), 'utf-8');
            $textLength = mb_strlen($text, 'utf-8');
            $prefix = mb_substr($text, 0, $offset, 'utf-8');
            $postfix = mb_substr($text, $offset + $length, $textLength, 'utf-8');

            $text = $prefix.$this->rewrite($s).$postfix;
        }

        $event->setResult($text);
    }

    private function rewrite(ReplacedShortcode $r)
    {
        return [
            'what' => function(ReplacedShortcode $r) { return '<p>'.$r->getReplacement().'</p>'; },
            'goes' => function(ReplacedShortcode $r) { return '<b>'.$r->getReplacement().'</b>'; },
            'around' => function(ReplacedShortcode $r) { return '<u>'.$r->getReplacement().'</u>'; },
        ][$r->getName()]($r);
    }
});

$processor = new Processor(new RegularParser(), $handlers);
$processor = $processor->withEventContainer($events);

$text = 'a [what] [goes /] [around /] [/what] z';
$expected = 'a <p>what <b>goes</b> <u>around</u> </p> z';
assert($expected === $processor->process($text));

@thunderer
Copy link
Owner

BTW The idea of an event before Events::REPLACE_SHORTCODES which allows you to tweak the replacement seems like a good idea. It may be a quite significant performance hit, but as an optional mechanism (no handler === no hit) should work quite well. The event handler would receive ReplacedShortcode and return the new replacement which would take place of the old one. The temporary name I came up with is Events::REWRITE_REPLACEMENT I need to investigate this further, thanks!

@thunderer thunderer self-assigned this Apr 25, 2018
@mpdude
Copy link
Author

mpdude commented Apr 26, 2018

Tomasz,

thanks a lot for your quick reply and the code example above. Indeed, I've seen something similar at #40 (comment) ;-).

I wonder if it really has to be as complicated as this, since there is already code to do this heavy lifting of merging the original content and the replacements together. I mean, if the ReplacedShortcode would allow to modify the replacement string, wouldn't we be done?

Yes, I do know about the advantages of immutable objects... 😀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants