Skip to content

Instantly share code, notes, and snippets.

@mbischof
Created September 25, 2013 23:15
Show Gist options
  • Save mbischof/6707531 to your computer and use it in GitHub Desktop.
Save mbischof/6707531 to your computer and use it in GitHub Desktop.
wordpress like shortcode
<?php
class ShortCodeWidget extends COutputProcessor
{
public $purifyOutput = false;
private $codes;
public function processOutput($output)
{
$dir = Yii::getPathOfAlias('ext.shortcodes');
$files = CFileHelper::findFiles($dir);
foreach ($files as $file) {
include $file;
}
$output = $this->transform($output);
if ($this->purifyOutput) {
$purifier = new CHtmlPurifier;
$output = $purifier->purify($output);
}
parent::processOutput($output);
}
function add($tag, $func)
{
if (is_callable($func)) {
$this->codes[$tag] = $func;
}
}
function transform($content)
{
if (empty($this->codes) || !is_array($this->codes)) {
return $content;
}
$pattern = $this->getRegex();
return preg_replace_callback("/$pattern/s", array($this, 'transformTag'), $content);
}
public function transformTag($m)
{
// allow [[foo]] syntax for escaping a tag
if ( $m[1] == '[' && $m[6] == ']' ) {
return substr($m[0], 1, -1);
}
$tag = $m[2];
$attr = $this->parseAttributes($m[3]);
if ( isset($m[5]) ) {
// enclosing tag - extra parameter
return $m[1] . call_user_func($this->codes[$tag], $attr, $m[5], $tag) . $m[6];
} else {
// self-closing tag
return $m[1] . call_user_func($this->codes[$tag], $attr, null, $tag) . $m[6];
}
}
function parseAttributes($text)
{
$atts = array();
$pattern = '/(w+)s*=s*"([^"]*)"(?:s|$)|(w+)s*=s*'([^']*)'(?:s|$)|(w+)s*=s*([^s'"]+)(?:s|$)|"([^"]*)"(?:s|$)|(S+)(?:s|$)/';
$text = preg_replace("/[x{00a0}x{200b}]+/u", " ", $text);
if (preg_match_all($pattern, $text, $match, PREG_SET_ORDER)) {
foreach ($match as $m) {
if (!empty($m[1]))
$atts[strtolower($m[1])] = stripcslashes($m[2]);
elseif (!empty($m[3]))
$atts[strtolower($m[3])] = stripcslashes($m[4]);
elseif (!empty($m[5]))
$atts[strtolower($m[5])] = stripcslashes($m[6]);
elseif (isset($m[7]) and strlen($m[7]))
$atts[] = stripcslashes($m[7]);
elseif (isset($m[8]))
$atts[] = stripcslashes($m[8]);
}
} else {
$atts = ltrim($text);
}
return $atts;
}
function getRegex()
{
$tagnames = array_keys($this->codes);
$tagregexp = join('|', array_map('preg_quote', $tagnames));
// WARNING! Do not change this regex without changing do_shortcode_tag() and strip_shortcode_tag()
return
'\[' // Opening bracket
. '(\[?)' // 1: Optional second opening bracket for escaping shortcodes: [[tag]]
. "($tagregexp)" // 2: Shortcode name
. '\b' // Word boundary
. '(' // 3: Unroll the loop: Inside the opening shortcode tag
. '[^\]\/]*' // Not a closing bracket or forward slash
. '(?:'
. '\/(?!\])' // A forward slash not followed by a closing bracket
. '[^\]\/]*' // Not a closing bracket or forward slash
. ')*?'
. ')'
. '(?:'
. '(\/)' // 4: Self closing tag ...
. '\]' // ... and closing bracket
. '|'
. '\]' // Closing bracket
. '(?:'
. '(' // 5: Unroll the loop: Optionally, anything between the opening and closing shortcode tags
. '[^\[]*+' // Not an opening bracket
. '(?:'
. '\[(?!\/\2\])' // An opening bracket not followed by the closing shortcode tag
. '[^\[]*+' // Not an opening bracket
. ')*+'
. ')'
. '\[\/\2\]' // Closing shortcode tag
. ')?'
. ')'
. '(\]?)'; // 6: Optional second closing brocket for escaping shortcodes: [[tag]]
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment