Skip to content

Instantly share code, notes, and snippets.

@ger86
Last active March 4, 2019 17:45
Show Gist options
  • Save ger86/466127d9f1bdad83431df576a4516a76 to your computer and use it in GitHub Desktop.
Save ger86/466127d9f1bdad83431df576a4516a76 to your computer and use it in GitHub Desktop.
<?php
namespace App\Service;
final class ShortcodeService {
private $shortcodes = [];
public function isShortcode($name) {
return isset($this->shortcodes[$name]);
}
/**
* Returns all the attrs of a found shortcode as a key / value array.
*
* @param string $text
* @return array
*/
private function _shortcodeParseAttrs(string $text): array {
$attrs = []
$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);
$text = html_entity_decode($text);
if (preg_match_all($pattern, $text, $match, PREG_SET_ORDER)) {
foreach ($match as $m) {
if (!empty($m[1])) {
$attrs[strtolower($m[1])] = stripcslashes($m[2]);
}
elseif (!empty($m[3])) {
$attrs[strtolower($m[3])] = stripcslashes($m[4]);
}
elseif (!empty($m[5])) {
$attrs[strtolower($m[5])] = stripcslashes($m[6]);
}
elseif (isset($m[7]) and strlen($m[7])) {
$attrs[] = stripcslashes($m[7]);
}
elseif (isset($m[8])) {
$attrs[] = stripcslashes($m[8]);
}
}
}
else {
$attrs = ltrim($text);
}
return $attrs;
}
/**
* Process one shortcode
*
* @param array $m contains the match of the regex
* @return string
*
*/
private function _shortcodeProcessTag(array $m): string {
$shortcodes = $this->shortcodes;
$tag = $m[2];
if (!empty($shortcodes[$tag])) {
$attr = $this->_shortcodeParseAttrs($m[3]);
$shortcode = $shortcodes[$tag];
if (!empty($m[4])) {
return $m[1] . $shortcode->apply($attr, $m[4]) . $m[5];
} else {
return $m[1] . $shortcode->apply($attr, null). $m[5];
}
} elseif (empty($m[4])) {
return $m[4];
}
return '';
}
/**
* Process a text with shortcodes
*/
public function shortcodeProcess(string $text) {
$shortcodes = $this->shortcodes;
$chunks = preg_split('!(\[{1,2}.*?\]{1,2})!', $text, -1, PREG_SPLIT_DELIM_CAPTURE);
$heap = array();
$heapIndex = array();
foreach ($chunks as $c) {
if (!$c) {
continue;
}
$escaped = false;
if ((substr($c, 0, 2) == '[[') && (substr($c, -2, 2) == ']]')) {
$escaped = true;
if ((substr($c, 0, 3) != '{') && (substr($c, -3, 1) != '}')) {
$c = substr($c, 1, -1);
}
}
if (!$escaped && ($c[0] == '[') && (substr($c, -1, 1) == ']')) {
$originalText = $c;
$c = substr($c, 1, -1);
$c = trim($c);
$ts = explode(' ', $c);
$tag = array_shift($ts);
$tag = trim($tag, '/');
if (!$this->isShortcode($tag)) {
array_unshift($heapIndex, '_string_');
array_unshift($heap, $originalText);
} elseif (substr($c, -1, 1) == '/') {
$m = array(
$c,
'',
$tag,
implode(' ', $ts),
NULL,
'',
);
array_unshift($heap_index, '_string_');
array_unshift($heap, $this->_shortcodeProcessTag($m));
} elseif ($c[0] == '/') {
$closingTag = substr($c, 1);
$processHeap = array();
$processHeapIndex = array();
$found = FALSE;
do {
$tag = array_shift($heapIndex);
$heapText = array_shift($heap);
if ($closingTag == $tag) {
$m = array(
$tag . ' ' . $heapText,
'',
$tag,
$heapText,
implode('', $processHeap),
'',
);
$str = $this->_shortcodeProcessTag($m);
array_unshift($heapIndex, '_string_');
array_unshift($heap, $str);
$found = TRUE;
} else {
array_unshift($processHeap, $heapText);
array_unshift($processHeapIndex, $tag);
}
} while (!$found && $heap);
if (!$found) {
foreach ($processHeap as $val) {
array_unshift($heap, $val);
}
foreach ($processHeapIndex as $val) {
array_unshift($heapIndex, $val);
}
}
} else {
array_unshift($heapIndex, $tag);
array_unshift($heap, implode(' ', $ts));
}
} else {
array_unshift($heapIndex, '_string_');
array_unshift($heap, $c);
}
}
return (implode('', array_reverse($heap)));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment