diff -r 7b1b88e27a20 -r 48c4eec2b7e6 wp/wp-includes/shortcodes.php --- a/wp/wp-includes/shortcodes.php Thu Sep 29 08:06:27 2022 +0200 +++ b/wp/wp-includes/shortcodes.php Fri Sep 05 18:40:08 2025 +0200 @@ -31,7 +31,7 @@ */ /** - * Container for storing shortcode tags and their hook to call for the shortcode + * Container for storing shortcode tags and their hook to call for the shortcode. * * @since 2.5.0 * @@ -105,11 +105,10 @@ } /** - * Clear all shortcodes. + * Clears all shortcodes. * - * This function is simple, it clears all of the shortcode tags by replacing the - * shortcodes global by a empty array. This is actually a very efficient method - * for removing all shortcodes. + * This function clears all of the shortcode tags by replacing the shortcodes global with + * an empty array. This is actually an efficient method for removing all shortcodes. * * @since 2.5.0 * @@ -122,7 +121,7 @@ } /** - * Whether a registered shortcode exists named $tag + * Determines whether a registered shortcode exists named $tag. * * @since 3.6.0 * @@ -137,7 +136,7 @@ } /** - * Whether the passed content contains the specified shortcode + * Determines whether the passed content contains the specified shortcode. * * @since 3.6.0 * @@ -148,7 +147,7 @@ * @return bool Whether the passed content contains the given shortcode. */ function has_shortcode( $content, $tag ) { - if ( false === strpos( $content, '[' ) ) { + if ( ! str_contains( $content, '[' ) ) { return false; } @@ -170,7 +169,45 @@ } /** - * Search content for shortcodes and filter shortcodes through their hooks. + * Returns a list of registered shortcode names found in the given content. + * + * Example usage: + * + * get_shortcode_tags_in_content( '[audio src="file.mp3"][/audio] [foo] [gallery ids="1,2,3"]' ); + * // array( 'audio', 'gallery' ) + * + * @since 6.3.2 + * + * @param string $content The content to check. + * @return string[] An array of registered shortcode names found in the content. + */ +function get_shortcode_tags_in_content( $content ) { + if ( false === strpos( $content, '[' ) ) { + return array(); + } + + preg_match_all( '/' . get_shortcode_regex() . '/', $content, $matches, PREG_SET_ORDER ); + if ( empty( $matches ) ) { + return array(); + } + + $tags = array(); + foreach ( $matches as $shortcode ) { + $tags[] = $shortcode[2]; + + if ( ! empty( $shortcode[5] ) ) { + $deep_tags = get_shortcode_tags_in_content( $shortcode[5] ); + if ( ! empty( $deep_tags ) ) { + $tags = array_merge( $tags, $deep_tags ); + } + } + } + + return $tags; +} + +/** + * Searches content for shortcodes and filter shortcodes through their hooks. * * This function is an alias for do_shortcode(). * @@ -188,7 +225,7 @@ } /** - * Search content for shortcodes and filter shortcodes through their hooks. + * Searches content for shortcodes and filter shortcodes through their hooks. * * If there are no shortcode tags defined, then the content will be returned * without any filtering. This might cause issues when plugins are disabled but @@ -206,7 +243,7 @@ function do_shortcode( $content, $ignore_html = false ) { global $shortcode_tags; - if ( false === strpos( $content, '[' ) ) { + if ( ! str_contains( $content, '[' ) ) { return $content; } @@ -222,6 +259,14 @@ return $content; } + // Ensure this context is only added once if shortcodes are nested. + $has_filter = has_filter( 'wp_get_attachment_image_context', '_filter_do_shortcode_context' ); + $filter_added = false; + + if ( ! $has_filter ) { + $filter_added = add_filter( 'wp_get_attachment_image_context', '_filter_do_shortcode_context' ); + } + $content = do_shortcodes_in_html_tags( $content, $ignore_html, $tagnames ); $pattern = get_shortcode_regex( $tagnames ); @@ -230,11 +275,31 @@ // Always restore square braces so we don't break things like