wp/wp-includes/shortcodes.php
changeset 16 a86126ab1dd4
parent 9 177826044cd9
child 18 be944660c56a
equal deleted inserted replaced
15:3d4e9c994f10 16:a86126ab1dd4
    21  *
    21  *
    22  * To apply shortcode tags to content:
    22  * To apply shortcode tags to content:
    23  *
    23  *
    24  *     $out = do_shortcode( $content );
    24  *     $out = do_shortcode( $content );
    25  *
    25  *
    26  * @link https://codex.wordpress.org/Shortcode_API
    26  * @link https://developer.wordpress.org/plugins/shortcodes/
    27  *
    27  *
    28  * @package WordPress
    28  * @package WordPress
    29  * @subpackage Shortcodes
    29  * @subpackage Shortcodes
    30  * @since 2.5.0
    30  * @since 2.5.0
    31  */
    31  */
    61  *                           itself (`$shortcode_tag`), in that order.
    61  *                           itself (`$shortcode_tag`), in that order.
    62  */
    62  */
    63 function add_shortcode( $tag, $callback ) {
    63 function add_shortcode( $tag, $callback ) {
    64 	global $shortcode_tags;
    64 	global $shortcode_tags;
    65 
    65 
    66 	if ( '' == trim( $tag ) ) {
    66 	if ( '' === trim( $tag ) ) {
    67 		$message = __( 'Invalid shortcode name: Empty name given.' );
    67 		$message = __( 'Invalid shortcode name: Empty name given.' );
    68 		_doing_it_wrong( __FUNCTION__, $message, '4.4.0' );
    68 		_doing_it_wrong( __FUNCTION__, $message, '4.4.0' );
    69 		return;
    69 		return;
    70 	}
    70 	}
    71 
    71 
    72 	if ( 0 !== preg_match( '@[<>&/\[\]\x00-\x20=]@', $tag ) ) {
    72 	if ( 0 !== preg_match( '@[<>&/\[\]\x00-\x20=]@', $tag ) ) {
    73 		/* translators: 1: shortcode name, 2: space separated list of reserved characters */
    73 		/* translators: 1: Shortcode name, 2: Space-separated list of reserved characters. */
    74 		$message = sprintf( __( 'Invalid shortcode name: %1$s. Do not use spaces or reserved characters: %2$s' ), $tag, '& / < > [ ] =' );
    74 		$message = sprintf( __( 'Invalid shortcode name: %1$s. Do not use spaces or reserved characters: %2$s' ), $tag, '& / < > [ ] =' );
    75 		_doing_it_wrong( __FUNCTION__, $message, '4.4.0' );
    75 		_doing_it_wrong( __FUNCTION__, $message, '4.4.0' );
    76 		return;
    76 		return;
    77 	}
    77 	}
    78 
    78 
   160 }
   160 }
   161 
   161 
   162 /**
   162 /**
   163  * Search content for shortcodes and filter shortcodes through their hooks.
   163  * Search content for shortcodes and filter shortcodes through their hooks.
   164  *
   164  *
       
   165  * This function is an alias for do_shortcode().
       
   166  *
       
   167  * @since 5.4.0
       
   168  *
       
   169  * @see do_shortcode()
       
   170  *
       
   171  * @param string $content     Content to search for shortcodes.
       
   172  * @param bool   $ignore_html When true, shortcodes inside HTML elements will be skipped.
       
   173  *                            Default false.
       
   174  * @return string Content with shortcodes filtered out.
       
   175  */
       
   176 function apply_shortcodes( $content, $ignore_html = false ) {
       
   177 	return do_shortcode( $content, $ignore_html );
       
   178 }
       
   179 
       
   180 /**
       
   181  * Search content for shortcodes and filter shortcodes through their hooks.
       
   182  *
   165  * If there are no shortcode tags defined, then the content will be returned
   183  * If there are no shortcode tags defined, then the content will be returned
   166  * without any filtering. This might cause issues when plugins are disabled but
   184  * without any filtering. This might cause issues when plugins are disabled but
   167  * the shortcode will still show up in the post or content.
   185  * the shortcode will still show up in the post or content.
   168  *
   186  *
   169  * @since 2.5.0
   187  * @since 2.5.0
   170  *
   188  *
   171  * @global array $shortcode_tags List of shortcode tags and their callback hooks.
   189  * @global array $shortcode_tags List of shortcode tags and their callback hooks.
   172  *
   190  *
   173  * @param string $content Content to search for shortcodes.
   191  * @param string $content     Content to search for shortcodes.
   174  * @param bool $ignore_html When true, shortcodes inside HTML elements will be skipped.
   192  * @param bool   $ignore_html When true, shortcodes inside HTML elements will be skipped.
       
   193  *                            Default false.
   175  * @return string Content with shortcodes filtered out.
   194  * @return string Content with shortcodes filtered out.
   176  */
   195  */
   177 function do_shortcode( $content, $ignore_html = false ) {
   196 function do_shortcode( $content, $ignore_html = false ) {
   178 	global $shortcode_tags;
   197 	global $shortcode_tags;
   179 
   198 
   196 	$content = do_shortcodes_in_html_tags( $content, $ignore_html, $tagnames );
   215 	$content = do_shortcodes_in_html_tags( $content, $ignore_html, $tagnames );
   197 
   216 
   198 	$pattern = get_shortcode_regex( $tagnames );
   217 	$pattern = get_shortcode_regex( $tagnames );
   199 	$content = preg_replace_callback( "/$pattern/", 'do_shortcode_tag', $content );
   218 	$content = preg_replace_callback( "/$pattern/", 'do_shortcode_tag', $content );
   200 
   219 
   201 	// Always restore square braces so we don't break things like <!--[if IE ]>
   220 	// Always restore square braces so we don't break things like <!--[if IE ]>.
   202 	$content = unescape_invalid_shortcodes( $content );
   221 	$content = unescape_invalid_shortcodes( $content );
   203 
   222 
   204 	return $content;
   223 	return $content;
   205 }
   224 }
   206 
   225 
   233 	if ( empty( $tagnames ) ) {
   252 	if ( empty( $tagnames ) ) {
   234 		$tagnames = array_keys( $shortcode_tags );
   253 		$tagnames = array_keys( $shortcode_tags );
   235 	}
   254 	}
   236 	$tagregexp = join( '|', array_map( 'preg_quote', $tagnames ) );
   255 	$tagregexp = join( '|', array_map( 'preg_quote', $tagnames ) );
   237 
   256 
   238 	// WARNING! Do not change this regex without changing do_shortcode_tag() and strip_shortcode_tag()
   257 	// WARNING! Do not change this regex without changing do_shortcode_tag() and strip_shortcode_tag().
   239 	// Also, see shortcode_unautop() and shortcode.js.
   258 	// Also, see shortcode_unautop() and shortcode.js.
   240 
   259 
   241 	// phpcs:disable Squiz.Strings.ConcatenationSpacing.PaddingFound -- don't remove regex indentation
   260 	// phpcs:disable Squiz.Strings.ConcatenationSpacing.PaddingFound -- don't remove regex indentation
   242 	return
   261 	return '\\['                             // Opening bracket.
   243 		'\\['                                // Opening bracket
   262 		. '(\\[?)'                           // 1: Optional second opening bracket for escaping shortcodes: [[tag]].
   244 		. '(\\[?)'                           // 1: Optional second opening bracket for escaping shortcodes: [[tag]]
   263 		. "($tagregexp)"                     // 2: Shortcode name.
   245 		. "($tagregexp)"                     // 2: Shortcode name
   264 		. '(?![\\w-])'                       // Not followed by word character or hyphen.
   246 		. '(?![\\w-])'                       // Not followed by word character or hyphen
   265 		. '('                                // 3: Unroll the loop: Inside the opening shortcode tag.
   247 		. '('                                // 3: Unroll the loop: Inside the opening shortcode tag
   266 		.     '[^\\]\\/]*'                   // Not a closing bracket or forward slash.
   248 		.     '[^\\]\\/]*'                   // Not a closing bracket or forward slash
       
   249 		.     '(?:'
   267 		.     '(?:'
   250 		.         '\\/(?!\\])'               // A forward slash not followed by a closing bracket
   268 		.         '\\/(?!\\])'               // A forward slash not followed by a closing bracket.
   251 		.         '[^\\]\\/]*'               // Not a closing bracket or forward slash
   269 		.         '[^\\]\\/]*'               // Not a closing bracket or forward slash.
   252 		.     ')*?'
   270 		.     ')*?'
   253 		. ')'
   271 		. ')'
   254 		. '(?:'
   272 		. '(?:'
   255 		.     '(\\/)'                        // 4: Self closing tag ...
   273 		.     '(\\/)'                        // 4: Self closing tag...
   256 		.     '\\]'                          // ... and closing bracket
   274 		.     '\\]'                          // ...and closing bracket.
   257 		. '|'
   275 		. '|'
   258 		.     '\\]'                          // Closing bracket
   276 		.     '\\]'                          // Closing bracket.
   259 		.     '(?:'
   277 		.     '(?:'
   260 		.         '('                        // 5: Unroll the loop: Optionally, anything between the opening and closing shortcode tags
   278 		.         '('                        // 5: Unroll the loop: Optionally, anything between the opening and closing shortcode tags.
   261 		.             '[^\\[]*+'             // Not an opening bracket
   279 		.             '[^\\[]*+'             // Not an opening bracket.
   262 		.             '(?:'
   280 		.             '(?:'
   263 		.                 '\\[(?!\\/\\2\\])' // An opening bracket not followed by the closing shortcode tag
   281 		.                 '\\[(?!\\/\\2\\])' // An opening bracket not followed by the closing shortcode tag.
   264 		.                 '[^\\[]*+'         // Not an opening bracket
   282 		.                 '[^\\[]*+'         // Not an opening bracket.
   265 		.             ')*+'
   283 		.             ')*+'
   266 		.         ')'
   284 		.         ')'
   267 		.         '\\[\\/\\2\\]'             // Closing shortcode tag
   285 		.         '\\[\\/\\2\\]'             // Closing shortcode tag.
   268 		.     ')?'
   286 		.     ')?'
   269 		. ')'
   287 		. ')'
   270 		. '(\\]?)';                          // 6: Optional second closing brocket for escaping shortcodes: [[tag]]
   288 		. '(\\]?)';                          // 6: Optional second closing brocket for escaping shortcodes: [[tag]].
   271 	// phpcs:enable
   289 	// phpcs:enable
   272 }
   290 }
   273 
   291 
   274 /**
   292 /**
   275  * Regular Expression callable for do_shortcode() for calling shortcode hook.
   293  * Regular Expression callable for do_shortcode() for calling shortcode hook.
   285  * @return string|false False on failure.
   303  * @return string|false False on failure.
   286  */
   304  */
   287 function do_shortcode_tag( $m ) {
   305 function do_shortcode_tag( $m ) {
   288 	global $shortcode_tags;
   306 	global $shortcode_tags;
   289 
   307 
   290 	// allow [[foo]] syntax for escaping a tag
   308 	// Allow [[foo]] syntax for escaping a tag.
   291 	if ( $m[1] == '[' && $m[6] == ']' ) {
   309 	if ( '[' === $m[1] && ']' === $m[6] ) {
   292 		return substr( $m[0], 1, -1 );
   310 		return substr( $m[0], 1, -1 );
   293 	}
   311 	}
   294 
   312 
   295 	$tag  = $m[2];
   313 	$tag  = $m[2];
   296 	$attr = shortcode_parse_atts( $m[3] );
   314 	$attr = shortcode_parse_atts( $m[3] );
   297 
   315 
   298 	if ( ! is_callable( $shortcode_tags[ $tag ] ) ) {
   316 	if ( ! is_callable( $shortcode_tags[ $tag ] ) ) {
   299 		/* translators: %s: shortcode tag */
   317 		/* translators: %s: Shortcode tag. */
   300 		$message = sprintf( __( 'Attempting to parse a shortcode without a valid callback: %s' ), $tag );
   318 		$message = sprintf( __( 'Attempting to parse a shortcode without a valid callback: %s' ), $tag );
   301 		_doing_it_wrong( __FUNCTION__, $message, '4.3.0' );
   319 		_doing_it_wrong( __FUNCTION__, $message, '4.3.0' );
   302 		return $m[0];
   320 		return $m[0];
   303 	}
   321 	}
   304 
   322 
   305 	/**
   323 	/**
   306 	 * Filters whether to call a shortcode callback.
   324 	 * Filters whether to call a shortcode callback.
   307 	 *
   325 	 *
   308 	 * Passing a truthy value to the filter will effectively short-circuit the
   326 	 * Returning a non-false value from filter will short-circuit the
   309 	 * shortcode generation process, returning that value instead.
   327 	 * shortcode generation process, returning that value instead.
   310 	 *
   328 	 *
   311 	 * @since 4.7.0
   329 	 * @since 4.7.0
   312 	 *
   330 	 *
   313 	 * @param bool|string $return      Short-circuit return value. Either false or the value to replace the shortcode with.
   331 	 * @param false|string $return      Short-circuit return value. Either false or the value to replace the shortcode with.
   314 	 * @param string       $tag         Shortcode name.
   332 	 * @param string       $tag         Shortcode name.
   315 	 * @param array|string $attr        Shortcode attributes array or empty string.
   333 	 * @param array|string $attr        Shortcode attributes array or empty string.
   316 	 * @param array        $m           Regular expression match array.
   334 	 * @param array        $m           Regular expression match array.
   317 	 */
   335 	 */
   318 	$return = apply_filters( 'pre_do_shortcode_tag', false, $tag, $attr, $m );
   336 	$return = apply_filters( 'pre_do_shortcode_tag', false, $tag, $attr, $m );
   345  * Assumes $content processed by KSES already.  Users with unfiltered_html
   363  * Assumes $content processed by KSES already.  Users with unfiltered_html
   346  * capability may get unexpected output if angle braces are nested in tags.
   364  * capability may get unexpected output if angle braces are nested in tags.
   347  *
   365  *
   348  * @since 4.2.3
   366  * @since 4.2.3
   349  *
   367  *
   350  * @param string $content Content to search for shortcodes
   368  * @param string $content     Content to search for shortcodes.
   351  * @param bool $ignore_html When true, all square braces inside elements will be encoded.
   369  * @param bool   $ignore_html When true, all square braces inside elements will be encoded.
   352  * @param array $tagnames List of shortcodes to find.
   370  * @param array  $tagnames    List of shortcodes to find.
   353  * @return string Content with shortcodes filtered out.
   371  * @return string Content with shortcodes filtered out.
   354  */
   372  */
   355 function do_shortcodes_in_html_tags( $content, $ignore_html, $tagnames ) {
   373 function do_shortcodes_in_html_tags( $content, $ignore_html, $tagnames ) {
   356 	// Normalize entities in unfiltered HTML before adding placeholders.
   374 	// Normalize entities in unfiltered HTML before adding placeholders.
   357 	$trans   = array(
   375 	$trans   = array(
   366 
   384 
   367 	$pattern = get_shortcode_regex( $tagnames );
   385 	$pattern = get_shortcode_regex( $tagnames );
   368 	$textarr = wp_html_split( $content );
   386 	$textarr = wp_html_split( $content );
   369 
   387 
   370 	foreach ( $textarr as &$element ) {
   388 	foreach ( $textarr as &$element ) {
   371 		if ( '' == $element || '<' !== $element[0] ) {
   389 		if ( '' === $element || '<' !== $element[0] ) {
   372 			continue;
   390 			continue;
   373 		}
   391 		}
   374 
   392 
   375 		$noopen  = false === strpos( $element, '[' );
   393 		$noopen  = false === strpos( $element, '[' );
   376 		$noclose = false === strpos( $element, ']' );
   394 		$noclose = false === strpos( $element, ']' );
   377 		if ( $noopen || $noclose ) {
   395 		if ( $noopen || $noclose ) {
   378 			// This element does not contain shortcodes.
   396 			// This element does not contain shortcodes.
   379 			if ( $noopen xor $noclose ) {
   397 			if ( $noopen xor $noclose ) {
   380 				// Need to encode stray [ or ] chars.
   398 				// Need to encode stray '[' or ']' chars.
   381 				$element = strtr( $element, $trans );
   399 				$element = strtr( $element, $trans );
   382 			}
   400 			}
   383 			continue;
   401 			continue;
   384 		}
   402 		}
   385 
   403 
   386 		if ( $ignore_html || '<!--' === substr( $element, 0, 4 ) || '<![CDATA[' === substr( $element, 0, 9 ) ) {
   404 		if ( $ignore_html || '<!--' === substr( $element, 0, 4 ) || '<![CDATA[' === substr( $element, 0, 9 ) ) {
   387 			// Encode all [ and ] chars.
   405 			// Encode all '[' and ']' chars.
   388 			$element = strtr( $element, $trans );
   406 			$element = strtr( $element, $trans );
   389 			continue;
   407 			continue;
   390 		}
   408 		}
   391 
   409 
   392 		$attributes = wp_kses_attr_parse( $element );
   410 		$attributes = wp_kses_attr_parse( $element );
   394 			// Some plugins are doing things like [name] <[email]>.
   412 			// Some plugins are doing things like [name] <[email]>.
   395 			if ( 1 === preg_match( '%^<\s*\[\[?[^\[\]]+\]%', $element ) ) {
   413 			if ( 1 === preg_match( '%^<\s*\[\[?[^\[\]]+\]%', $element ) ) {
   396 				$element = preg_replace_callback( "/$pattern/", 'do_shortcode_tag', $element );
   414 				$element = preg_replace_callback( "/$pattern/", 'do_shortcode_tag', $element );
   397 			}
   415 			}
   398 
   416 
   399 			// Looks like we found some crazy unfiltered HTML.  Skipping it for sanity.
   417 			// Looks like we found some crazy unfiltered HTML. Skipping it for sanity.
   400 			$element = strtr( $element, $trans );
   418 			$element = strtr( $element, $trans );
   401 			continue;
   419 			continue;
   402 		}
   420 		}
   403 
   421 
   404 		// Get element name
   422 		// Get element name.
   405 		$front   = array_shift( $attributes );
   423 		$front   = array_shift( $attributes );
   406 		$back    = array_pop( $attributes );
   424 		$back    = array_pop( $attributes );
   407 		$matches = array();
   425 		$matches = array();
   408 		preg_match( '%[a-zA-Z0-9]+%', $front, $matches );
   426 		preg_match( '%[a-zA-Z0-9]+%', $front, $matches );
   409 		$elname = $matches[0];
   427 		$elname = $matches[0];
   411 		// Look for shortcodes in each attribute separately.
   429 		// Look for shortcodes in each attribute separately.
   412 		foreach ( $attributes as &$attr ) {
   430 		foreach ( $attributes as &$attr ) {
   413 			$open  = strpos( $attr, '[' );
   431 			$open  = strpos( $attr, '[' );
   414 			$close = strpos( $attr, ']' );
   432 			$close = strpos( $attr, ']' );
   415 			if ( false === $open || false === $close ) {
   433 			if ( false === $open || false === $close ) {
   416 				continue; // Go to next attribute.  Square braces will be escaped at end of loop.
   434 				continue; // Go to next attribute. Square braces will be escaped at end of loop.
   417 			}
   435 			}
   418 			$double = strpos( $attr, '"' );
   436 			$double = strpos( $attr, '"' );
   419 			$single = strpos( $attr, "'" );
   437 			$single = strpos( $attr, "'" );
   420 			if ( ( false === $single || $open < $single ) && ( false === $double || $open < $double ) ) {
   438 			if ( ( false === $single || $open < $single ) && ( false === $double || $open < $double ) ) {
   421 				// $attr like '[shortcode]' or 'name = [shortcode]' implies unfiltered_html.
   439 				/*
   422 				// In this specific situation we assume KSES did not run because the input
   440 				 * $attr like '[shortcode]' or 'name = [shortcode]' implies unfiltered_html.
   423 				// was written by an administrator, so we should avoid changing the output
   441 				 * In this specific situation we assume KSES did not run because the input
   424 				// and we do not need to run KSES here.
   442 				 * was written by an administrator, so we should avoid changing the output
       
   443 				 * and we do not need to run KSES here.
       
   444 				 */
   425 				$attr = preg_replace_callback( "/$pattern/", 'do_shortcode_tag', $attr );
   445 				$attr = preg_replace_callback( "/$pattern/", 'do_shortcode_tag', $attr );
   426 			} else {
   446 			} else {
   427 				// $attr like 'name = "[shortcode]"' or "name = '[shortcode]'"
   447 				// $attr like 'name = "[shortcode]"' or "name = '[shortcode]'".
   428 				// We do not know if $content was unfiltered. Assume KSES ran before shortcodes.
   448 				// We do not know if $content was unfiltered. Assume KSES ran before shortcodes.
   429 				$count    = 0;
   449 				$count    = 0;
   430 				$new_attr = preg_replace_callback( "/$pattern/", 'do_shortcode_tag', $attr, -1, $count );
   450 				$new_attr = preg_replace_callback( "/$pattern/", 'do_shortcode_tag', $attr, -1, $count );
   431 				if ( $count > 0 ) {
   451 				if ( $count > 0 ) {
   432 					// Sanitize the shortcode output using KSES.
   452 					// Sanitize the shortcode output using KSES.
   438 				}
   458 				}
   439 			}
   459 			}
   440 		}
   460 		}
   441 		$element = $front . implode( '', $attributes ) . $back;
   461 		$element = $front . implode( '', $attributes ) . $back;
   442 
   462 
   443 		// Now encode any remaining [ or ] chars.
   463 		// Now encode any remaining '[' or ']' chars.
   444 		$element = strtr( $element, $trans );
   464 		$element = strtr( $element, $trans );
   445 	}
   465 	}
   446 
   466 
   447 	$content = implode( '', $textarr );
   467 	$content = implode( '', $textarr );
   448 
   468 
   489  *
   509  *
   490  * @since 2.5.0
   510  * @since 2.5.0
   491  *
   511  *
   492  * @param string $text
   512  * @param string $text
   493  * @return array|string List of attribute values.
   513  * @return array|string List of attribute values.
   494  *                      Returns empty array if trim( $text ) == '""'.
   514  *                      Returns empty array if '""' === trim( $text ).
   495  *                      Returns empty string if trim( $text ) == ''.
   515  *                      Returns empty string if '' === trim( $text ).
   496  *                      All other matches are checked for not empty().
   516  *                      All other matches are checked for not empty().
   497  */
   517  */
   498 function shortcode_parse_atts( $text ) {
   518 function shortcode_parse_atts( $text ) {
   499 	$atts    = array();
   519 	$atts    = array();
   500 	$pattern = get_shortcode_atts_regex();
   520 	$pattern = get_shortcode_atts_regex();
   514 			} elseif ( isset( $m[9] ) ) {
   534 			} elseif ( isset( $m[9] ) ) {
   515 				$atts[] = stripcslashes( $m[9] );
   535 				$atts[] = stripcslashes( $m[9] );
   516 			}
   536 			}
   517 		}
   537 		}
   518 
   538 
   519 		// Reject any unclosed HTML elements
   539 		// Reject any unclosed HTML elements.
   520 		foreach ( $atts as &$value ) {
   540 		foreach ( $atts as &$value ) {
   521 			if ( false !== strpos( $value, '<' ) ) {
   541 			if ( false !== strpos( $value, '<' ) ) {
   522 				if ( 1 !== preg_match( '/^[^<]*+(?:<[^>]*+>[^<]*+)*+$/', $value ) ) {
   542 				if ( 1 !== preg_match( '/^[^<]*+(?:<[^>]*+>[^<]*+)*+$/', $value ) ) {
   523 					$value = '';
   543 					$value = '';
   524 				}
   544 				}
   525 			}
   545 			}
   526 		}
   546 		}
   527 	} else {
   547 	} else {
   528 		$atts = ltrim( $text );
   548 		$atts = ltrim( $text );
   529 	}
   549 	}
       
   550 
   530 	return $atts;
   551 	return $atts;
   531 }
   552 }
   532 
   553 
   533 /**
   554 /**
   534  * Combine user attributes with known attributes and fill in defaults when needed.
   555  * Combine user attributes with known attributes and fill in defaults when needed.
   555 			$out[ $name ] = $atts[ $name ];
   576 			$out[ $name ] = $atts[ $name ];
   556 		} else {
   577 		} else {
   557 			$out[ $name ] = $default;
   578 			$out[ $name ] = $default;
   558 		}
   579 		}
   559 	}
   580 	}
   560 	/**
   581 
   561 	 * Filters a shortcode's default attributes.
       
   562 	 *
       
   563 	 * If the third parameter of the shortcode_atts() function is present then this filter is available.
       
   564 	 * The third parameter, $shortcode, is the name of the shortcode.
       
   565 	 *
       
   566 	 * @since 3.6.0
       
   567 	 * @since 4.4.0 Added the `$shortcode` parameter.
       
   568 	 *
       
   569 	 * @param array  $out       The output array of shortcode attributes.
       
   570 	 * @param array  $pairs     The supported attributes and their defaults.
       
   571 	 * @param array  $atts      The user defined shortcode attributes.
       
   572 	 * @param string $shortcode The shortcode name.
       
   573 	 */
       
   574 	if ( $shortcode ) {
   582 	if ( $shortcode ) {
       
   583 		/**
       
   584 		 * Filters shortcode attributes.
       
   585 		 *
       
   586 		 * If the third parameter of the shortcode_atts() function is present then this filter is available.
       
   587 		 * The third parameter, $shortcode, is the name of the shortcode.
       
   588 		 *
       
   589 		 * @since 3.6.0
       
   590 		 * @since 4.4.0 Added the `$shortcode` parameter.
       
   591 		 *
       
   592 		 * @param array  $out       The output array of shortcode attributes.
       
   593 		 * @param array  $pairs     The supported attributes and their defaults.
       
   594 		 * @param array  $atts      The user defined shortcode attributes.
       
   595 		 * @param string $shortcode The shortcode name.
       
   596 		 */
   575 		$out = apply_filters( "shortcode_atts_{$shortcode}", $out, $pairs, $atts, $shortcode );
   597 		$out = apply_filters( "shortcode_atts_{$shortcode}", $out, $pairs, $atts, $shortcode );
   576 	}
   598 	}
   577 
   599 
   578 	return $out;
   600 	return $out;
   579 }
   601 }
   623 	$content = do_shortcodes_in_html_tags( $content, true, $tagnames );
   645 	$content = do_shortcodes_in_html_tags( $content, true, $tagnames );
   624 
   646 
   625 	$pattern = get_shortcode_regex( $tagnames );
   647 	$pattern = get_shortcode_regex( $tagnames );
   626 	$content = preg_replace_callback( "/$pattern/", 'strip_shortcode_tag', $content );
   648 	$content = preg_replace_callback( "/$pattern/", 'strip_shortcode_tag', $content );
   627 
   649 
   628 	// Always restore square braces so we don't break things like <!--[if IE ]>
   650 	// Always restore square braces so we don't break things like <!--[if IE ]>.
   629 	$content = unescape_invalid_shortcodes( $content );
   651 	$content = unescape_invalid_shortcodes( $content );
   630 
   652 
   631 	return $content;
   653 	return $content;
   632 }
   654 }
   633 
   655 
   638  *
   660  *
   639  * @param array $m RegEx matches against post content.
   661  * @param array $m RegEx matches against post content.
   640  * @return string|false The content stripped of the tag, otherwise false.
   662  * @return string|false The content stripped of the tag, otherwise false.
   641  */
   663  */
   642 function strip_shortcode_tag( $m ) {
   664 function strip_shortcode_tag( $m ) {
   643 	// allow [[foo]] syntax for escaping a tag
   665 	// Allow [[foo]] syntax for escaping a tag.
   644 	if ( $m[1] == '[' && $m[6] == ']' ) {
   666 	if ( '[' === $m[1] && ']' === $m[6] ) {
   645 		return substr( $m[0], 1, -1 );
   667 		return substr( $m[0], 1, -1 );
   646 	}
   668 	}
   647 
   669 
   648 	return $m[1] . $m[6];
   670 	return $m[1] . $m[6];
   649 }
   671 }