Not logged in. · Lost password · Register
Forum: General Help and Support Development RSS
Parsing markup in plugin output
Avatar
DavidN #1
Member for 3 months · 2 posts
Group memberships: Members
Show profile · Link to this post
Subject: Parsing markup in plugin output
Hi! I'm attempting to write a plugin for personal use on a wiki which will generate links. I'm trying to find the correct way to allow parsing the output from the plugin as markup - the eventual aim is for the plugin to generate a link with an icon. Outputting HTML works fine, but is there a way to output wiki markup and then have that output parsed?

Here's my class so far:

class syntax_plugin_zchar extends DokuWiki_Syntax_Plugin {

    function getType(){
        return 'container';
    }
 
    function getSort(){
        return 999;
    }

    function connectTo($mode) {
      $this->Lexer->addEntryPattern('<zchar>',$mode,'plugin_zchar');
    }
 
    function postConnect() {
      $this->Lexer->addExitPattern('</zchar>','plugin_zchar');
    }

    function getChars() {
        return [
            'anna' => 'Anna Arbuckle',
            'bob' => 'Bob Bobberson',
            'clive' => 'Clive Clark',
            'david' => 'David Dennis',
        ];
    }
   
    function handle($match, $state, $pos, &$handler){
        $result = ['text' => ''];
        switch ($state) {
          case DOKU_LEXER_ENTER :
          case DOKU_LEXER_MATCHED :
          case DOKU_LEXER_EXIT :
          case DOKU_LEXER_SPECIAL :
            break;
          case DOKU_LEXER_UNMATCHED :
            $values['key'] = $match;
            $chars = $this->getChars();
            $char = $chars[$values['key']];
            if (empty($char)) {
                $result['text'] = "(Person '" . $data['key'] . "' not found)";
            }
            else {
                $result['text'] = '[[person:' . $char . ']]';
            }
        }
        return $result;
    }
 
    function render($mode, &$renderer, $data) {
        if($mode != 'xhtml') { return false; }
        if(empty($data)) { return false; }
        $renderer->doc .= $data['text'];
        return true;
    }
}

With this, <zchar>anna</zchar> will output [[person:Anna Arbuckle]] literally on the page. How can I instead have that interpreted as a link - parse the output of the plugin as markup?

Thanks!
Avatar
LarsDW223 #2
Member since Sep 2014 · 472 posts · Location: Paderborn
Group memberships: Members
Show profile · Link to this post
Have a look at this code snippet:

$instructions = p_get_instructions($markup);
$html = p_render('xhtml', $instructions, $info);

The function p_get_instructions will parse the wiki markup and p_render will generate the output from it - in this case for 'xhtml'.
Avatar
DavidN #3
Member for 3 months · 2 posts
Group memberships: Members
Show profile · Link to this post
Thanks so much! That was the exact magic I was missing - I've now expanded this to automatically create links for people, locations and roles that are pulled from a database, and it's so much easier to maintain :)
Avatar
andi (Administrator) #4
User title: splitbrain
Member since May 2006 · 3538 posts · Location: Berlin Germany
Group memberships: Administrators, Members
Show profile · Link to this post
In reply to post #2
Quote by LarsDW223 on 2019-12-23, 06:32:
$instructions = p_get_instructions($markup);
$html = p_render('xhtml', $instructions, $info);

Don't. Unless you have a very very good reason to do this and your plugin is only rarely used on a page. Doing this instantiates a completely new parser/rendering cycle (within the current one) and is bound to become a performance nightmare.

There is no reason for your plugin to *create* wiki syntax. If you want to *accept* wiki syntax provided by users, then use the proper mode handling mechanisms as described at https://www.dokuwiki.org/devel:syntax_plugins#key_concepts
Read this if you don't get any useful answers.
Lies dies wenn du keine hilfreichen Antworten bekommst.
Avatar
xube #5
Member since Mar 2010 · 2 posts
Group memberships: Members
Show profile · Link to this post
Hello, andi,

Could you tell me how can i render my syntax accordingly to proper mode handling? Am i doing something wrong? I use getAllowedTypes as well as getType. I am trying use PType even it is not necessary and undesirable because the output is going to the table.

p_render is working perfectly fine. I understand concerns about cache, but why is dokuwiki syntax not working on my output? Did i miss something?

class syntax_plugin_infobox extends DokuWiki_Syntax_Plugin {
   
