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