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