    /* REGEX PATTERNS */
    protected $entry_pattern       = '<infobox>\n.*?(?=.*</infobox>)';
    protected $row_pattern         = '\|.*?(?=.*?)\n';
    protected $exit_pattern        = '</infobox>';

    function getType(){ return 'formatting';}
    function getAllowedTypes() { return array('container', 'formatting', 'substition', 'protected', 'disabled', 'paragraphs'); }
    function getPType(){ return 'stack';}
    function getSort(){ return 195; }
 
    public function connectTo($mode) {
        $this->Lexer->addEntryPattern($this->entry_pattern, $mode, 'plugin_infobox'); //new       
       
        //Add Internal Pattern Match
        $this->Lexer->addPattern($this->row_pattern, 'plugin_infobox');       
    }
   
    public function postConnect() {
        $this->Lexer->addExitPattern($this->exit_pattern, 'plugin_infobox');       
    }
   
    public function handle($match, $state, $pos, Doku_Handler $handler) {   
       
        switch ($state){
       
            case DOKU_LEXER_ENTER :
                break;
            case DOKU_LEXER_MATCHED :
                //Find The Token And Value (Before '=' remove white space, convert to lower case).
                $tokenDiv = strpos($match, '=');                                            //Find Token Value Divider ('=')
                $prettyToken = trim(substr($match, 1, ($tokenDiv - 1)));                    //Everything Before '=', Remove White Space
                $token = strtolower($prettyToken);                                            //Convert To Lower Case
                $value = trim(substr($match, ($tokenDiv + 1)));                                //Everything after '='

                return array($state, $value, $prettyToken);

            case DOKU_LEXER_UNMATCHED :   
                return array($state, $match);
            case DOKU_LEXER_EXIT :
                return array($state, '');
            case DOKU_LEXER_SPECIAL :
                return array($state, $data, '');
        }
       
        return array($state, $match);       
    }
    
    public function render($mode, Doku_Renderer $renderer, $indata){
           
        if (empty($indata)) return false;
        list($state, $data, $title) = $indata;
        $token = strtolower($title);
   
        if($mode == 'xhtml'){
            switch ($state){
              case DOKU_LEXER_ENTER :
                  $renderer->startSectionEdit(0, $indata);
                  $renderer->doc .= '<table class="infobox" style="border:1px #CCC solid;background-color:#F5F5F5">';
                  break;
              case DOKU_LEXER_MATCHED :
                $renderer->doc .= '<tr>';               
                if ($token) :
                switch ($token) {
                    case 'title';
                    case 'header';
                    case 'subtitle';
                        $renderer->doc .= '<th colspan="2" style="text-align:center; font-size: 125%; font-weight: bold; background:#ccf;">'.$title.'</th>';
                        break;
                    case 'image';
                        $renderer->doc .= '<td colspan="2">'.$renderer->internalmedia($data,'','center','auto','auto','cache','nolink',true).'</td>';                       
                    break;
                    case 'footer';
                        $renderer->doc .= '<td colspan="2">'.$data.'</td>';
                        break;
                    default;
                        $renderer->doc .= '<th>'.$title.'</th>';
                        $renderer->doc .= '<td>'.$data.'</td>';
                        // $instructions = p_get_instructions($data);
                        // $html = p_render('xhtml', $instructions, $info);
                        // $renderer->doc .= '<td>'.$html.'</td>';
                        break;
                    }
                endif;               
                $renderer->doc .= '</tr>';
                break;             
              case DOKU_LEXER_SPECIAL :               
                break;
              case DOKU_LEXER_UNMATCHED :
                // $renderer->doc .= $renderer->_xmlEntities($data);
                break;
              case DOKU_LEXER_EXIT :
                $renderer->doc .= '</table>';
                $renderer->finishSectionEdit();
                break;               
            }           
            return true;
        }       
        return false;
    }
}
Close Smaller – Larger + Reply to this post:
Verification code: VeriCode Please enter the word from the image into the text field below. (Type the letters only, lower case is okay.)
Smileys: :-) ;-) :-D :-p :blush: :cool: :rolleyes: :huh: :-/ <_< :-( :'( :#: :scared: 8-( :nuts: :-O
Special characters:
Go to forum
Imprint
This board is powered by the Unclassified NewsBoard software, 20150713-dev, © 2003-2015 by Yves Goergen
Current time: 2020-04-02, 21:54:09 (UTC +02:00)