Skip to content

Modifying shortcode replacements via event handler? #67

Open

Description

@mpdude

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?

Activity

  1. mpdude commented on Apr 25, 2018

    @mpdude
    Author

    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...

  2. thunderer commented on Apr 25, 2018

    @thunderer
    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));
  3. thunderer commented on Apr 25, 2018

    @thunderer
    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!

  4. self-assigned this
    on Apr 25, 2018
  5. mpdude commented on Apr 26, 2018

    @mpdude
    Author

    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

Metadata

Metadata

Assignees

Labels

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions