311
* Search only inside HTML elements for shortcodes and process them.
313
* Any [ or ] characters remaining inside elements will be HTML encoded
314
* to prevent interference with shortcodes that are outside the elements.
315
* Assumes $content processed by KSES already. Users with unfiltered_html
316
* capability may get unexpected output if angle braces are nested in tags.
320
* @param string $content Content to search for shortcodes
321
* @param bool $ignore_html When true, all square braces inside elements will be encoded.
322
* @return string Content with shortcodes filtered out.
324
function do_shortcodes_in_html_tags( $content, $ignore_html ) {
325
// Normalize entities in unfiltered HTML before adding placeholders.
326
$trans = array( '[' => '[', ']' => ']' );
327
$content = strtr( $content, $trans );
328
$trans = array( '[' => '[', ']' => ']' );
330
$pattern = get_shortcode_regex();
333
'!' // Start of comment, after the <.
334
. '(?:' // Unroll the loop: Consume everything until --> is found.
335
. '-(?!->)' // Dash not followed by end of comment.
336
. '[^\-]*+' // Consume non-dashes.
337
. ')*+' // Loop possessively.
338
. '(?:-->)?'; // End of comment. If not found, match all input.
341
'/(' // Capture the entire match.
342
. '<' // Find start of element.
343
. '(?(?=!--)' // Is this a comment?
344
. $comment_regex // Find end of comment.
346
. '[^>]*>?' // Find end of element. If not found, match all input.
350
$textarr = preg_split( $regex, $content, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY );
352
foreach ( $textarr as &$element ) {
353
if ( '<' !== $element[0] ) {
357
$noopen = false === strpos( $element, '[' );
358
$noclose = false === strpos( $element, ']' );
359
if ( $noopen || $noclose ) {
360
// This element does not contain shortcodes.
361
if ( $noopen xor $noclose ) {
362
// Need to encode stray [ or ] chars.
363
$element = strtr( $element, $trans );
368
if ( $ignore_html || '<!--' === substr( $element, 0, 4 ) ) {
369
// Encode all [ and ] chars.
370
$element = strtr( $element, $trans );
374
$attributes = wp_kses_attr_parse( $element );
375
if ( false === $attributes ) {
376
// Looks like we found some crazy unfiltered HTML. Skipping it for sanity.
377
$element = strtr( $element, $trans );
382
$front = array_shift( $attributes );
383
$back = array_pop( $attributes );
385
preg_match('%[a-zA-Z0-9]+%', $front, $matches);
386
$elname = $matches[0];
388
// Look for shortcodes in each attribute separately.
389
foreach ( $attributes as &$attr ) {
390
$open = strpos( $attr, '[' );
391
$close = strpos( $attr, ']' );
392
if ( false === $open || false === $close ) {
393
continue; // Go to next attribute. Square braces will be escaped at end of loop.
395
$double = strpos( $attr, '"' );
396
$single = strpos( $attr, "'" );
397
if ( ( false === $single || $open < $single ) && ( false === $double || $open < $double ) ) {
398
// $attr like '[shortcode]' or 'name = [shortcode]' implies unfiltered_html.
399
// In this specific situation we assume KSES did not run because the input
400
// was written by an administrator, so we should avoid changing the output
401
// and we do not need to run KSES here.
402
$attr = preg_replace_callback( "/$pattern/s", 'do_shortcode_tag', $attr );
404
// $attr like 'name = "[shortcode]"' or "name = '[shortcode]'"
405
// We do not know if $content was unfiltered. Assume KSES ran before shortcodes.
407
$new_attr = preg_replace_callback( "/$pattern/s", 'do_shortcode_tag', $attr, -1, $count );
409
// Sanitize the shortcode output using KSES.
410
$new_attr = wp_kses_one_attr( $new_attr, $elname );
411
if ( '' !== $new_attr ) {
412
// The shortcode is safe to use now.
418
$element = $front . implode( '', $attributes ) . $back;
420
// Now encode any remaining [ or ] chars.
421
$element = strtr( $element, $trans );
424
$content = implode( '', $textarr );
430
* Remove placeholders added by do_shortcodes_in_html_tags().
434
* @param string $content Content to search for placeholders.
435
* @return string Content with placeholders removed.
437
function unescape_invalid_shortcodes( $content ) {
438
// Clean up entire string, avoids re-parsing HTML.
439
$trans = array( '[' => '[', ']' => ']' );
440
$content = strtr( $content, $trans );
294
446
* Retrieve all attributes from the shortcodes tag.
296
448
* The attributes list has the attribute name as the key and the value of the