Class to automate parsing Joomla Content Plugin tags.

 

Easy operation, define your tag name, and if it is a self-closing tag

Update 4-23-2013 - Added option to use an alternate closing tag. Namespaced DOMDocument, so the class can itself be namespaced, should the application require it.

$content = '{plugin param yoyoyo param1="param with a string value containing spaces" param2="2" param3="3" unquotedinteger=4 param4=unquotedstring}plugin content{/plugin}';
$content.= '{plugin}contents{/plugin}';
$parser = new TagParser('plugin');
$parser->parse($content);
foreach($parser->tags as $key=>$tag) {
    $param1 = $tag->getParam('param1','default value');
    echo $tag->getContent('default content');
    /* of course, you'll want to do something with the tags */
    $content = $tag->replace($content,'<p class="param1 or whatever">'.$param1.'</p>');
}
 
/* appending the previous $content and using the previous $parser 
 * (adjusting it for a slightly different tag, with an alternate closing tag),
 * this tag is appended to the taglist of the previous instance 
 */
$content.= "{plugin:detail param1=2 param2=3 param3=1}plugin content2{/plugin}";
$parser->setIdentifier('plugin:detail');
$parser->setOptions(array('alternateclose'=>'plugin'));
$parser->parse($content);
foreach($parser->tags as $key=>$tag) {
    echo $tag->getParam('param1','default value');
    echo $tag->getContent('default content');
    /* we did something else, so we just get rid of this tag entirely */
    $content = $tag->replace($content,'');
}
 
$content2 = '{plugin2 param param1=1 param2=2 param3=3}';
$parser2 = new TagParser('plugin2',array('selfclosing'=>true));
$parser2->parse($content2);
foreach($parser2->tags as $key=>$tag) {
    echo $tag->getParam('param1','default value');
}
 
$content3 = '[plugin3 param param1=1 param2=2 param3=3]<a href="#">plugin content</a>[/plugin3]';
$parser3 = new TagParser('plugin3',array('bracket'=>'[]'));
$parser3->parse($content3);
foreach($parser3->tags as $key=>$tag) {
    echo $tag->getParam('param1','default value');
    echo $tag->getContent('default content');
}
 

And here's the class:

<!--?php
/**
* @package library TagParser
* @copyright (C) 2010-2013 RicheyWeb - www.richeyweb.com
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
*/
// no direct access
defined( '_JEXEC' ) or die( 'Restricted access' );
    class TagParser {
        protected static $instances = array();
        private $identifier = '';
        private $options = array(
            'bracket'=>'{}',
            'alternateclose'=>false,
            'selfclosing'=>false
        );
        public $tags = array();
        public $total = 0;
        public function __construct($identifier=false,$options=false) {
            if($identifier) {
                $this->setIdentifier($identifier);
                if($options) $this->setOptions($options);
            }
        }
        public static function getInstance($identifier=false,$options=false) {
            $instanceid = $identifier?$identifier:'';
            if(empty(self::$instances[$instanceid])) {
                self::$instances[$instanceid] = new TagParser($identifier,$options);
            }
            return self::$instances[$instanceid];
        }
        public function setIdentifier($identifier=false) {
            if($identifier) $this->identifier = $identifier;
        }
        public function setOptions($options=false) {
            if(is_array($options)) {
                foreach($options as $key=>$option) $this->options[$key]=$option;
            }
            if(strlen($this->options['bracket']) == 1) $this->options['bracket'] = $this->options['bracket'].$this->options['bracket'];       
        }
        public function parse($content) {
            $regex ='/'.$this->bracket('open').$this->identifier.'\s*?(?<params>.*?)'.$this->bracket('close');
            if(!$this->options['selfclosing']) $regex.='(?<content>.*?)(?<closetag>'.$this->bracket('open').'\/'.($this->options['alternateclose']?$this->options['alternateclose']:$this->identifier).$this->bracket('close').')';
            $regex.='/';
            $matches = array();
            preg_match_all($regex,$content,$matches);
            foreach($matches[0] as $key=>$match) {
                $this->total++;
                $this->tags[$key]=new TagParserItem($match);
                $this->tags[$key]->tagid = $this->total;
                if(strlen($matches['params'][$key])) {
                    $params = new \DOMDocument;
                    $params->loadHTML('<br '.trim($matches['params'][$key]).' />');
                    $paramsxml = simplexml_import_dom($params->documentElement);
                    if(count($paramsxml->body->br->attributes())) {
                        $this->tags[$key]->params = array();
                        foreach($paramsxml->body->br->attributes() as $attribute=>$value) {
                            $this->tags[$key]->params[$attribute]=(strlen($value->__toString())?$value->__toString():true);
                        }
                    }
                }
                if(!$this->options['selfclosing']) $this->tags[$key]->content = $matches['content'][$key];
            }
        }    
        private function bracket($type='open') {
            return preg_quote(($type=='open')?$this->options['bracket'][0]:$this->options['bracket'][1]);
        }
    }
    class TagParserItem {
        public $tag;
        public $tagid=0;
        public $params = false;
        public $content = false;
        public function __construct($tag) {
            $this->tag = $tag;
        }
        public function getParam($name,$default) {
            return isset($this->params[$name])?$this->params[$name]:$default;
        }
        public function getContent($default='') {
            return $this->content?$this->content:$default;
        }
        public function replace($content,$replacement='') {
            $regex='/'.preg_quote($this->tag,'/').'/';
            return preg_replace($regex,$replacement,$content,1);
        }
    }
 

 

Why is this software free?

I’m ditching the freemium game and giving this software to the Joomla crowd for free. It’s a nod to “Jumla”—Swahili for “all together”—because fragmentation sucks, and I’d rather focus on innovation and paid gigs. Use it, build with it, and if you need custom work, I’m super into that.

What's The Catch?

There isn’t one! I’m all about building tools that empower the Joomla community and spark creativity. This software’s free because I’d rather see it in your hands - fueling awesome projects. If you really feel like paying something, I’d appreciate a review in the Joomla Extension Directory—your feedback means a lot!