| 1 | <?php |
|---|
| 2 | /* |
|---|
| 3 | Plugin Name: Tagcode Interpreter |
|---|
| 4 | Description: Can be used to replace buggy shortcodes |
|---|
| 5 | Version: 0.9 |
|---|
| 6 | Author: Jacob Beauregard |
|---|
| 7 | */ |
|---|
| 8 | |
|---|
| 9 | /** |
|---|
| 10 | * global index |
|---|
| 11 | */ |
|---|
| 12 | $_tagcode_register = array(); |
|---|
| 13 | |
|---|
| 14 | /** |
|---|
| 15 | * tagcode public interface |
|---|
| 16 | */ |
|---|
| 17 | function add_tagcode($name,$handler,$priority=10) { |
|---|
| 18 | global $_tagcode_register; |
|---|
| 19 | $_tagcode_register[$name] = true; |
|---|
| 20 | return add_filter(_tagcode_ref_name($name),$handler,$priority,3); |
|---|
| 21 | } |
|---|
| 22 | function apply_tagcodes($name,$content,$attrs) { |
|---|
| 23 | $ref = array($name,$content,$attrs); |
|---|
| 24 | return apply_filters_ref_array(_tagcode_ref_name($name),$ref); |
|---|
| 25 | } |
|---|
| 26 | function eval_tagcodes($content) { |
|---|
| 27 | return _tagcode_eval($content); |
|---|
| 28 | } |
|---|
| 29 | function has_tagcode($name,$handler=false) { |
|---|
| 30 | return has_filter(_tagcode_ref_name($name),$handler); |
|---|
| 31 | } |
|---|
| 32 | function remove_all_tagcodes($name,$priority=false) { |
|---|
| 33 | global $_tagcode_register; |
|---|
| 34 | $value = remove_all_filters(_tagcode_ref_name($name),$priority); |
|---|
| 35 | if (!has_tagcode($name)) { |
|---|
| 36 | $_tagcode_register[$name] = false; |
|---|
| 37 | } |
|---|
| 38 | return $value; |
|---|
| 39 | } |
|---|
| 40 | function remove_tagcode($name,$handler,$priority=10) { |
|---|
| 41 | global $_tagcode_register; |
|---|
| 42 | $value = remove_filter(_tagcode_ref_name($name),$handler,$priority,3); |
|---|
| 43 | if (!has_tagcode($name)) { |
|---|
| 44 | $_tagcode_register[$name] = false; |
|---|
| 45 | } |
|---|
| 46 | return $value; |
|---|
| 47 | } |
|---|
| 48 | |
|---|
| 49 | /** |
|---|
| 50 | * alias to use in filter for given tag name |
|---|
| 51 | */ |
|---|
| 52 | function _tagcode_ref_name($name) { |
|---|
| 53 | return "_tagcode_".strtolower($args[0]); |
|---|
| 54 | } |
|---|
| 55 | |
|---|
| 56 | /** |
|---|
| 57 | * types of tagcode expressions |
|---|
| 58 | */ |
|---|
| 59 | function _tagcode_types() { |
|---|
| 60 | return array( |
|---|
| 61 | 'esc_lsqbr', |
|---|
| 62 | 'esc_rsqbr', |
|---|
| 63 | 'tag_inline', |
|---|
| 64 | 'tag_open', |
|---|
| 65 | 'tag_close', |
|---|
| 66 | 'attr', |
|---|
| 67 | 'literal', |
|---|
| 68 | 'entity_ref', |
|---|
| 69 | 'char_ref', |
|---|
| 70 | 'char_str', |
|---|
| 71 | 'name', |
|---|
| 72 | 'text' |
|---|
| 73 | ); |
|---|
| 74 | } |
|---|
| 75 | |
|---|
| 76 | /* |
|---|
| 77 | * tagcode expressions that are subtypes of other tagcode expressions |
|---|
| 78 | */ |
|---|
| 79 | function _tagcode_sub_root() { |
|---|
| 80 | //top level types |
|---|
| 81 | return array('esc_rsqbr','esc_lsqbr','tag_inline','tag_open','tag_close','text'); |
|---|
| 82 | } |
|---|
| 83 | function _tagcode_sub_tag_inline() { |
|---|
| 84 | return array('attr','name'); |
|---|
| 85 | } |
|---|
| 86 | function _tagcode_sub_tag_open() { |
|---|
| 87 | return array('attr','name'); |
|---|
| 88 | } |
|---|
| 89 | function _tagcode_sub_tag_close() { |
|---|
| 90 | return array('name'); |
|---|
| 91 | } |
|---|
| 92 | function _tagcode_sub_text() { |
|---|
| 93 | return null; |
|---|
| 94 | } |
|---|
| 95 | function _tagcode_sub_name() { |
|---|
| 96 | return null; |
|---|
| 97 | } |
|---|
| 98 | function _tagcode_sub_attr() { |
|---|
| 99 | return array('name','literal'); |
|---|
| 100 | } |
|---|
| 101 | function _tagcode_sub_literal() { |
|---|
| 102 | return null; |
|---|
| 103 | //return array('char_ref','entity_ref','char_str'); |
|---|
| 104 | } |
|---|
| 105 | function _tagcode_sub_char_str() { |
|---|
| 106 | return null; |
|---|
| 107 | } |
|---|
| 108 | function _tagcode_sub_char_ref() { |
|---|
| 109 | return null; |
|---|
| 110 | } |
|---|
| 111 | function _tagcode_sub_entity_ref() { |
|---|
| 112 | return null; |
|---|
| 113 | } |
|---|
| 114 | function _tagcode_sub_esc_lsqbr() { |
|---|
| 115 | return null; |
|---|
| 116 | } |
|---|
| 117 | function _tagcode_sub_esc_rsqbr() { |
|---|
| 118 | return null; |
|---|
| 119 | } |
|---|
| 120 | |
|---|
| 121 | /** |
|---|
| 122 | * returns subtypes of expression type |
|---|
| 123 | */ |
|---|
| 124 | function _tagcode_sub($type='root') { |
|---|
| 125 | if (in_array($type,_tagcode_types()) || $type == 'root') { |
|---|
| 126 | $func = "_tagcode_sub_{$type}"; |
|---|
| 127 | $subtypes = call_user_func($func); |
|---|
| 128 | } |
|---|
| 129 | return $subtypes; |
|---|
| 130 | } |
|---|
| 131 | |
|---|
| 132 | /** |
|---|
| 133 | * regular expressions to match valid expressions |
|---|
| 134 | */ |
|---|
| 135 | function _tagcode_re_name($named=false) { |
|---|
| 136 | $expr = '[A-Za-z][-A-Za-z0-9_:.]*'; |
|---|
| 137 | return $named?"(?P<name>{$expr})":$expr; |
|---|
| 138 | } |
|---|
| 139 | function _tagcode_re_registered_name($named=false) { |
|---|
| 140 | global $_tagcode_register; |
|---|
| 141 | $tags = join("|",array_map('preg_quote',array_keys($_tagcode_register))); |
|---|
| 142 | if (strlen($tags) === 0) { |
|---|
| 143 | //to guarantee failure in the instance there are no registered tagcodes |
|---|
| 144 | $expr = '$^'; |
|---|
| 145 | } else { |
|---|
| 146 | $name = _tagcode_re_name(); |
|---|
| 147 | $expr = "{$name}(?<={$tags})"; |
|---|
| 148 | } |
|---|
| 149 | return $named?"(?P<name>{$expr})":$expr; |
|---|
| 150 | } |
|---|
| 151 | function _tagcode_re_char_str($named=false) { |
|---|
| 152 | $expr = "[^%&]+"; |
|---|
| 153 | return $named?"(?P<char_str>{$expr})":$expr; |
|---|
| 154 | } |
|---|
| 155 | function _tagcode_re_char_str_sq($named=false) { |
|---|
| 156 | //single quote version for shortcode_re_char_str |
|---|
| 157 | $expr = "[^%&']+"; |
|---|
| 158 | return $named?"(?P<char_str>{$expr})":$expr; |
|---|
| 159 | } |
|---|
| 160 | function _tagcode_re_char_str_dq($named=false) { |
|---|
| 161 | //double quote version for shortcode_re_char_str |
|---|
| 162 | $expr = '[^%&"]+'; |
|---|
| 163 | return $named?"(?P<char_str>{$expr})":$expr; |
|---|
| 164 | } |
|---|
| 165 | function _tagcode_re_char_ref($named=false) { |
|---|
| 166 | $expr = "&#(?:[0-9]+|x[0-9a-fA-F]+);"; |
|---|
| 167 | return $named?"(?P<char_ref>{$expr})":$expr; |
|---|
| 168 | } |
|---|
| 169 | function _tagcode_re_entity_ref($named=false) { |
|---|
| 170 | $name = _tagcode_re_name(); |
|---|
| 171 | $expr = "&{$name};"; |
|---|
| 172 | return $named?"(?P<entity_ref>{$expr})":$expr; |
|---|
| 173 | } |
|---|
| 174 | function _tagcode_re_literal($named=false) { |
|---|
| 175 | $nq = _tagcode_re_literal_nq(); |
|---|
| 176 | $sq = _tagcode_re_literal_sq(); |
|---|
| 177 | $dq = _tagcode_re_literal_dq(); |
|---|
| 178 | $expr = "(?:{$nq}|{$sq}|{$dq})"; |
|---|
| 179 | return $named?"(?P<literal>{$expr})":$expr; |
|---|
| 180 | } |
|---|
| 181 | function _tagcode_re_literal_nq() { |
|---|
| 182 | //literal without quotes |
|---|
| 183 | $expr = "[-a-zA-Z0-9_:.]+"; |
|---|
| 184 | return $expr; |
|---|
| 185 | } |
|---|
| 186 | function _tagcode_re_literal_sq() { |
|---|
| 187 | //literal with single quotes |
|---|
| 188 | $char_str = _tagcode_re_char_str_sq(); |
|---|
| 189 | $char_ref = _tagcode_re_char_ref(); |
|---|
| 190 | $entity_ref = _tagcode_re_entity_ref(); |
|---|
| 191 | $expr = "'(?:{$char_str}|{$char_ref}|{$entity_ref})*'"; |
|---|
| 192 | return $expr; |
|---|
| 193 | } |
|---|
| 194 | function _tagcode_re_literal_dq() { |
|---|
| 195 | //literal with double quotes |
|---|
| 196 | $char_str = _tagcode_re_char_str_dq(); |
|---|
| 197 | $char_ref = _tagcode_re_char_ref(); |
|---|
| 198 | $entity_ref = _tagcode_re_entity_ref(); |
|---|
| 199 | $expr = "\"(?:{$char_str}|{$char_ref}|{$entity_ref})*\""; |
|---|
| 200 | return $expr; |
|---|
| 201 | } |
|---|
| 202 | function _tagcode_re_attr($named=false) { |
|---|
| 203 | $name = _tagcode_re_name(); |
|---|
| 204 | $literal = _tagcode_re_literal(); |
|---|
| 205 | $expr = "(?<!^){$name}(?:={$literal})?"; |
|---|
| 206 | return $named?"(?P<attr>{$expr})":$expr; |
|---|
| 207 | } |
|---|
| 208 | function _tagcode_re_esc_lsqbr($named=false) { |
|---|
| 209 | $expr = "\\[\\["; |
|---|
| 210 | return $named?"(?P<esc_lsqbr>{$expr})":$expr; |
|---|
| 211 | } |
|---|
| 212 | function _tagcode_re_esc_rsqbr($named=false) { |
|---|
| 213 | //two right square brackets not immediately followed by an odd number of sequential right square brackets |
|---|
| 214 | $expr = '\]\](?=(?:\]\])*(?!\]))'; |
|---|
| 215 | return $named?"(?P<esc_rsqbr>{$expr})":$expr; |
|---|
| 216 | } |
|---|
| 217 | function _tagcode_re_tag_inline($named=false) { |
|---|
| 218 | $name = _tagcode_re_registered_name(); |
|---|
| 219 | $attr = _tagcode_re_attr(); |
|---|
| 220 | $expr = "{$name}(?:\\s+{$attr})*"; |
|---|
| 221 | return $named?"\\[(?P<tag_inline>{$expr})\\s*\\/\\]":"\\[{$expr}\\s*\\/\\]"; |
|---|
| 222 | } |
|---|
| 223 | function _tagcode_re_tag_open($named=false) { |
|---|
| 224 | $name = _tagcode_re_registered_name(); |
|---|
| 225 | $attr = _tagcode_re_attr(); |
|---|
| 226 | $expr = "{$name}(?:\\s+{$attr})*"; |
|---|
| 227 | return $named?"\\[(?P<tag_open>{$expr})\\s*\\]":"\\[{$expr}\\s*\\]"; |
|---|
| 228 | } |
|---|
| 229 | function _tagcode_re_tag_close($named=false) { |
|---|
| 230 | $name = _tagcode_re_registered_name(); |
|---|
| 231 | $expr = $name; |
|---|
| 232 | return $named?"\\[\\/(?P<tag_close>{$expr})\\s*\\]":"\\[\\/{$expr}\\s*\\]"; |
|---|
| 233 | } |
|---|
| 234 | function _tagcode_re_text($named=false) { |
|---|
| 235 | $expr = '(?s:.[^\[\]]*)'; |
|---|
| 236 | return $named?"(?P<text>{$expr})":$expr; |
|---|
| 237 | } |
|---|
| 238 | |
|---|
| 239 | /** |
|---|
| 240 | * combines shortcode regex of types specified in parameters, returns delimited regex |
|---|
| 241 | */ |
|---|
| 242 | function _tagcode_re_combine() { |
|---|
| 243 | $types = func_get_args(); |
|---|
| 244 | |
|---|
| 245 | $regexps = array(); |
|---|
| 246 | foreach ($types as $type) { |
|---|
| 247 | $re_func = "_tagcode_re_{$type}"; |
|---|
| 248 | array_push($regexps,call_user_func($re_func,1)); |
|---|
| 249 | } |
|---|
| 250 | $statement = '/' . join('|',$regexps) . '/'; |
|---|
| 251 | return $statement; |
|---|
| 252 | } |
|---|
| 253 | |
|---|
| 254 | /** |
|---|
| 255 | * returns regular expression to match subtypes of an expression (ex. attr => {$name}={$literal}) |
|---|
| 256 | */ |
|---|
| 257 | function _tagcode_re_subtypes($type) { |
|---|
| 258 | $subtypes = _tagcode_sub($type); |
|---|
| 259 | $re = null; |
|---|
| 260 | if (count($subtypes)) { |
|---|
| 261 | $re = call_user_func_array('_tagcode_re_combine',$subtypes); |
|---|
| 262 | } |
|---|
| 263 | return $re; |
|---|
| 264 | } |
|---|
| 265 | |
|---|
| 266 | /** |
|---|
| 267 | * evaluation of different tagcode expressions |
|---|
| 268 | */ |
|---|
| 269 | function _tagcode_eval_name($name) { |
|---|
| 270 | return strtolower($name['expression']); |
|---|
| 271 | } |
|---|
| 272 | function _tagcode_eval_char_str($char_str) { |
|---|
| 273 | return $char_str['expression']; |
|---|
| 274 | } |
|---|
| 275 | function _tagcode_eval_char_ref($char_ref) { |
|---|
| 276 | //Not sure if this is the proper way to handle char_refs. |
|---|
| 277 | //I'm doing this rather than running html_entity_decode on a full string |
|---|
| 278 | //because I don't understand html_entity_decode's argument for a |
|---|
| 279 | //character set. Which also means that this code is probably incorrect. |
|---|
| 280 | $expr = $char_ref['expression']; |
|---|
| 281 | if ($expr[0] == 'x') { |
|---|
| 282 | $expr = hexdec($expr); |
|---|
| 283 | } |
|---|
| 284 | $expr = chr($expr); |
|---|
| 285 | return $expr; |
|---|
| 286 | } |
|---|
| 287 | function _tagcode_eval_entity_ref($entity_ref) { |
|---|
| 288 | $expr = strtolower($entity_ref['expression']); |
|---|
| 289 | $lookup = array_flip(get_html_translation_table(HTML_ENTITIES)); |
|---|
| 290 | return $lookup[$expr]; |
|---|
| 291 | } |
|---|
| 292 | function _tagcode_eval_literal($literal) { |
|---|
| 293 | //$expr = ""; |
|---|
| 294 | //foreach ($literal['children'] as $child) { |
|---|
| 295 | // $eval_func = "_tagcode_eval_{$child['type']}"; |
|---|
| 296 | // $expr .= call_user_func($eval_func,$child); |
|---|
| 297 | //} |
|---|
| 298 | $expr = $literal['expression']; |
|---|
| 299 | $expr = html_entity_decode($expr); |
|---|
| 300 | if ($expr[0] == "'" || $expr[0] == '"') { |
|---|
| 301 | $expr = substr($expr,1,strlen($expr)-2); |
|---|
| 302 | } |
|---|
| 303 | return $expr; |
|---|
| 304 | } |
|---|
| 305 | function _tagcode_eval_attr($attr) { |
|---|
| 306 | $children = $attr['children']; |
|---|
| 307 | $key = _tagcode_eval_name($children[0]); |
|---|
| 308 | if (isset($children[1])) { |
|---|
| 309 | $value = _tagcode_eval_literal($children[1]); |
|---|
| 310 | } else { |
|---|
| 311 | $value = $key; |
|---|
| 312 | } |
|---|
| 313 | return array('key' => $key, 'value' => $value); |
|---|
| 314 | } |
|---|
| 315 | function _tagcode_eval_esc_lsqbr($esc_lsqbr,&$stack) { |
|---|
| 316 | $node = array_pop($stack); |
|---|
| 317 | $node['content'] .= "["; |
|---|
| 318 | array_push($stack,$node); |
|---|
| 319 | return $node; |
|---|
| 320 | } |
|---|
| 321 | function _tagcode_eval_esc_rsqbr($esc_rsqbr,&$stack) { |
|---|
| 322 | $node = array_pop($stack); |
|---|
| 323 | $node['content'] .= "]"; |
|---|
| 324 | array_push($stack,$node); |
|---|
| 325 | return $node; |
|---|
| 326 | } |
|---|
| 327 | function _tagcode_eval_tag_inline($tag_inline,&$stack) { |
|---|
| 328 | $children = $tag_inline['children']; |
|---|
| 329 | $name = _tagcode_eval_name($children[0]); |
|---|
| 330 | $attrs = array(); |
|---|
| 331 | foreach ($children as $child) { |
|---|
| 332 | if ($child['type'] == 'attr') { |
|---|
| 333 | $attr = _tagcode_eval_attr($child); |
|---|
| 334 | $key = $attr['key']; |
|---|
| 335 | $value = $attr['value']; |
|---|
| 336 | $attrs[$key] = $value; |
|---|
| 337 | } |
|---|
| 338 | } |
|---|
| 339 | $content = apply_tagcodes($name,'',$attrs); |
|---|
| 340 | // adds evaluated content to next on the stack |
|---|
| 341 | $node = array_pop($stack); |
|---|
| 342 | $node['content'] .= $content; |
|---|
| 343 | array_push($stack,$node); |
|---|
| 344 | return $node; |
|---|
| 345 | } |
|---|
| 346 | function _tagcode_eval_tag_open($tag_open,&$stack,&$refs) { |
|---|
| 347 | $children = $tag_open['children']; |
|---|
| 348 | $name = _tagcode_eval_name($children[0]); |
|---|
| 349 | $attrs = array(); |
|---|
| 350 | foreach ($children as $child) { |
|---|
| 351 | if ($child['type'] == 'attr') { |
|---|
| 352 | $attr = _tagcode_eval_attr($child); |
|---|
| 353 | $key = $attr['key']; |
|---|
| 354 | $value = $attr['value']; |
|---|
| 355 | $attrs[$key] = $value; |
|---|
| 356 | } |
|---|
| 357 | } |
|---|
| 358 | $data = array('name' => $name, 'attrs' => $attrs); |
|---|
| 359 | $node = array('node' => $data, 'content' => ''); |
|---|
| 360 | //throws itself on the stack with attributes, etc. |
|---|
| 361 | array_push($stack,$node); |
|---|
| 362 | $refs[$name] += 1; |
|---|
| 363 | return $node; |
|---|
| 364 | } |
|---|
| 365 | function _tagcode_eval_tag_close($tag_close,&$stack,&$refs) { |
|---|
| 366 | $value = null; |
|---|
| 367 | $name = _tagcode_eval_name($tag_close['children'][0]); |
|---|
| 368 | if ($refs[$name] > 0) { |
|---|
| 369 | do { |
|---|
| 370 | $child = array_pop($stack); |
|---|
| 371 | $child_node = $child['node']; |
|---|
| 372 | $child_name = $child['node']['name']; |
|---|
| 373 | $child_attrs = $child['node']['attrs']; |
|---|
| 374 | $parent = array_pop($stack); |
|---|
| 375 | $parent['content'] .= apply_tagcodes($name,$child['content'],$child_attrs); |
|---|
| 376 | $refs[$name] -= 1; |
|---|
| 377 | array_push($stack,$parent); |
|---|
| 378 | } while ($child_name != $name); |
|---|
| 379 | } |
|---|
| 380 | return array('name' => $name); |
|---|
| 381 | } |
|---|
| 382 | function _tagcode_eval_text($text,&$stack) { |
|---|
| 383 | $node = array_pop($stack); |
|---|
| 384 | $node['content'] .= $text['expression']; |
|---|
| 385 | array_push($stack,$node); |
|---|
| 386 | return $text['expression']; |
|---|
| 387 | } |
|---|
| 388 | function _tagcode_eval($expr) { |
|---|
| 389 | $stack = array(); |
|---|
| 390 | $refs = array(); |
|---|
| 391 | //build parse tree |
|---|
| 392 | $root = _tagcode_build_tree($expr); |
|---|
| 393 | |
|---|
| 394 | //create root content node, throw on stack |
|---|
| 395 | $root_node = array('node' => 'root', 'content' => ''); |
|---|
| 396 | array_push($stack,$root_node); |
|---|
| 397 | //evaluate immediate children |
|---|
| 398 | $subs = _tagcode_sub(); |
|---|
| 399 | foreach ($root['children'] as $child) { |
|---|
| 400 | if (in_array($child['type'],$subs)) { |
|---|
| 401 | $func = "_tagcode_eval_{$child['type']}"; |
|---|
| 402 | switch ($child['type']) { |
|---|
| 403 | case 'tag_inline': |
|---|
| 404 | _tagcode_eval_tag_inline($child,$stack,$refs); |
|---|
| 405 | break; |
|---|
| 406 | case 'tag_open': |
|---|
| 407 | _tagcode_eval_tag_open($child,$stack,$refs); |
|---|
| 408 | break; |
|---|
| 409 | case 'tag_close': |
|---|
| 410 | _tagcode_eval_tag_close($child,$stack,$refs); |
|---|
| 411 | break; |
|---|
| 412 | case 'text': |
|---|
| 413 | _tagcode_eval_text($child,$stack); |
|---|
| 414 | break; |
|---|
| 415 | case 'esc_lsqbr': |
|---|
| 416 | _tagcode_eval_esc_lsqbr($child,$stack); |
|---|
| 417 | break; |
|---|
| 418 | case 'esc_rsqbr': |
|---|
| 419 | _tagcode_eval_esc_rsqbr($child,$stack); |
|---|
| 420 | break; |
|---|
| 421 | default: |
|---|
| 422 | call_user_func($func,$child); |
|---|
| 423 | } |
|---|
| 424 | } |
|---|
| 425 | } |
|---|
| 426 | //evaluate children remaining on stack |
|---|
| 427 | $child = array_pop($stack); |
|---|
| 428 | while ($child['node'] != 'root') { |
|---|
| 429 | $parent = array_pop($stack); |
|---|
| 430 | $child_node = $child['node']; |
|---|
| 431 | $child_name = $child['node']['name']; |
|---|
| 432 | $child_attrs = $child['node']['attrs']; |
|---|
| 433 | $parent['content'] .= apply_tagcodes($child_name,'',$child_attrs); |
|---|
| 434 | $parent['content'] .= $child['content']; |
|---|
| 435 | $child = $parent; |
|---|
| 436 | } |
|---|
| 437 | return $child['content']; |
|---|
| 438 | } |
|---|
| 439 | |
|---|
| 440 | /** |
|---|
| 441 | * builds an expression tree from a tagcode expression |
|---|
| 442 | */ |
|---|
| 443 | function _tagcode_build_tree($parent) { |
|---|
| 444 | if (is_string($parent)) { |
|---|
| 445 | $parent = array('type' => 'root', 'expression' => $parent); |
|---|
| 446 | } |
|---|
| 447 | $parent_type = $parent['type']; |
|---|
| 448 | $parent_expression = $parent['expression']; |
|---|
| 449 | $re_subtypes = _tagcode_re_subtypes($parent_type); |
|---|
| 450 | $nodes = array(); |
|---|
| 451 | if ($re_subtypes) { |
|---|
| 452 | $match_set = array(); |
|---|
| 453 | preg_match_all($re_subtypes,$parent_expression,$match_set,PREG_SET_ORDER); |
|---|
| 454 | foreach ($match_set as $index => $match) { |
|---|
| 455 | foreach (_tagcode_types() as $type) { |
|---|
| 456 | if (strlen($match[$type]) > 0) { |
|---|
| 457 | $nodes[$index] = array('type' => $type, 'expression' => $match[$type]); |
|---|
| 458 | } |
|---|
| 459 | } |
|---|
| 460 | } |
|---|
| 461 | } |
|---|
| 462 | $parent['children'] = array_map('_tagcode_build_tree',$nodes); |
|---|
| 463 | return $parent; |
|---|
| 464 | } |
|---|
| 465 | |
|---|
| 466 | add_filter('the_content','eval_tagcodes',11); |
|---|