| [ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * WordPress API for creating bbcode-like tags or what WordPress calls 4 * "shortcodes". The tag and attribute parsing or regular expression code is 5 * based on the Textpattern tag parser. 6 * 7 * A few examples are below: 8 * 9 * [shortcode /] 10 * [shortcode foo="bar" baz="bing" /] 11 * [shortcode foo="bar"]content[/shortcode] 12 * 13 * Shortcode tags support attributes and enclosed content, but does not entirely 14 * support inline shortcodes in other shortcodes. You will have to call the 15 * shortcode parser in your function to account for that. 16 * 17 * {@internal 18 * Please be aware that the above note was made during the beta of WordPress 2.6 19 * and in the future may not be accurate. Please update the note when it is no 20 * longer the case.}} 21 * 22 * To apply shortcode tags to content: 23 * 24 * $out = do_shortcode( $content ); 25 * 26 * @link https://developer.wordpress.org/plugins/shortcodes/ 27 * 28 * @package WordPress 29 * @subpackage Shortcodes 30 * @since 2.5.0 31 */ 32 33 /** 34 * Container for storing shortcode tags and their hook to call for the shortcode. 35 * 36 * @since 2.5.0 37 * 38 * @name $shortcode_tags 39 * @var array 40 * @global array $shortcode_tags 41 */ 42 $shortcode_tags = array(); 43 44 /** 45 * Adds a new shortcode. 46 * 47 * Care should be taken through prefixing or other means to ensure that the 48 * shortcode tag being added is unique and will not conflict with other, 49 * already-added shortcode tags. In the event of a duplicated tag, the tag 50 * loaded last will take precedence. 51 * 52 * @since 2.5.0 53 * 54 * @global array $shortcode_tags 55 * 56 * @param string $tag Shortcode tag to be searched in post content. 57 * @param callable $callback The callback function to run when the shortcode is found. 58 * Every shortcode callback is passed three parameters by default, 59 * including an array of attributes (`$atts`), the shortcode content 60 * or null if not set (`$content`), and finally the shortcode tag 61 * itself (`$shortcode_tag`), in that order. 62 */ 63 function add_shortcode( $tag, $callback ) { 64 global $shortcode_tags; 65 66 if ( '' === trim( $tag ) ) { 67 _doing_it_wrong( 68 __FUNCTION__, 69 __( 'Invalid shortcode name: Empty name given.' ), 70 '4.4.0' 71 ); 72 return; 73 } 74 75 if ( 0 !== preg_match( '@[<>&/\[\]\x00-\x20=]@', $tag ) ) { 76 _doing_it_wrong( 77 __FUNCTION__, 78 sprintf( 79 /* translators: 1: Shortcode name, 2: Space-separated list of reserved characters. */ 80 __( 'Invalid shortcode name: %1$s. Do not use spaces or reserved characters: %2$s' ), 81 $tag, 82 '& / < > [ ] =' 83 ), 84 '4.4.0' 85 ); 86 return; 87 } 88 89 $shortcode_tags[ $tag ] = $callback; 90 } 91 92 /** 93 * Removes hook for shortcode. 94 * 95 * @since 2.5.0 96 * 97 * @global array $shortcode_tags 98 * 99 * @param string $tag Shortcode tag to remove hook for. 100 */ 101 function remove_shortcode( $tag ) { 102 global $shortcode_tags; 103 104 unset( $shortcode_tags[ $tag ] ); 105 } 106 107 /** 108 * Clears all shortcodes. 109 * 110 * This function clears all of the shortcode tags by replacing the shortcodes global with 111 * an empty array. This is actually an efficient method for removing all shortcodes. 112 * 113 * @since 2.5.0 114 * 115 * @global array $shortcode_tags 116 */ 117 function remove_all_shortcodes() { 118 global $shortcode_tags; 119 120 $shortcode_tags = array(); 121 } 122 123 /** 124 * Determines whether a registered shortcode exists named $tag. 125 * 126 * @since 3.6.0 127 * 128 * @global array $shortcode_tags List of shortcode tags and their callback hooks. 129 * 130 * @param string $tag Shortcode tag to check. 131 * @return bool Whether the given shortcode exists. 132 */ 133 function shortcode_exists( $tag ) { 134 global $shortcode_tags; 135 return array_key_exists( $tag, $shortcode_tags ); 136 } 137 138 /** 139 * Determines whether the passed content contains the specified shortcode. 140 * 141 * @since 3.6.0 142 * 143 * @global array $shortcode_tags 144 * 145 * @param string $content Content to search for shortcodes. 146 * @param string $tag Shortcode tag to check. 147 * @return bool Whether the passed content contains the given shortcode. 148 * 149 * @phpstan-return ( $tag is '' ? false : ( $content is empty ? false : bool ) ) 150 */ 151 function has_shortcode( $content, $tag ) { 152 if ( ! str_contains( $content, '[' ) ) { 153 return false; 154 } 155 156 if ( shortcode_exists( $tag ) ) { 157 preg_match_all( '/' . get_shortcode_regex() . '/', $content, $matches, PREG_SET_ORDER ); 158 if ( empty( $matches ) ) { 159 return false; 160 } 161 162 foreach ( $matches as $shortcode ) { 163 if ( $tag === $shortcode[2] ) { 164 return true; 165 } elseif ( ! empty( $shortcode[5] ) && has_shortcode( $shortcode[5], $tag ) ) { 166 return true; 167 } 168 } 169 } 170 return false; 171 } 172 173 /** 174 * Returns a list of registered shortcode names found in the given content. 175 * 176 * Example usage: 177 * 178 * get_shortcode_tags_in_content( '[audio src="file.mp3"][/audio] [foo] [gallery ids="1,2,3"]' ); 179 * // array( 'audio', 'gallery' ) 180 * 181 * @since 6.3.2 182 * 183 * @param string $content The content to check. 184 * @return string[] An array of registered shortcode names found in the content. 185 */ 186 function get_shortcode_tags_in_content( $content ) { 187 if ( ! str_contains( $content, '[' ) ) { 188 return array(); 189 } 190 191 preg_match_all( '/' . get_shortcode_regex() . '/', $content, $matches, PREG_SET_ORDER ); 192 if ( empty( $matches ) ) { 193 return array(); 194 } 195 196 $tags = array(); 197 foreach ( $matches as $shortcode ) { 198 $tags[] = $shortcode[2]; 199 200 if ( ! empty( $shortcode[5] ) ) { 201 $deep_tags = get_shortcode_tags_in_content( $shortcode[5] ); 202 if ( ! empty( $deep_tags ) ) { 203 $tags = array_merge( $tags, $deep_tags ); 204 } 205 } 206 } 207 208 return $tags; 209 } 210 211 /** 212 * Searches content for shortcodes and filter shortcodes through their hooks. 213 * 214 * This function is an alias for do_shortcode(). 215 * 216 * @since 5.4.0 217 * 218 * @see do_shortcode() 219 * 220 * @param string $content Content to search for shortcodes. 221 * @param bool $ignore_html When true, shortcodes inside HTML elements will be skipped. 222 * Default false. 223 * @return string Content with shortcodes filtered out. 224 */ 225 function apply_shortcodes( $content, $ignore_html = false ) { 226 return do_shortcode( $content, $ignore_html ); 227 } 228 229 /** 230 * Searches content for shortcodes and filter shortcodes through their hooks. 231 * 232 * If there are no shortcode tags defined, then the content will be returned 233 * without any filtering. This might cause issues when plugins are disabled but 234 * the shortcode will still show up in the post or content. 235 * 236 * @since 2.5.0 237 * 238 * @global array $shortcode_tags List of shortcode tags and their callback hooks. 239 * 240 * @param string $content Content to search for shortcodes. 241 * @param bool $ignore_html When true, shortcodes inside HTML elements will be skipped. 242 * Default false. 243 * @return string Content with shortcodes filtered out. 244 */ 245 function do_shortcode( $content, $ignore_html = false ) { 246 global $shortcode_tags; 247 248 if ( ! str_contains( $content, '[' ) ) { 249 return $content; 250 } 251 252 if ( empty( $shortcode_tags ) || ! is_array( $shortcode_tags ) ) { 253 return $content; 254 } 255 256 // Find all registered tag names in $content. 257 preg_match_all( '@\[([^<>&/\[\]\x00-\x20=]++)@', $content, $matches ); 258 $tagnames = array_intersect( array_keys( $shortcode_tags ), $matches[1] ); 259 260 if ( empty( $tagnames ) ) { 261 return $content; 262 } 263 264 // Ensure this context is only added once if shortcodes are nested. 265 $has_filter = has_filter( 'wp_get_attachment_image_context', '_filter_do_shortcode_context' ); 266 $filter_added = false; 267 268 if ( ! $has_filter ) { 269 $filter_added = add_filter( 'wp_get_attachment_image_context', '_filter_do_shortcode_context' ); 270 } 271 272 $content = do_shortcodes_in_html_tags( $content, $ignore_html, $tagnames ); 273 274 $pattern = get_shortcode_regex( $tagnames ); 275 $content = preg_replace_callback( "/$pattern/", 'do_shortcode_tag', $content ); 276 277 // Always restore square braces so we don't break things like <!--[if IE ]>. 278 $content = unescape_invalid_shortcodes( $content ); 279 280 // Only remove the filter if it was added in this scope. 281 if ( $filter_added ) { 282 remove_filter( 'wp_get_attachment_image_context', '_filter_do_shortcode_context' ); 283 } 284 285 return $content; 286 } 287 288 /** 289 * Filter the `wp_get_attachment_image_context` hook during shortcode rendering. 290 * 291 * When wp_get_attachment_image() is called during shortcode rendering, we need to make clear 292 * that the context is a shortcode and not part of the theme's template rendering logic. 293 * 294 * @since 6.3.0 295 * @access private 296 * 297 * @return string The filtered context value for wp_get_attachment_images when doing shortcodes. 298 */ 299 function _filter_do_shortcode_context() { 300 return 'do_shortcode'; 301 } 302 303 /** 304 * Retrieves the shortcode regular expression for searching. 305 * 306 * The regular expression combines the shortcode tags in the regular expression 307 * in a regex class. 308 * 309 * The regular expression contains 6 different sub matches to help with parsing. 310 * 311 * 1 - An extra [ to allow for escaping shortcodes with double [[]] 312 * 2 - The shortcode name 313 * 3 - The shortcode argument list 314 * 4 - The self closing / 315 * 5 - The content of a shortcode when it wraps some content. 316 * 6 - An extra ] to allow for escaping shortcodes with double [[]] 317 * 318 * @since 2.5.0 319 * @since 4.4.0 Added the `$tagnames` parameter. 320 * 321 * @global array $shortcode_tags 322 * 323 * @param array $tagnames Optional. List of shortcodes to find. Defaults to all registered shortcodes. 324 * @return string The shortcode search regular expression. 325 */ 326 function get_shortcode_regex( $tagnames = null ) { 327 global $shortcode_tags; 328 329 if ( empty( $tagnames ) ) { 330 $tagnames = array_keys( $shortcode_tags ); 331 } 332 $tagregexp = implode( '|', array_map( 'preg_quote', $tagnames ) ); 333 334 /* 335 * WARNING! Do not change this regex without changing do_shortcode_tag() and strip_shortcode_tag(). 336 * Also, see shortcode_unautop() and shortcode.js. 337 */ 338 339 // phpcs:disable Squiz.Strings.ConcatenationSpacing.PaddingFound -- don't remove regex indentation 340 return '\\[' // Opening bracket. 341 . '(\\[?)' // 1: Optional second opening bracket for escaping shortcodes: [[tag]]. 342 . "($tagregexp)" // 2: Shortcode name. 343 . '(?![\\w-])' // Not followed by word character or hyphen. 344 . '(' // 3: Unroll the loop: Inside the opening shortcode tag. 345 . '[^\\]\\/]*' // Not a closing bracket or forward slash. 346 . '(?:' 347 . '\\/(?!\\])' // A forward slash not followed by a closing bracket. 348 . '[^\\]\\/]*' // Not a closing bracket or forward slash. 349 . ')*?' 350 . ')' 351 . '(?:' 352 . '(\\/)' // 4: Self closing tag... 353 . '\\]' // ...and closing bracket. 354 . '|' 355 . '\\]' // Closing bracket. 356 . '(?:' 357 . '(' // 5: Unroll the loop: Optionally, anything between the opening and closing shortcode tags. 358 . '[^\\[]*+' // Not an opening bracket. 359 . '(?:' 360 . '\\[(?!\\/\\2\\])' // An opening bracket not followed by the closing shortcode tag. 361 . '[^\\[]*+' // Not an opening bracket. 362 . ')*+' 363 . ')' 364 . '\\[\\/\\2\\]' // Closing shortcode tag. 365 . ')?' 366 . ')' 367 . '(\\]?)'; // 6: Optional second closing bracket for escaping shortcodes: [[tag]]. 368 // phpcs:enable 369 } 370 371 /** 372 * Regular Expression callable for do_shortcode() for calling shortcode hook. 373 * 374 * @see get_shortcode_regex() for details of the match array contents. 375 * 376 * @since 2.5.0 377 * @access private 378 * 379 * @global array $shortcode_tags 380 * 381 * @param array $m { 382 * Regular expression match array. 383 * 384 * @type string $0 Entire matched shortcode text. 385 * @type string $1 Optional second opening bracket for escaping shortcodes. 386 * @type string $2 Shortcode name. 387 * @type string $3 Shortcode arguments list. 388 * @type string $4 Optional self closing slash. 389 * @type string $5 Content of a shortcode when it wraps some content. 390 * @type string $6 Optional second closing bracket for escaping shortcodes. 391 * } 392 * @return string Shortcode output. 393 */ 394 function do_shortcode_tag( $m ) { 395 global $shortcode_tags; 396 397 // Allow [[foo]] syntax for escaping a tag. 398 if ( '[' === $m[1] && ']' === $m[6] ) { 399 return substr( $m[0], 1, -1 ); 400 } 401 402 $tag = $m[2]; 403 $attr = shortcode_parse_atts( $m[3] ); 404 405 if ( ! is_callable( $shortcode_tags[ $tag ] ) ) { 406 _doing_it_wrong( 407 __FUNCTION__, 408 /* translators: %s: Shortcode tag. */ 409 sprintf( __( 'Attempting to parse a shortcode without a valid callback: %s' ), $tag ), 410 '4.3.0' 411 ); 412 return $m[0]; 413 } 414 415 /** 416 * Filters whether to call a shortcode callback. 417 * 418 * Returning a non-false value from filter will short-circuit the 419 * shortcode generation process, returning that value instead. 420 * 421 * @since 4.7.0 422 * @since 6.5.0 The `$attr` parameter is always an array. 423 * 424 * @param false|string $output Short-circuit return value. Either false or the value to replace the shortcode with. 425 * @param string $tag Shortcode name. 426 * @param array $attr Shortcode attributes array, can be empty if the original arguments string cannot be parsed. 427 * @param array $m Regular expression match array. 428 */ 429 $return = apply_filters( 'pre_do_shortcode_tag', false, $tag, $attr, $m ); 430 if ( false !== $return ) { 431 return $return; 432 } 433 434 $content = $m[5] ?? null; 435 436 $output = $m[1] . call_user_func( $shortcode_tags[ $tag ], $attr, $content, $tag ) . $m[6]; 437 438 /** 439 * Filters the output created by a shortcode callback. 440 * 441 * @since 4.7.0 442 * @since 6.5.0 The `$attr` parameter is always an array. 443 * 444 * @param string $output Shortcode output. 445 * @param string $tag Shortcode name. 446 * @param array $attr Shortcode attributes array, can be empty if the original arguments string cannot be parsed. 447 * @param array $m Regular expression match array. 448 */ 449 return apply_filters( 'do_shortcode_tag', $output, $tag, $attr, $m ); 450 } 451 452 /** 453 * Searches only inside HTML elements for shortcodes and process them. 454 * 455 * Any [ or ] characters remaining inside elements will be HTML encoded 456 * to prevent interference with shortcodes that are outside the elements. 457 * Assumes $content processed by KSES already. Users with unfiltered_html 458 * capability may get unexpected output if angle braces are nested in tags. 459 * 460 * @since 4.2.3 461 * 462 * @param string $content Content to search for shortcodes. 463 * @param bool $ignore_html When true, all square braces inside elements will be encoded. 464 * @param array $tagnames List of shortcodes to find. 465 * @return string Content with shortcodes filtered out. 466 */ 467 function do_shortcodes_in_html_tags( $content, $ignore_html, $tagnames ) { 468 // Normalize entities in unfiltered HTML before adding placeholders. 469 $trans = array( 470 '[' => '[', 471 ']' => ']', 472 ); 473 $content = strtr( $content, $trans ); 474 $trans = array( 475 '[' => '[', 476 ']' => ']', 477 ); 478 479 $pattern = get_shortcode_regex( $tagnames ); 480 $textarr = wp_html_split( $content ); 481 482 foreach ( $textarr as &$element ) { 483 if ( '' === $element || '<' !== $element[0] ) { 484 continue; 485 } 486 487 $noopen = ! str_contains( $element, '[' ); 488 $noclose = ! str_contains( $element, ']' ); 489 if ( $noopen || $noclose ) { 490 // This element does not contain shortcodes. 491 if ( $noopen xor $noclose ) { 492 // Need to encode stray '[' or ']' chars. 493 $element = strtr( $element, $trans ); 494 } 495 continue; 496 } 497 498 if ( $ignore_html || str_starts_with( $element, '<!--' ) || str_starts_with( $element, '<![CDATA[' ) ) { 499 // Encode all '[' and ']' chars. 500 $element = strtr( $element, $trans ); 501 continue; 502 } 503 504 $attributes = wp_kses_attr_parse( $element ); 505 if ( false === $attributes ) { 506 // Some plugins are doing things like [name] <[email]>. 507 if ( 1 === preg_match( '%^<\s*\[\[?[^\[\]]+\]%', $element ) ) { 508 $element = preg_replace_callback( "/$pattern/", 'do_shortcode_tag', $element ); 509 } 510 511 // Looks like we found some unexpected unfiltered HTML. Skipping it for confidence. 512 $element = strtr( $element, $trans ); 513 continue; 514 } 515 516 // Get element name. 517 $front = array_shift( $attributes ); 518 $back = array_pop( $attributes ); 519 $matches = array(); 520 preg_match( '%[a-zA-Z0-9]+%', $front, $matches ); 521 $elname = $matches[0]; 522 523 // Look for shortcodes in each attribute separately. 524 foreach ( $attributes as &$attr ) { 525 $open = strpos( $attr, '[' ); 526 $close = strpos( $attr, ']' ); 527 if ( false === $open || false === $close ) { 528 continue; // Go to next attribute. Square braces will be escaped at end of loop. 529 } 530 $double = strpos( $attr, '"' ); 531 $single = strpos( $attr, "'" ); 532 if ( ( false === $single || $open < $single ) && ( false === $double || $open < $double ) ) { 533 /* 534 * $attr like '[shortcode]' or 'name = [shortcode]' implies unfiltered_html. 535 * In this specific situation we assume KSES did not run because the input 536 * was written by an administrator, so we should avoid changing the output 537 * and we do not need to run KSES here. 538 */ 539 $attr = preg_replace_callback( "/$pattern/", 'do_shortcode_tag', $attr ); 540 } else { 541 /* 542 * $attr like 'name = "[shortcode]"' or "name = '[shortcode]'". 543 * We do not know if $content was unfiltered. Assume KSES ran before shortcodes. 544 */ 545 $count = 0; 546 $new_attr = preg_replace_callback( "/$pattern/", 'do_shortcode_tag', $attr, -1, $count ); 547 if ( $count > 0 ) { 548 // Sanitize the shortcode output using KSES. 549 $new_attr = wp_kses_one_attr( $new_attr, $elname ); 550 if ( '' !== trim( $new_attr ) ) { 551 // The shortcode is safe to use now. 552 $attr = $new_attr; 553 } 554 } 555 } 556 } 557 $element = $front . implode( '', $attributes ) . $back; 558 559 // Now encode any remaining '[' or ']' chars. 560 $element = strtr( $element, $trans ); 561 } 562 563 $content = implode( '', $textarr ); 564 565 return $content; 566 } 567 568 /** 569 * Removes placeholders added by do_shortcodes_in_html_tags(). 570 * 571 * @since 4.2.3 572 * 573 * @param string $content Content to search for placeholders. 574 * @return string Content with placeholders removed. 575 */ 576 function unescape_invalid_shortcodes( $content ) { 577 // Clean up entire string, avoids re-parsing HTML. 578 $trans = array( 579 '[' => '[', 580 ']' => ']', 581 ); 582 583 $content = strtr( $content, $trans ); 584 585 return $content; 586 } 587 588 /** 589 * Retrieves the shortcode attributes regex. 590 * 591 * @since 4.4.0 592 * 593 * @return string The shortcode attribute regular expression. 594 */ 595 function get_shortcode_atts_regex() { 596 return '/([\w-]+)\s*=\s*"([^"]*)"(?:\s|$)|([\w-]+)\s*=\s*\'([^\']*)\'(?:\s|$)|([\w-]+)\s*=\s*([^\s\'"]+)(?:\s|$)|"([^"]*)"(?:\s|$)|\'([^\']*)\'(?:\s|$)|(\S+)(?:\s|$)/'; 597 } 598 599 /** 600 * Retrieves all attributes from the shortcodes tag. 601 * 602 * The attributes list has the attribute name as the key and the value of the 603 * attribute as the value in the key/value pair. This allows for easier 604 * retrieval of the attributes, since all attributes have to be known. 605 * 606 * @since 2.5.0 607 * @since 6.5.0 The function now always returns an array, 608 * even if the original arguments string cannot be parsed or is empty. 609 * 610 * @param string $text Shortcode arguments list. 611 * @return array Array of attribute values keyed by attribute name. 612 * Returns empty array if there are no attributes 613 * or if the original arguments string cannot be parsed. 614 */ 615 function shortcode_parse_atts( $text ) { 616 $atts = array(); 617 $pattern = get_shortcode_atts_regex(); 618 $text = preg_replace( "/[\x{00a0}\x{200b}]+/u", ' ', $text ); 619 if ( preg_match_all( $pattern, $text, $match, PREG_SET_ORDER ) ) { 620 foreach ( $match as $m ) { 621 if ( ! empty( $m[1] ) ) { 622 $atts[ strtolower( $m[1] ) ] = stripcslashes( $m[2] ); 623 } elseif ( ! empty( $m[3] ) ) { 624 $atts[ strtolower( $m[3] ) ] = stripcslashes( $m[4] ); 625 } elseif ( ! empty( $m[5] ) ) { 626 $atts[ strtolower( $m[5] ) ] = stripcslashes( $m[6] ); 627 } elseif ( isset( $m[7] ) && strlen( $m[7] ) ) { 628 $atts[] = stripcslashes( $m[7] ); 629 } elseif ( isset( $m[8] ) && strlen( $m[8] ) ) { 630 $atts[] = stripcslashes( $m[8] ); 631 } elseif ( isset( $m[9] ) ) { 632 $atts[] = stripcslashes( $m[9] ); 633 } 634 } 635 636 // Reject any unclosed HTML elements. 637 foreach ( $atts as &$value ) { 638 if ( str_contains( $value, '<' ) ) { 639 if ( 1 !== preg_match( '/^[^<]*+(?:<[^>]*+>[^<]*+)*+$/', $value ) ) { 640 $value = ''; 641 } 642 } 643 } 644 } 645 646 return $atts; 647 } 648 649 /** 650 * Combines user attributes with known attributes and fill in defaults when needed. 651 * 652 * The pairs should be considered to be all of the attributes which are 653 * supported by the caller and given as a list. The returned attributes will 654 * only contain the attributes in the $pairs list. 655 * 656 * If the $atts list has unsupported attributes, then they will be ignored and 657 * removed from the final returned list. 658 * 659 * @since 2.5.0 660 * 661 * @param array $pairs Entire list of supported attributes and their defaults. 662 * @param array $atts User defined attributes in shortcode tag. 663 * @param string $shortcode Optional. The name of the shortcode, provided for context to enable filtering 664 * @return array Combined and filtered attribute list. 665 */ 666 function shortcode_atts( $pairs, $atts, $shortcode = '' ) { 667 $atts = (array) $atts; 668 $out = array(); 669 foreach ( $pairs as $name => $default ) { 670 if ( array_key_exists( $name, $atts ) ) { 671 $out[ $name ] = $atts[ $name ]; 672 } else { 673 $out[ $name ] = $default; 674 } 675 } 676 677 if ( $shortcode ) { 678 /** 679 * Filters shortcode attributes. 680 * 681 * If the third parameter of the shortcode_atts() function is present then this filter is available. 682 * The third parameter, $shortcode, is the name of the shortcode. 683 * 684 * @since 3.6.0 685 * @since 4.4.0 Added the `$shortcode` parameter. 686 * 687 * @param array $out The output array of shortcode attributes. 688 * @param array $pairs The supported attributes and their defaults. 689 * @param array $atts The user defined shortcode attributes. 690 * @param string $shortcode The shortcode name. 691 */ 692 $out = apply_filters( "shortcode_atts_{$shortcode}", $out, $pairs, $atts, $shortcode ); 693 } 694 695 return $out; 696 } 697 698 /** 699 * Removes all shortcode tags from the given content. 700 * 701 * @since 2.5.0 702 * 703 * @global array $shortcode_tags 704 * 705 * @param string $content Content to remove shortcode tags. 706 * @return string Content without shortcode tags. 707 */ 708 function strip_shortcodes( $content ) { 709 global $shortcode_tags; 710 711 if ( ! str_contains( $content, '[' ) ) { 712 return $content; 713 } 714 715 if ( empty( $shortcode_tags ) || ! is_array( $shortcode_tags ) ) { 716 return $content; 717 } 718 719 // Find all registered tag names in $content. 720 preg_match_all( '@\[([^<>&/\[\]\x00-\x20=]++)@', $content, $matches ); 721 722 $tags_to_remove = array_keys( $shortcode_tags ); 723 724 /** 725 * Filters the list of shortcode tags to remove from the content. 726 * 727 * @since 4.7.0 728 * 729 * @param array $tags_to_remove Array of shortcode tags to remove. 730 * @param string $content Content shortcodes are being removed from. 731 */ 732 $tags_to_remove = apply_filters( 'strip_shortcodes_tagnames', $tags_to_remove, $content ); 733 734 $tagnames = array_intersect( $tags_to_remove, $matches[1] ); 735 736 if ( empty( $tagnames ) ) { 737 return $content; 738 } 739 740 $content = do_shortcodes_in_html_tags( $content, true, $tagnames ); 741 742 $pattern = get_shortcode_regex( $tagnames ); 743 $content = preg_replace_callback( "/$pattern/", 'strip_shortcode_tag', $content ); 744 745 // Always restore square braces so we don't break things like <!--[if IE ]>. 746 $content = unescape_invalid_shortcodes( $content ); 747 748 return $content; 749 } 750 751 /** 752 * Strips a shortcode tag based on RegEx matches against post content. 753 * 754 * @since 3.3.0 755 * 756 * @param array $m RegEx matches against post content. 757 * @return string|false The content stripped of the tag, otherwise false. 758 */ 759 function strip_shortcode_tag( $m ) { 760 // Allow [[foo]] syntax for escaping a tag. 761 if ( '[' === $m[1] && ']' === $m[6] ) { 762 return substr( $m[0], 1, -1 ); 763 } 764 765 return $m[1] . $m[6]; 766 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated : Sun Oct 4 08:20:33 2026 | Cross-referenced by PHPXref |