run:R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:51
R W Run
23.8 KB
2026-03-11 16:18:51
R W Run
7.8 KB
2026-03-11 16:18:52
R W Run
36.1 KB
2026-03-11 16:18:51
R W Run
11.9 KB
2026-03-11 16:18:52
R W Run
18.94 KB
2026-03-11 16:18:52
R W Run
7.35 KB
2026-03-11 16:18:52
R W Run
28.6 KB
2026-03-11 16:18:51
R W Run
316 By
2026-03-11 16:18:51
R W Run
12.9 KB
2026-03-11 16:18:51
R W Run
61.02 KB
2026-03-11 16:18:52
R W Run
15 KB
2026-03-11 16:18:51
R W Run
112.05 KB
2026-03-11 16:18:51
R W Run
12.47 KB
2026-03-11 16:18:51
R W Run
15.07 KB
2026-03-11 16:18:52
R W Run
9.84 KB
2026-03-11 16:18:52
R W Run
13.17 KB
2026-03-11 16:18:52
R W Run
33.83 KB
2026-03-11 16:18:51
R W Run
42.63 KB
2026-03-11 16:18:51
R W Run
55.71 KB
2026-03-11 16:18:52
R W Run
12.53 KB
2026-03-11 16:18:51
R W Run
2.55 KB
2026-03-11 16:18:52
R W Run
28.92 KB
2026-03-11 16:18:52
R W Run
539 By
2026-03-11 16:18:51
R W Run
367 By
2026-03-11 16:18:52
R W Run
42.65 KB
2026-03-11 16:18:51
R W Run
401 By
2026-03-11 16:18:51
R W Run
6.61 KB
2026-03-11 16:18:51
R W Run
664 By
2026-03-11 16:18:52
R W Run
20.63 KB
2026-03-11 16:18:51
R W Run
2.18 KB
2026-03-11 16:18:52
R W Run
453 By
2026-03-11 16:18:52
R W Run
457 By
2026-03-11 16:18:51
R W Run
36.83 KB
2026-03-11 16:18:52
R W Run
2.41 KB
2026-03-11 16:18:52
R W Run
8.28 KB
2026-03-11 16:18:51
R W Run
13.89 KB
2026-03-11 16:18:51
R W Run
11.76 KB
2026-03-11 16:18:51
R W Run
2.65 KB
2026-03-11 16:18:51
R W Run
7.43 KB
2026-03-11 16:18:51
R W Run
17.46 KB
2026-03-11 16:18:51
R W Run
5.14 KB
2026-03-11 16:18:52
R W Run
16.7 KB
2026-03-11 16:18:51
R W Run
8.28 KB
2026-03-11 16:18:52
R W Run
2.92 KB
2026-03-11 16:18:52
R W Run
1.32 KB
2026-03-11 16:18:51
R W Run
4.6 KB
2026-03-11 16:18:52
R W Run
11.62 KB
2026-03-11 16:18:52
R W Run
2.5 KB
2026-03-11 16:18:51
R W Run
1.97 KB
2026-03-11 16:18:51
R W Run
11.25 KB
2026-03-11 16:18:52
R W Run
5.32 KB
2026-03-11 16:18:51
R W Run
10.99 KB
2026-03-11 16:18:52
R W Run
68.32 KB
2026-03-11 16:18:51
R W Run
6.34 KB
2026-03-11 16:18:51
R W Run
5.49 KB
2026-03-11 16:18:51
R W Run
1.99 KB
2026-03-11 16:18:52
R W Run
7.02 KB
2026-03-11 16:18:51
R W Run
4.91 KB
2026-03-11 16:18:52
R W Run
16.86 KB
2026-03-11 16:18:51
R W Run
24.23 KB
2026-03-11 16:18:51
R W Run
3.97 KB
2026-03-11 16:18:51
R W Run
47.66 KB
2026-03-11 16:18:51
R W Run
9.22 KB
2026-03-11 16:18:51
R W Run
25.51 KB
2026-03-11 16:18:51
R W Run
198.38 KB
2026-03-11 16:18:52
R W Run
56.65 KB
2026-03-11 16:18:51
R W Run
10.46 KB
2026-03-11 16:18:51
R W Run
10.95 KB
2026-03-11 16:18:52
R W Run
29.26 KB
2026-03-11 16:18:51
R W Run
70.91 KB
2026-03-11 16:18:52
R W Run
35.3 KB
2026-03-11 16:18:52
R W Run
16.61 KB
2026-03-11 16:18:52
R W Run
2.57 KB
2026-03-11 16:18:52
R W Run
39.83 KB
2026-03-11 16:18:51
R W Run
70.64 KB
2026-03-11 16:18:51
R W Run
15.56 KB
2026-03-11 16:18:52
R W Run
7.33 KB
2026-03-11 16:18:52
R W Run
253 By
2026-03-11 16:18:51
R W Run
7.96 KB
2026-03-11 16:18:52
R W Run
3.23 KB
2026-03-11 16:18:52
R W Run
969 By
2026-03-11 16:18:52
R W Run
16.28 KB
2026-03-11 16:18:51
R W Run
7.22 KB
2026-03-11 16:18:51
R W Run
12.95 KB
2026-03-11 16:18:51
R W Run
6.53 KB
2026-03-11 16:18:51
R W Run
3.42 KB
2026-03-11 16:18:52
R W Run
5.84 KB
2026-03-11 16:18:51
R W Run
1.97 KB
2026-03-11 16:18:51
R W Run
4.3 KB
2026-03-11 16:18:52
R W Run
2.91 KB
2026-03-11 16:18:51
R W Run
16.46 KB
2026-03-11 16:18:52
R W Run
40.6 KB
2026-03-11 16:18:51
R W Run
20.22 KB
2026-03-11 16:18:51
R W Run
36.11 KB
2026-03-11 16:18:52
R W Run
17.01 KB
2026-03-11 16:18:51
R W Run
7.27 KB
2026-03-11 16:18:52
R W Run
6.62 KB
2026-03-11 16:18:52
R W Run
16.49 KB
2026-03-11 16:18:52
R W Run
1.79 KB
2026-03-11 16:18:52
R W Run
29.82 KB
2026-03-11 16:18:51
R W Run
6.67 KB
2026-03-11 16:18:52
R W Run
8.98 KB
2026-03-11 16:18:52
R W Run
19.42 KB
2026-03-11 16:18:51
R W Run
12.01 KB
2026-03-11 16:18:51
R W Run
17.11 KB
2026-03-11 16:18:51
R W Run
6.74 KB
2026-03-11 16:18:52
R W Run
30.93 KB
2026-03-11 16:18:51
R W Run
4.99 KB
2026-03-11 16:18:51
R W Run
4.25 KB
2026-03-11 16:18:51
R W Run
24.72 KB
2026-03-11 16:18:51
R W Run
29.96 KB
2026-03-11 16:18:52
R W Run
6.41 KB
2026-03-11 16:18:51
R W Run
160 KB
2026-03-11 16:18:51
R W Run
6.72 KB
2026-03-11 16:18:52
R W Run
10.92 KB
2026-03-11 16:18:51
R W Run
4.77 KB
2026-03-11 16:18:51
R W Run
3.38 KB
2026-03-11 16:18:51
R W Run
11.18 KB
2026-03-11 16:18:51
R W Run
62.19 KB
2026-03-11 16:18:51
R W Run
2.46 KB
2026-03-11 16:18:51
R W Run
9.17 KB
2026-03-11 16:18:51
R W Run
32.15 KB
2026-03-11 16:18:51
R W Run
34.05 KB
2026-03-11 16:18:52
R W Run
7.15 KB
2026-03-11 16:18:51
R W Run
3.47 KB
2026-03-11 16:18:52
R W Run
1.87 KB
2026-03-11 16:18:52
R W Run
30.91 KB
2026-03-11 16:18:51
R W Run
7.29 KB
2026-03-11 16:18:52
R W Run
7.35 KB
2026-03-11 16:18:51
R W Run
12.54 KB
2026-03-11 16:18:51
R W Run
19.12 KB
2026-03-11 16:18:51
R W Run
18.12 KB
2026-03-11 16:18:52
R W Run
39.99 KB
2026-03-11 16:18:52
R W Run
5.17 KB
2026-03-11 16:18:52
R W Run
979 By
2026-03-11 16:18:51
R W Run
18.44 KB
2026-03-11 16:18:52
R W Run
10.24 KB
2026-03-11 16:18:51
R W Run
1.77 KB
2026-03-11 16:18:52
R W Run
34.9 KB
2026-03-11 16:18:51
R W Run
7.19 KB
2026-03-11 16:18:52
R W Run
160.5 KB
2026-03-11 16:18:51
R W Run
64.27 KB
2026-03-11 16:18:51
R W Run
27.95 KB
2026-03-11 16:18:51
R W Run
4.69 KB
2026-03-11 16:18:51
R W Run
2.94 KB
2026-03-11 16:18:51
R W Run
43.13 KB
2026-03-11 16:18:52
R W Run
2.25 KB
2026-03-11 16:18:52
R W Run
22.5 KB
2026-03-11 16:18:51
R W Run
13.01 KB
2026-03-11 16:18:52
R W Run
3.27 KB
2026-03-11 16:18:51
R W Run
18 KB
2026-03-11 16:18:51
R W Run
210.4 KB
2026-03-11 16:18:52
R W Run
25.86 KB
2026-03-11 16:18:52
R W Run
115.85 KB
2026-03-11 16:18:51
R W Run
373 By
2026-03-11 16:18:52
R W Run
343 By
2026-03-11 16:18:52
R W Run
338 By
2026-03-11 16:18:51
R W Run
100.73 KB
2026-03-11 16:18:52
R W Run
130.93 KB
2026-03-11 16:18:51
R W Run
19.1 KB
2026-03-11 16:18:51
R W Run
17.41 KB
2026-03-11 16:18:52
R W Run
41.98 KB
2026-03-11 16:18:52
R W Run
400 By
2026-03-11 16:18:52
R W Run
11.1 KB
2026-03-11 16:18:52
R W Run
37.02 KB
2026-03-11 16:18:51
R W Run
2.24 KB
2026-03-11 16:18:51
R W Run
188.13 KB
2026-03-11 16:18:51
R W Run
338 By
2026-03-11 16:18:51
R W Run
38 KB
2026-03-11 16:18:51
R W Run
4.02 KB
2026-03-11 16:18:52
R W Run
5.38 KB
2026-03-11 16:18:51
R W Run
3.05 KB
2026-03-11 16:18:52
R W Run
2.61 KB
2026-03-11 16:18:51
R W Run
1.16 KB
2026-03-11 16:18:52
R W Run
4.04 KB
2026-03-11 16:18:51
R W Run
3.71 KB
2026-03-11 16:18:51
R W Run
24.6 KB
2026-03-11 16:18:51
R W Run
9.56 KB
2026-03-11 16:18:51
R W Run
346.43 KB
2026-03-11 16:18:52
R W Run
281.84 KB
2026-03-11 16:18:52
R W Run
14.95 KB
2026-03-11 16:18:51
R W Run
8.44 KB
2026-03-11 16:18:52
R W Run
168.95 KB
2026-03-11 16:18:52
R W Run
20.71 KB
2026-03-11 16:18:52
R W Run
25.27 KB
2026-03-11 16:18:51
R W Run
5.72 KB
2026-03-11 16:18:51
R W Run
4.63 KB
2026-03-11 16:18:52
R W Run
81.73 KB
2026-03-11 16:18:51
R W Run
67.18 KB
2026-03-11 16:18:51
R W Run
156.36 KB
2026-03-11 16:18:52
R W Run
55.19 KB
2026-03-11 16:18:51
R W Run
162 By
2026-03-11 16:18:51
R W Run
61.72 KB
2026-03-11 16:18:51
R W Run
216.06 KB
2026-03-11 16:18:52
R W Run
65.09 KB
2026-03-11 16:18:51
R W Run
25.24 KB
2026-03-11 16:18:52
R W Run
4.81 KB
2026-03-11 16:18:51
R W Run
6.48 KB
2026-03-11 16:18:52
R W Run
21.25 KB
2026-03-11 16:18:51
R W Run
2.79 KB
2026-03-11 16:18:52
R W Run
89.69 KB
2026-03-11 16:18:52
R W Run
19.42 KB
2026-03-11 16:18:52
R W Run
3.69 KB
2026-03-11 16:18:52
R W Run
4.11 KB
2026-03-11 16:18:51
R W Run
40.74 KB
2026-03-11 16:18:51
R W Run
25.38 KB
2026-03-11 16:18:51
R W Run
43.31 KB
2026-03-11 16:18:52
R W Run
102.57 KB
2026-03-11 16:18:52
R W Run
6.18 KB
2026-03-11 16:18:51
R W Run
124.47 KB
2026-03-11 16:18:52
R W Run
35.65 KB
2026-03-11 16:18:52
R W Run
6.94 KB
2026-03-11 16:18:52
R W Run
67.04 KB
2026-03-11 16:18:52
R W Run
10.62 KB
2026-03-11 16:18:51
R W Run
289.35 KB
2026-03-11 16:18:52
R W Run
36.23 KB
2026-03-11 16:18:51
R W Run
200 By
2026-03-11 16:18:52
R W Run
200 By
2026-03-11 16:18:52
R W Run
98.29 KB
2026-03-11 16:18:52
R W Run
30.02 KB
2026-03-11 16:18:52
R W Run
19.03 KB
2026-03-11 16:18:52
R W Run
5.06 KB
2026-03-11 16:18:52
R W Run
255 By
2026-03-11 16:18:51
R W Run
22.66 KB
2026-03-11 16:18:52
R W Run
154.63 KB
2026-03-11 16:18:51
R W Run
9.68 KB
2026-03-11 16:18:51
R W Run
258 By
2026-03-11 16:18:51
R W Run
23.49 KB
2026-03-11 16:18:51
R W Run
3.16 KB
2026-03-11 16:18:51
R W Run
8.4 KB
2026-03-11 16:18:52
R W Run
441 By
2026-03-11 16:18:51
R W Run
7.39 KB
2026-03-11 16:18:51
R W Run
173 KB
2026-03-11 16:18:52
R W Run
544 By
2026-03-11 16:18:52
R W Run
4.17 KB
2026-03-11 16:18:51
R W Run
35.97 KB
2026-03-11 16:18:52
R W Run
1.69 KB
2026-03-11 16:18:51
R W Run
2.84 KB
2026-03-11 16:18:52
R W Run
6.09 KB
2026-03-11 16:18:51
R W Run
8.71 KB
2026-03-11 16:18:51
R W Run
131.84 KB
2026-03-11 16:18:51
R W Run
37.45 KB
2026-03-11 16:18:51
R W Run
173.89 KB
2026-03-11 16:18:51
R W Run
7.09 KB
2026-03-11 16:18:51
R W Run
6.41 KB
2026-03-11 16:18:51
R W Run
1.08 KB
2026-03-11 16:18:51
R W Run
69.46 KB
2026-03-11 16:18:52
R W Run
445 By
2026-03-11 16:18:51
R W Run
799 By
2026-03-11 16:18:52
R W Run
error_log
📄shortcodes.php
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 */
63function 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 */
101function 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 */
117function 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 */
133function 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 */
149function has_shortcode( $content, $tag ) {
150 if ( ! str_contains( $content, '[' ) ) {
151 return false;
152 }
153
154 if ( shortcode_exists( $tag ) ) {
155 preg_match_all( '/' . get_shortcode_regex() . '/', $content, $matches, PREG_SET_ORDER );
156 if ( empty( $matches ) ) {
157 return false;
158 }
159
160 foreach ( $matches as $shortcode ) {
161 if ( $tag === $shortcode[2] ) {
162 return true;
163 } elseif ( ! empty( $shortcode[5] ) && has_shortcode( $shortcode[5], $tag ) ) {
164 return true;
165 }
166 }
167 }
168 return false;
169}
170
171/**
172 * Returns a list of registered shortcode names found in the given content.
173 *
174 * Example usage:
175 *
176 * get_shortcode_tags_in_content( '[audio src="file.mp3"][/audio] [foo] [gallery ids="1,2,3"]' );
177 * // array( 'audio', 'gallery' )
178 *
179 * @since 6.3.2
180 *
181 * @param string $content The content to check.
182 * @return string[] An array of registered shortcode names found in the content.
183 */
184function get_shortcode_tags_in_content( $content ) {
185 if ( ! str_contains( $content, '[' ) ) {
186 return array();
187 }
188
189 preg_match_all( '/' . get_shortcode_regex() . '/', $content, $matches, PREG_SET_ORDER );
190 if ( empty( $matches ) ) {
191 return array();
192 }
193
194 $tags = array();
195 foreach ( $matches as $shortcode ) {
196 $tags[] = $shortcode[2];
197
198 if ( ! empty( $shortcode[5] ) ) {
199 $deep_tags = get_shortcode_tags_in_content( $shortcode[5] );
200 if ( ! empty( $deep_tags ) ) {
201 $tags = array_merge( $tags, $deep_tags );
202 }
203 }
204 }
205
206 return $tags;
207}
208
209/**
210 * Searches content for shortcodes and filter shortcodes through their hooks.
211 *
212 * This function is an alias for do_shortcode().
213 *
214 * @since 5.4.0
215 *
216 * @see do_shortcode()
217 *
218 * @param string $content Content to search for shortcodes.
219 * @param bool $ignore_html When true, shortcodes inside HTML elements will be skipped.
220 * Default false.
221 * @return string Content with shortcodes filtered out.
222 */
223function apply_shortcodes( $content, $ignore_html = false ) {
224 return do_shortcode( $content, $ignore_html );
225}
226
227/**
228 * Searches content for shortcodes and filter shortcodes through their hooks.
229 *
230 * If there are no shortcode tags defined, then the content will be returned
231 * without any filtering. This might cause issues when plugins are disabled but
232 * the shortcode will still show up in the post or content.
233 *
234 * @since 2.5.0
235 *
236 * @global array $shortcode_tags List of shortcode tags and their callback hooks.
237 *
238 * @param string $content Content to search for shortcodes.
239 * @param bool $ignore_html When true, shortcodes inside HTML elements will be skipped.
240 * Default false.
241 * @return string Content with shortcodes filtered out.
242 */
243function do_shortcode( $content, $ignore_html = false ) {
244 global $shortcode_tags;
245
246 if ( ! str_contains( $content, '[' ) ) {
247 return $content;
248 }
249
250 if ( empty( $shortcode_tags ) || ! is_array( $shortcode_tags ) ) {
251 return $content;
252 }
253
254 // Find all registered tag names in $content.
255 preg_match_all( '@\[([^<>&/\[\]\x00-\x20=]++)@', $content, $matches );
256 $tagnames = array_intersect( array_keys( $shortcode_tags ), $matches[1] );
257
258 if ( empty( $tagnames ) ) {
259 return $content;
260 }
261
262 // Ensure this context is only added once if shortcodes are nested.
263 $has_filter = has_filter( 'wp_get_attachment_image_context', '_filter_do_shortcode_context' );
264 $filter_added = false;
265
266 if ( ! $has_filter ) {
267 $filter_added = add_filter( 'wp_get_attachment_image_context', '_filter_do_shortcode_context' );
268 }
269
270 $content = do_shortcodes_in_html_tags( $content, $ignore_html, $tagnames );
271
272 $pattern = get_shortcode_regex( $tagnames );
273 $content = preg_replace_callback( "/$pattern/", 'do_shortcode_tag', $content );
274
275 // Always restore square braces so we don't break things like <!--[if IE ]>.
276 $content = unescape_invalid_shortcodes( $content );
277
278 // Only remove the filter if it was added in this scope.
279 if ( $filter_added ) {
280 remove_filter( 'wp_get_attachment_image_context', '_filter_do_shortcode_context' );
281 }
282
283 return $content;
284}
285
286/**
287 * Filter the `wp_get_attachment_image_context` hook during shortcode rendering.
288 *
289 * When wp_get_attachment_image() is called during shortcode rendering, we need to make clear
290 * that the context is a shortcode and not part of the theme's template rendering logic.
291 *
292 * @since 6.3.0
293 * @access private
294 *
295 * @return string The filtered context value for wp_get_attachment_images when doing shortcodes.
296 */
297function _filter_do_shortcode_context() {
298 return 'do_shortcode';
299}
300
301/**
302 * Retrieves the shortcode regular expression for searching.
303 *
304 * The regular expression combines the shortcode tags in the regular expression
305 * in a regex class.
306 *
307 * The regular expression contains 6 different sub matches to help with parsing.
308 *
309 * 1 - An extra [ to allow for escaping shortcodes with double [[]]
310 * 2 - The shortcode name
311 * 3 - The shortcode argument list
312 * 4 - The self closing /
313 * 5 - The content of a shortcode when it wraps some content.
314 * 6 - An extra ] to allow for escaping shortcodes with double [[]]
315 *
316 * @since 2.5.0
317 * @since 4.4.0 Added the `$tagnames` parameter.
318 *
319 * @global array $shortcode_tags
320 *
321 * @param array $tagnames Optional. List of shortcodes to find. Defaults to all registered shortcodes.
322 * @return string The shortcode search regular expression.
323 */
324function get_shortcode_regex( $tagnames = null ) {
325 global $shortcode_tags;
326
327 if ( empty( $tagnames ) ) {
328 $tagnames = array_keys( $shortcode_tags );
329 }
330 $tagregexp = implode( '|', array_map( 'preg_quote', $tagnames ) );
331
332 /*
333 * WARNING! Do not change this regex without changing do_shortcode_tag() and strip_shortcode_tag().
334 * Also, see shortcode_unautop() and shortcode.js.
335 */
336
337 // phpcs:disable Squiz.Strings.ConcatenationSpacing.PaddingFound -- don't remove regex indentation
338 return '\\[' // Opening bracket.
339 . '(\\[?)' // 1: Optional second opening bracket for escaping shortcodes: [[tag]].
340 . "($tagregexp)" // 2: Shortcode name.
341 . '(?![\\w-])' // Not followed by word character or hyphen.
342 . '(' // 3: Unroll the loop: Inside the opening shortcode tag.
343 . '[^\\]\\/]*' // Not a closing bracket or forward slash.
344 . '(?:'
345 . '\\/(?!\\])' // A forward slash not followed by a closing bracket.
346 . '[^\\]\\/]*' // Not a closing bracket or forward slash.
347 . ')*?'
348 . ')'
349 . '(?:'
350 . '(\\/)' // 4: Self closing tag...
351 . '\\]' // ...and closing bracket.
352 . '|'
353 . '\\]' // Closing bracket.
354 . '(?:'
355 . '(' // 5: Unroll the loop: Optionally, anything between the opening and closing shortcode tags.
356 . '[^\\[]*+' // Not an opening bracket.
357 . '(?:'
358 . '\\[(?!\\/\\2\\])' // An opening bracket not followed by the closing shortcode tag.
359 . '[^\\[]*+' // Not an opening bracket.
360 . ')*+'
361 . ')'
362 . '\\[\\/\\2\\]' // Closing shortcode tag.
363 . ')?'
364 . ')'
365 . '(\\]?)'; // 6: Optional second closing bracket for escaping shortcodes: [[tag]].
366 // phpcs:enable
367}
368
369/**
370 * Regular Expression callable for do_shortcode() for calling shortcode hook.
371 *
372 * @see get_shortcode_regex() for details of the match array contents.
373 *
374 * @since 2.5.0
375 * @access private
376 *
377 * @global array $shortcode_tags
378 *
379 * @param array $m {
380 * Regular expression match array.
381 *
382 * @type string $0 Entire matched shortcode text.
383 * @type string $1 Optional second opening bracket for escaping shortcodes.
384 * @type string $2 Shortcode name.
385 * @type string $3 Shortcode arguments list.
386 * @type string $4 Optional self closing slash.
387 * @type string $5 Content of a shortcode when it wraps some content.
388 * @type string $6 Optional second closing bracket for escaping shortcodes.
389 * }
390 * @return string Shortcode output.
391 */
392function do_shortcode_tag( $m ) {
393 global $shortcode_tags;
394
395 // Allow [[foo]] syntax for escaping a tag.
396 if ( '[' === $m[1] && ']' === $m[6] ) {
397 return substr( $m[0], 1, -1 );
398 }
399
400 $tag = $m[2];
401 $attr = shortcode_parse_atts( $m[3] );
402
403 if ( ! is_callable( $shortcode_tags[ $tag ] ) ) {
404 _doing_it_wrong(
405 __FUNCTION__,
406 /* translators: %s: Shortcode tag. */
407 sprintf( __( 'Attempting to parse a shortcode without a valid callback: %s' ), $tag ),
408 '4.3.0'
409 );
410 return $m[0];
411 }
412
413 /**
414 * Filters whether to call a shortcode callback.
415 *
416 * Returning a non-false value from filter will short-circuit the
417 * shortcode generation process, returning that value instead.
418 *
419 * @since 4.7.0
420 * @since 6.5.0 The `$attr` parameter is always an array.
421 *
422 * @param false|string $output Short-circuit return value. Either false or the value to replace the shortcode with.
423 * @param string $tag Shortcode name.
424 * @param array $attr Shortcode attributes array, can be empty if the original arguments string cannot be parsed.
425 * @param array $m Regular expression match array.
426 */
427 $return = apply_filters( 'pre_do_shortcode_tag', false, $tag, $attr, $m );
428 if ( false !== $return ) {
429 return $return;
430 }
431
432 $content = isset( $m[5] ) ? $m[5] : null;
433
434 $output = $m[1] . call_user_func( $shortcode_tags[ $tag ], $attr, $content, $tag ) . $m[6];
435
436 /**
437 * Filters the output created by a shortcode callback.
438 *
439 * @since 4.7.0
440 * @since 6.5.0 The `$attr` parameter is always an array.
441 *
442 * @param string $output Shortcode output.
443 * @param string $tag Shortcode name.
444 * @param array $attr Shortcode attributes array, can be empty if the original arguments string cannot be parsed.
445 * @param array $m Regular expression match array.
446 */
447 return apply_filters( 'do_shortcode_tag', $output, $tag, $attr, $m );
448}
449
450/**
451 * Searches only inside HTML elements for shortcodes and process them.
452 *
453 * Any [ or ] characters remaining inside elements will be HTML encoded
454 * to prevent interference with shortcodes that are outside the elements.
455 * Assumes $content processed by KSES already. Users with unfiltered_html
456 * capability may get unexpected output if angle braces are nested in tags.
457 *
458 * @since 4.2.3
459 *
460 * @param string $content Content to search for shortcodes.
461 * @param bool $ignore_html When true, all square braces inside elements will be encoded.
462 * @param array $tagnames List of shortcodes to find.
463 * @return string Content with shortcodes filtered out.
464 */
465function do_shortcodes_in_html_tags( $content, $ignore_html, $tagnames ) {
466 // Normalize entities in unfiltered HTML before adding placeholders.
467 $trans = array(
468 '&#91;' => '&#091;',
469 '&#93;' => '&#093;',
470 );
471 $content = strtr( $content, $trans );
472 $trans = array(
473 '[' => '&#91;',
474 ']' => '&#93;',
475 );
476
477 $pattern = get_shortcode_regex( $tagnames );
478 $textarr = wp_html_split( $content );
479
480 foreach ( $textarr as &$element ) {
481 if ( '' === $element || '<' !== $element[0] ) {
482 continue;
483 }
484
485 $noopen = ! str_contains( $element, '[' );
486 $noclose = ! str_contains( $element, ']' );
487 if ( $noopen || $noclose ) {
488 // This element does not contain shortcodes.
489 if ( $noopen xor $noclose ) {
490 // Need to encode stray '[' or ']' chars.
491 $element = strtr( $element, $trans );
492 }
493 continue;
494 }
495
496 if ( $ignore_html || str_starts_with( $element, '<!--' ) || str_starts_with( $element, '<![CDATA[' ) ) {
497 // Encode all '[' and ']' chars.
498 $element = strtr( $element, $trans );
499 continue;
500 }
501
502 $attributes = wp_kses_attr_parse( $element );
503 if ( false === $attributes ) {
504 // Some plugins are doing things like [name] <[email]>.
505 if ( 1 === preg_match( '%^<\s*\[\[?[^\[\]]+\]%', $element ) ) {
506 $element = preg_replace_callback( "/$pattern/", 'do_shortcode_tag', $element );
507 }
508
509 // Looks like we found some unexpected unfiltered HTML. Skipping it for confidence.
510 $element = strtr( $element, $trans );
511 continue;
512 }
513
514 // Get element name.
515 $front = array_shift( $attributes );
516 $back = array_pop( $attributes );
517 $matches = array();
518 preg_match( '%[a-zA-Z0-9]+%', $front, $matches );
519 $elname = $matches[0];
520
521 // Look for shortcodes in each attribute separately.
522 foreach ( $attributes as &$attr ) {
523 $open = strpos( $attr, '[' );
524 $close = strpos( $attr, ']' );
525 if ( false === $open || false === $close ) {
526 continue; // Go to next attribute. Square braces will be escaped at end of loop.
527 }
528 $double = strpos( $attr, '"' );
529 $single = strpos( $attr, "'" );
530 if ( ( false === $single || $open < $single ) && ( false === $double || $open < $double ) ) {
531 /*
532 * $attr like '[shortcode]' or 'name = [shortcode]' implies unfiltered_html.
533 * In this specific situation we assume KSES did not run because the input
534 * was written by an administrator, so we should avoid changing the output
535 * and we do not need to run KSES here.
536 */
537 $attr = preg_replace_callback( "/$pattern/", 'do_shortcode_tag', $attr );
538 } else {
539 /*
540 * $attr like 'name = "[shortcode]"' or "name = '[shortcode]'".
541 * We do not know if $content was unfiltered. Assume KSES ran before shortcodes.
542 */
543 $count = 0;
544 $new_attr = preg_replace_callback( "/$pattern/", 'do_shortcode_tag', $attr, -1, $count );
545 if ( $count > 0 ) {
546 // Sanitize the shortcode output using KSES.
547 $new_attr = wp_kses_one_attr( $new_attr, $elname );
548 if ( '' !== trim( $new_attr ) ) {
549 // The shortcode is safe to use now.
550 $attr = $new_attr;
551 }
552 }
553 }
554 }
555 $element = $front . implode( '', $attributes ) . $back;
556
557 // Now encode any remaining '[' or ']' chars.
558 $element = strtr( $element, $trans );
559 }
560
561 $content = implode( '', $textarr );
562
563 return $content;
564}
565
566/**
567 * Removes placeholders added by do_shortcodes_in_html_tags().
568 *
569 * @since 4.2.3
570 *
571 * @param string $content Content to search for placeholders.
572 * @return string Content with placeholders removed.
573 */
574function unescape_invalid_shortcodes( $content ) {
575 // Clean up entire string, avoids re-parsing HTML.
576 $trans = array(
577 '&#91;' => '[',
578 '&#93;' => ']',
579 );
580
581 $content = strtr( $content, $trans );
582
583 return $content;
584}
585
586/**
587 * Retrieves the shortcode attributes regex.
588 *
589 * @since 4.4.0
590 *
591 * @return string The shortcode attribute regular expression.
592 */
593function get_shortcode_atts_regex() {
594 return '/([\w-]+)\s*=\s*"([^"]*)"(?:\s|$)|([\w-]+)\s*=\s*\'([^\']*)\'(?:\s|$)|([\w-]+)\s*=\s*([^\s\'"]+)(?:\s|$)|"([^"]*)"(?:\s|$)|\'([^\']*)\'(?:\s|$)|(\S+)(?:\s|$)/';
595}
596
597/**
598 * Retrieves all attributes from the shortcodes tag.
599 *
600 * The attributes list has the attribute name as the key and the value of the
601 * attribute as the value in the key/value pair. This allows for easier
602 * retrieval of the attributes, since all attributes have to be known.
603 *
604 * @since 2.5.0
605 * @since 6.5.0 The function now always returns an array,
606 * even if the original arguments string cannot be parsed or is empty.
607 *
608 * @param string $text Shortcode arguments list.
609 * @return array Array of attribute values keyed by attribute name.
610 * Returns empty array if there are no attributes
611 * or if the original arguments string cannot be parsed.
612 */
613function shortcode_parse_atts( $text ) {
614 $atts = array();
615 $pattern = get_shortcode_atts_regex();
616 $text = preg_replace( "/[\x{00a0}\x{200b}]+/u", ' ', $text );
617 if ( preg_match_all( $pattern, $text, $match, PREG_SET_ORDER ) ) {
618 foreach ( $match as $m ) {
619 if ( ! empty( $m[1] ) ) {
620 $atts[ strtolower( $m[1] ) ] = stripcslashes( $m[2] );
621 } elseif ( ! empty( $m[3] ) ) {
622 $atts[ strtolower( $m[3] ) ] = stripcslashes( $m[4] );
623 } elseif ( ! empty( $m[5] ) ) {
624 $atts[ strtolower( $m[5] ) ] = stripcslashes( $m[6] );
625 } elseif ( isset( $m[7] ) && strlen( $m[7] ) ) {
626 $atts[] = stripcslashes( $m[7] );
627 } elseif ( isset( $m[8] ) && strlen( $m[8] ) ) {
628 $atts[] = stripcslashes( $m[8] );
629 } elseif ( isset( $m[9] ) ) {
630 $atts[] = stripcslashes( $m[9] );
631 }
632 }
633
634 // Reject any unclosed HTML elements.
635 foreach ( $atts as &$value ) {
636 if ( str_contains( $value, '<' ) ) {
637 if ( 1 !== preg_match( '/^[^<]*+(?:<[^>]*+>[^<]*+)*+$/', $value ) ) {
638 $value = '';
639 }
640 }
641 }
642 }
643
644 return $atts;
645}
646
647/**
648 * Combines user attributes with known attributes and fill in defaults when needed.
649 *
650 * The pairs should be considered to be all of the attributes which are
651 * supported by the caller and given as a list. The returned attributes will
652 * only contain the attributes in the $pairs list.
653 *
654 * If the $atts list has unsupported attributes, then they will be ignored and
655 * removed from the final returned list.
656 *
657 * @since 2.5.0
658 *
659 * @param array $pairs Entire list of supported attributes and their defaults.
660 * @param array $atts User defined attributes in shortcode tag.
661 * @param string $shortcode Optional. The name of the shortcode, provided for context to enable filtering
662 * @return array Combined and filtered attribute list.
663 */
664function shortcode_atts( $pairs, $atts, $shortcode = '' ) {
665 $atts = (array) $atts;
666 $out = array();
667 foreach ( $pairs as $name => $default ) {
668 if ( array_key_exists( $name, $atts ) ) {
669 $out[ $name ] = $atts[ $name ];
670 } else {
671 $out[ $name ] = $default;
672 }
673 }
674
675 if ( $shortcode ) {
676 /**
677 * Filters shortcode attributes.
678 *
679 * If the third parameter of the shortcode_atts() function is present then this filter is available.
680 * The third parameter, $shortcode, is the name of the shortcode.
681 *
682 * @since 3.6.0
683 * @since 4.4.0 Added the `$shortcode` parameter.
684 *
685 * @param array $out The output array of shortcode attributes.
686 * @param array $pairs The supported attributes and their defaults.
687 * @param array $atts The user defined shortcode attributes.
688 * @param string $shortcode The shortcode name.
689 */
690 $out = apply_filters( "shortcode_atts_{$shortcode}", $out, $pairs, $atts, $shortcode );
691 }
692
693 return $out;
694}
695
696/**
697 * Removes all shortcode tags from the given content.
698 *
699 * @since 2.5.0
700 *
701 * @global array $shortcode_tags
702 *
703 * @param string $content Content to remove shortcode tags.
704 * @return string Content without shortcode tags.
705 */
706function strip_shortcodes( $content ) {
707 global $shortcode_tags;
708
709 if ( ! str_contains( $content, '[' ) ) {
710 return $content;
711 }
712
713 if ( empty( $shortcode_tags ) || ! is_array( $shortcode_tags ) ) {
714 return $content;
715 }
716
717 // Find all registered tag names in $content.
718 preg_match_all( '@\[([^<>&/\[\]\x00-\x20=]++)@', $content, $matches );
719
720 $tags_to_remove = array_keys( $shortcode_tags );
721
722 /**
723 * Filters the list of shortcode tags to remove from the content.
724 *
725 * @since 4.7.0
726 *
727 * @param array $tags_to_remove Array of shortcode tags to remove.
728 * @param string $content Content shortcodes are being removed from.
729 */
730 $tags_to_remove = apply_filters( 'strip_shortcodes_tagnames', $tags_to_remove, $content );
731
732 $tagnames = array_intersect( $tags_to_remove, $matches[1] );
733
734 if ( empty( $tagnames ) ) {
735 return $content;
736 }
737
738 $content = do_shortcodes_in_html_tags( $content, true, $tagnames );
739
740 $pattern = get_shortcode_regex( $tagnames );
741 $content = preg_replace_callback( "/$pattern/", 'strip_shortcode_tag', $content );
742
743 // Always restore square braces so we don't break things like <!--[if IE ]>.
744 $content = unescape_invalid_shortcodes( $content );
745
746 return $content;
747}
748
749/**
750 * Strips a shortcode tag based on RegEx matches against post content.
751 *
752 * @since 3.3.0
753 *
754 * @param array $m RegEx matches against post content.
755 * @return string|false The content stripped of the tag, otherwise false.
756 */
757function strip_shortcode_tag( $m ) {
758 // Allow [[foo]] syntax for escaping a tag.
759 if ( '[' === $m[1] && ']' === $m[6] ) {
760 return substr( $m[0], 1, -1 );
761 }
762
763 return $m[1] . $m[6];
764}
765