Completed
Push — master ( 0191c7...c4cd1f )
by
unknown
40s
created
redux-core/inc/extensions/shortcodes/class-redux-shortcodes.php 2 patches
Indentation   +295 added lines, -295 removed lines patch added patch discarded remove patch
@@ -11,299 +11,299 @@
 block discarded – undo
11 11
 
12 12
 if ( ! class_exists( 'Redux_Shortcodes' ) ) {
13 13
 
14
-	/**
15
-	 * Redux Framework shortcode extension class. Takes the common WordPress functions `wp_get_theme()` and `bloginfo()` and a few other functions and makes them accessible via shortcodes. Below you will find a table for the possible shortcodes and their values.
16
-	 * | shortcode | Function | Description |
17
-	 * |-----------|----------|-------------|
18
-	 * | blog-name | bloginfo("name") | Displays the "Site Title" set in Settings > General. This data is retrieved from the "blogname" record in the wp_options table. |
19
-	 * | blog-description | bloginfo("description") |  Displays the "Tagline" set in Settings > General. This data is retrieved from the "blogdescription" record in the wp_options table.|
20
-	 * | blog-wpurl | bloginfo("wpurl") |  Displays the "WordPress address (URL)" set in Settings > General. This data is retrieved from the "siteurl" record in the wp_options table. Consider using **blog-root_url** instead, especially for multi-site configurations using paths instead of subdomains (it will return the root site not the current sub-site). |
21
-	 * | blog-root_url | site_url() |  Return the root site, not the current sub-site. |
22
-	 * | blog-url | home_url() |  Displays the "Site address (URL)" set in Settings > General. This data is retrieved from the "home" record in the wp_options table. |
23
-	 * | blog-admin_email | bloginfo("admin_email") |  Displays the "E-mail address" set in Settings > General. This data is retrieved from the "admin_email" record in the wp_options table.|
24
-	 * | blog-charset | bloginfo("charset") |  Displays the "Encoding for pages and feeds" set in Settings > Reading. This data is retrieved from the "blog_charset" record in the wp_options table. Note: In Version 3.5.0 and later, character encoding is no longer configurable from the Administration Panel. Therefore, this parameter always echoes "UTF-8", which is the default encoding of WordPress.|
25
-	 * | blog-version | bloginfo("version") |  Displays the WordPress Version you use. This data is retrieved from the $wp_version variable set in wp-includes/version.php.|
26
-	 * | blog-html_type | bloginfo("html_type") |  Displays the Content-Type of WordPress HTML pages (default: "text/html"). This data is retrieved from the "html_type" record in the wp_options table. Themes and plugins can override the default value using the pre_option_html_type filter.|
27
-	 * | blog-text_direction | bloginfo("text_direction") |  Displays the Text Direction of WordPress HTML pages. Consider using **blog-text_direction_boolean** instead if you want a true/false response. |
28
-	 * | blog-text_direction_boolean | is_rtl() |  Displays true/false check if the Text Direction of WordPress HTML pages is left instead of right |
29
-	 * | blog-language | bloginfo("language") |  Displays the language of WordPress.|
30
-	 * | blog-stylesheet_url | get_stylesheet_uri() |  Displays the primary CSS (usually style.css) file URL of the active theme. |
31
-	 * | blog-stylesheet_directory | bloginfo("stylesheet_directory") |  Displays the stylesheet directory URL of the active theme. (Was a local path in earlier WordPress versions.) Consider echoing get_stylesheet_directory_uri() instead.|
32
-	 * | blog-template_url | get_template_directory_uri() |  Parent template uri. Consider using **blog-child_template_url** for the child template URI. |
33
-	 * | blog-child_template_url | get_stylesheet_directory_uri() | Child template URI. |
34
-	 * | blog-pingback_url | bloginfo("pingback_url") |  Displays the Pingback XML-RPC file URL (xmlrpc.php).|
35
-	 * | blog-atom_url | bloginfo("atom_url") |  Displays the Atom feed URL (/feed/atom).|
36
-	 * | blog-rdf_url | bloginfo("rdf_url") |  Displays the RDF/RSS 1.0 feed URL (/feed/rfd).|
37
-	 * | blog-rss_url | bloginfo("rss_url") |  Displays the RSS 0.92 feed URL (/feed/rss).|
38
-	 * | blog-rss2_url | bloginfo("rss2_url") |  Displays the RSS 2.0 feed URL (/feed).|
39
-	 * | blog-comments_atom_url | bloginfo("comments_atom_url") |  Displays the comments Atom feed URL (/comments/feed).|
40
-	 * | blog-comments_rss2_url | bloginfo("comments_rss2_url") |  Displays the comments RSS 2.0 feed URL (/comments/feed).|
41
-	 * | login-url | wp_login_url() | Returns the WordPress login URL. |
42
-	 * | login-url | wp_logout_url() | Returns the WordPress logout URL. |
43
-	 * | current_year | date("Y") | Returns the current year. |
44
-	 * | theme-name | $theme_info->get("Name") | Theme name as given in theme's style.css |
45
-	 * | theme-uri | $theme_info->get("ThemeURI") | The path to the theme's directory |
46
-	 * | theme-description | $theme_info->get("Description") | The description of the theme |
47
-	 * | theme-author | $theme_info->get("Author") | The theme's author |
48
-	 * | theme-author_uri | $theme_info->get("AuthorURI") | The website of the theme author |
49
-	 * | theme-version | $theme_info->get("Version") | The version of the theme |
50
-	 * | theme-template | $theme_info->get("Template") | The folder name of the current theme |
51
-	 * | theme-status | $theme_info->get("Status") | If the theme is published |
52
-	 * | theme-tags | $theme_info->get("Tags") | Tags used to describe the theme |
53
-	 * | theme-text_domain | $theme_info->get("TextDomain") | The text domain used in the theme for translation purposes |
54
-	 * | theme-domain_path | $theme_info->get("DomainPath") | Path to the theme translation files |
55
-	 *
56
-	 * @version 1.0.0
57
-	 */
58
-
59
-	/**
60
-	 * Class Redux_Shortcodes
61
-	 */
62
-	class Redux_Shortcodes {
63
-
64
-		/**
65
-		 * Redux_Shortcodes constructor.
66
-		 */
67
-		public function __construct() {
68
-			if ( ! shortcode_exists( 'bloginfo' ) ) {
69
-				add_shortcode( 'bloginfo', array( $this, 'blog_info' ) );
70
-			} else {
71
-				add_shortcode( 'redux_bloginfo', array( $this, 'blog_info' ) );
72
-			}
73
-
74
-			if ( ! shortcode_exists( 'themeinfo' ) ) {
75
-				add_shortcode( 'themeinfo', array( $this, 'theme_info' ) );
76
-			} else {
77
-				add_shortcode( 'redux_themeinfo', array( $this, 'theme_info' ) );
78
-			}
79
-
80
-			if ( ! shortcode_exists( 'date' ) ) {
81
-				add_shortcode( 'date', array( $this, 'date' ) );
82
-			} else {
83
-				add_shortcode( 'redux_date', array( $this, 'date' ) );
84
-			}
85
-		}
86
-
87
-		/**
88
-		 * Return site/blog info by a validated selector.
89
-		 * Assumes the return value is printed into HTML (text node).
90
-		 * If you need raw values for other contexts, remove the esc_* here
91
-		 * and escape at the final render point instead.
92
-		 *
93
-		 * @param array|string $atts    Attributes.
94
-		 * @param string|null  $content Content.
95
-		 *
96
-		 * @return string Escaped for HTML text (URLs are escaped with esc_url()).
97
-		 */
98
-		public function blog_info( $atts = array(), ?string $content = null ): string {
99
-
100
-			// Normalize and merge defaults.
101
-			$atts = is_array( $atts ) ? wp_unslash( $atts ) : array();
102
-			$atts = shortcode_atts(
103
-				array(
104
-					'data' => '',
105
-				),
106
-				$atts
107
-			);
108
-
109
-			// Allow content as fallback for the selector.
110
-			if ( null !== $content && '' === $atts['data'] ) {
111
-				$atts['data'] = $content;
112
-			}
113
-
114
-			// Validate selector as a key and clamp length.
115
-			$key = substr( sanitize_key( $atts['data'] ), 0, 64 );
116
-
117
-			// Map aliases -> handlers.
118
-			// Keep your original intent (filesystem paths vs URIs) but make it safe and explicit.
119
-			switch ( $key ) {
120
-				// Filesystem paths (escape as text).
121
-				case 'stylesheet_directory':
122
-				case 'child_template_directory':
123
-					return esc_html( get_stylesheet_directory() );
124
-
125
-				case 'template_directory':
126
-					return esc_html( get_template_directory() );
127
-
128
-				// Theme URIs.
129
-				case 'parent_template_url':
130
-					return esc_url( get_template_directory_uri() );
131
-
132
-				case 'child_template_url':
133
-				case 'template_url':
134
-					return esc_url( get_stylesheet_directory_uri() );
135
-
136
-				// URLs.
137
-				case 'url':
138
-					return esc_url( home_url() );
139
-
140
-				case 'root_url':
141
-					return esc_url( site_url() );
142
-
143
-				case 'stylesheet_url':
144
-					return esc_url( get_stylesheet_uri() );
145
-
146
-				case 'logout_url':
147
-					return esc_url( wp_logout_url() );
148
-
149
-				case 'login_url':
150
-					return esc_url( wp_login_url() );
151
-
152
-				case 'register_url':
153
-					return esc_url( wp_registration_url() );
154
-
155
-				case 'lostpassword_url':
156
-				case 'lost_password_url':
157
-					return esc_url( wp_lostpassword_url() );
158
-
159
-				// Booleans.
160
-				case 'text_direction_bool':
161
-				case 'text_direction_boolean':
162
-					return esc_html( is_rtl() ? '1' : '0' );
163
-
164
-				case 'is_multisite':
165
-					return esc_html( is_multisite() ? '1' : '0' );
166
-
167
-				// Text direction as string.
168
-				case 'text_direction':
169
-					return esc_html( is_rtl() ? 'rtl' : 'ltr' );
170
-
171
-				default:
172
-					// Safe fallback: pull raw blog info, then escape as text.
173
-					// (Avoid over-sanitizing: this is trusted core data).
174
-					$value = get_bloginfo( $key );
175
-					return esc_html( (string) $value );
176
-			}
177
-		}
178
-
179
-		/**
180
-		 * Get theme info.
181
-		 *
182
-		 * @param array|string $atts    Attributes.
183
-		 * @param string|null  $content Content.
184
-		 *
185
-		 * @return string
186
-		 */
187
-		public function theme_info( array $atts = array(), ?string $content = null ): string {
188
-			// Normalize input and merge defaults.
189
-			$atts = wp_unslash( $atts );
190
-			$atts = shortcode_atts(
191
-				array(
192
-					'data' => '',
193
-				),
194
-				$atts
195
-			);
196
-
197
-			// Allow content as a fallback selector.
198
-			if ( null !== $content && '' === $atts['data'] ) {
199
-				$atts['data'] = $content;
200
-			}
201
-
202
-			// Validate selector as a key.
203
-			$key = sanitize_key( $atts['data'] );
204
-
205
-			// Map aliases -> canonical WP_Theme header keys or special handlers.
206
-			$map = array(
207
-				'name'        => 'Name',
208
-				'themeuri'    => 'ThemeURI',
209
-				'theme_uri'   => 'ThemeURI',
210
-				'description' => 'Description',
211
-				'author'      => 'Author',
212
-				'authoruri'   => 'AuthorURI',
213
-				'author_uri'  => 'AuthorURI',
214
-				'version'     => 'Version',
215
-				'template'    => 'Template',
216
-				'status'      => 'Status',
217
-				'tags'        => 'Tags',
218
-				'textdomain'  => 'TextDomain',
219
-				'text_domain' => 'TextDomain',
220
-				'domainpath'  => 'DomainPath',
221
-				'domain_path' => 'DomainPath',
222
-				'is_child'    => 'is_child', // special case.
223
-			);
224
-
225
-			// Default to "name" when empty or unknown.
226
-			if ( '' === $key || ! isset( $map[ $key ] ) ) {
227
-				$key = 'name';
228
-			}
229
-
230
-			// Cache theme object.
231
-			if ( empty( $this->theme_info ) ) {
232
-				$this->theme_info = wp_get_theme();
233
-			}
234
-
235
-			$canonical = $map[ $key ];
236
-
237
-			// Special case: is_child — return "1" or "0" as string.
238
-			if ( 'is_child' === $canonical ) {
239
-				$bool = Redux_Helpers::is_child_theme( get_template_directory() );
240
-				return esc_html( $bool ? '1' : '0' );
241
-			}
242
-
243
-			$value = $this->theme_info->get( $canonical );
244
-
245
-			// WP_Theme::get('Tags') may be array; normalize to string.
246
-			if ( is_array( $value ) ) {
247
-				$value = implode( ', ', array_filter( array_map( 'trim', $value ) ) );
248
-			}
249
-
250
-			$value = (string) $value;
251
-
252
-			// Escape by context.
253
-			switch ( $canonical ) {
254
-				case 'ThemeURI':
255
-				case 'AuthorURI':
256
-					// If you ultimately print this inside an href, escape at that final context instead.
257
-					// Here we assume the plain text output of the URL.
258
-					return esc_url( $value );
259
-
260
-				default:
261
-					return esc_html( $value );
262
-			}
263
-		}
264
-
265
-		/**
266
-		 * Get date info.
267
-		 *
268
-		 * @param array|string $atts    Attributes.
269
-		 * @param string|null  $content Content.
270
-		 *
271
-		 * @return string
272
-		 */
273
-		public function date( $atts = array(), ?string $content = null ): string {
274
-
275
-			// 1) Normalize + unslash
276
-			$atts = is_array( $atts ) ? wp_unslash( $atts ) : array();
277
-
278
-			// 2) Default/merge (if this is a shortcode handler, pass the tag as the 3rd arg)
279
-			$atts = shortcode_atts(
280
-				array(
281
-					'data' => '',
282
-				),
283
-				$atts
284
-			);
285
-
286
-			// 3) Allow content as a fallback for the format
287
-			if ( null !== $content && '' === $atts['data'] ) {
288
-				// Keep content simple text; strip tags and control chars.
289
-				$atts['data'] = sanitize_text_field( wp_unslash( $content ) );
290
-			}
291
-
292
-			// 4) Validate and constrain the format string
293
-			$format = (string) $atts['data'];
294
-			$format = substr( $format, 0, 64 ); // avoid absurdly long inputs.
295
-
296
-			// Allow common date format tokens + typical literal punctuation and backslash for escaping.
297
-			// If invalid chars are present, fall back to a safe default.
298
-			if ( '' === $format || ! preg_match( '/^[A-Za-z0-9\s:\-.,\/\\\\T]+$/', $format ) ) {
299
-				$format = 'Y';
300
-			}
301
-
302
-			// 5) Use wp_date() to respect WP timezone and locale (date_i18n is deprecated).
303
-			$output = wp_date( $format );
304
-
305
-			// 6) Escape for HTML context before returning (safe default for shortcode/rendered output).
306
-			return esc_html( $output );
307
-		}
308
-	}
14
+    /**
15
+     * Redux Framework shortcode extension class. Takes the common WordPress functions `wp_get_theme()` and `bloginfo()` and a few other functions and makes them accessible via shortcodes. Below you will find a table for the possible shortcodes and their values.
16
+     * | shortcode | Function | Description |
17
+     * |-----------|----------|-------------|
18
+     * | blog-name | bloginfo("name") | Displays the "Site Title" set in Settings > General. This data is retrieved from the "blogname" record in the wp_options table. |
19
+     * | blog-description | bloginfo("description") |  Displays the "Tagline" set in Settings > General. This data is retrieved from the "blogdescription" record in the wp_options table.|
20
+     * | blog-wpurl | bloginfo("wpurl") |  Displays the "WordPress address (URL)" set in Settings > General. This data is retrieved from the "siteurl" record in the wp_options table. Consider using **blog-root_url** instead, especially for multi-site configurations using paths instead of subdomains (it will return the root site not the current sub-site). |
21
+     * | blog-root_url | site_url() |  Return the root site, not the current sub-site. |
22
+     * | blog-url | home_url() |  Displays the "Site address (URL)" set in Settings > General. This data is retrieved from the "home" record in the wp_options table. |
23
+     * | blog-admin_email | bloginfo("admin_email") |  Displays the "E-mail address" set in Settings > General. This data is retrieved from the "admin_email" record in the wp_options table.|
24
+     * | blog-charset | bloginfo("charset") |  Displays the "Encoding for pages and feeds" set in Settings > Reading. This data is retrieved from the "blog_charset" record in the wp_options table. Note: In Version 3.5.0 and later, character encoding is no longer configurable from the Administration Panel. Therefore, this parameter always echoes "UTF-8", which is the default encoding of WordPress.|
25
+     * | blog-version | bloginfo("version") |  Displays the WordPress Version you use. This data is retrieved from the $wp_version variable set in wp-includes/version.php.|
26
+     * | blog-html_type | bloginfo("html_type") |  Displays the Content-Type of WordPress HTML pages (default: "text/html"). This data is retrieved from the "html_type" record in the wp_options table. Themes and plugins can override the default value using the pre_option_html_type filter.|
27
+     * | blog-text_direction | bloginfo("text_direction") |  Displays the Text Direction of WordPress HTML pages. Consider using **blog-text_direction_boolean** instead if you want a true/false response. |
28
+     * | blog-text_direction_boolean | is_rtl() |  Displays true/false check if the Text Direction of WordPress HTML pages is left instead of right |
29
+     * | blog-language | bloginfo("language") |  Displays the language of WordPress.|
30
+     * | blog-stylesheet_url | get_stylesheet_uri() |  Displays the primary CSS (usually style.css) file URL of the active theme. |
31
+     * | blog-stylesheet_directory | bloginfo("stylesheet_directory") |  Displays the stylesheet directory URL of the active theme. (Was a local path in earlier WordPress versions.) Consider echoing get_stylesheet_directory_uri() instead.|
32
+     * | blog-template_url | get_template_directory_uri() |  Parent template uri. Consider using **blog-child_template_url** for the child template URI. |
33
+     * | blog-child_template_url | get_stylesheet_directory_uri() | Child template URI. |
34
+     * | blog-pingback_url | bloginfo("pingback_url") |  Displays the Pingback XML-RPC file URL (xmlrpc.php).|
35
+     * | blog-atom_url | bloginfo("atom_url") |  Displays the Atom feed URL (/feed/atom).|
36
+     * | blog-rdf_url | bloginfo("rdf_url") |  Displays the RDF/RSS 1.0 feed URL (/feed/rfd).|
37
+     * | blog-rss_url | bloginfo("rss_url") |  Displays the RSS 0.92 feed URL (/feed/rss).|
38
+     * | blog-rss2_url | bloginfo("rss2_url") |  Displays the RSS 2.0 feed URL (/feed).|
39
+     * | blog-comments_atom_url | bloginfo("comments_atom_url") |  Displays the comments Atom feed URL (/comments/feed).|
40
+     * | blog-comments_rss2_url | bloginfo("comments_rss2_url") |  Displays the comments RSS 2.0 feed URL (/comments/feed).|
41
+     * | login-url | wp_login_url() | Returns the WordPress login URL. |
42
+     * | login-url | wp_logout_url() | Returns the WordPress logout URL. |
43
+     * | current_year | date("Y") | Returns the current year. |
44
+     * | theme-name | $theme_info->get("Name") | Theme name as given in theme's style.css |
45
+     * | theme-uri | $theme_info->get("ThemeURI") | The path to the theme's directory |
46
+     * | theme-description | $theme_info->get("Description") | The description of the theme |
47
+     * | theme-author | $theme_info->get("Author") | The theme's author |
48
+     * | theme-author_uri | $theme_info->get("AuthorURI") | The website of the theme author |
49
+     * | theme-version | $theme_info->get("Version") | The version of the theme |
50
+     * | theme-template | $theme_info->get("Template") | The folder name of the current theme |
51
+     * | theme-status | $theme_info->get("Status") | If the theme is published |
52
+     * | theme-tags | $theme_info->get("Tags") | Tags used to describe the theme |
53
+     * | theme-text_domain | $theme_info->get("TextDomain") | The text domain used in the theme for translation purposes |
54
+     * | theme-domain_path | $theme_info->get("DomainPath") | Path to the theme translation files |
55
+     *
56
+     * @version 1.0.0
57
+     */
58
+
59
+    /**
60
+     * Class Redux_Shortcodes
61
+     */
62
+    class Redux_Shortcodes {
63
+
64
+        /**
65
+         * Redux_Shortcodes constructor.
66
+         */
67
+        public function __construct() {
68
+            if ( ! shortcode_exists( 'bloginfo' ) ) {
69
+                add_shortcode( 'bloginfo', array( $this, 'blog_info' ) );
70
+            } else {
71
+                add_shortcode( 'redux_bloginfo', array( $this, 'blog_info' ) );
72
+            }
73
+
74
+            if ( ! shortcode_exists( 'themeinfo' ) ) {
75
+                add_shortcode( 'themeinfo', array( $this, 'theme_info' ) );
76
+            } else {
77
+                add_shortcode( 'redux_themeinfo', array( $this, 'theme_info' ) );
78
+            }
79
+
80
+            if ( ! shortcode_exists( 'date' ) ) {
81
+                add_shortcode( 'date', array( $this, 'date' ) );
82
+            } else {
83
+                add_shortcode( 'redux_date', array( $this, 'date' ) );
84
+            }
85
+        }
86
+
87
+        /**
88
+         * Return site/blog info by a validated selector.
89
+         * Assumes the return value is printed into HTML (text node).
90
+         * If you need raw values for other contexts, remove the esc_* here
91
+         * and escape at the final render point instead.
92
+         *
93
+         * @param array|string $atts    Attributes.
94
+         * @param string|null  $content Content.
95
+         *
96
+         * @return string Escaped for HTML text (URLs are escaped with esc_url()).
97
+         */
98
+        public function blog_info( $atts = array(), ?string $content = null ): string {
99
+
100
+            // Normalize and merge defaults.
101
+            $atts = is_array( $atts ) ? wp_unslash( $atts ) : array();
102
+            $atts = shortcode_atts(
103
+                array(
104
+                    'data' => '',
105
+                ),
106
+                $atts
107
+            );
108
+
109
+            // Allow content as fallback for the selector.
110
+            if ( null !== $content && '' === $atts['data'] ) {
111
+                $atts['data'] = $content;
112
+            }
113
+
114
+            // Validate selector as a key and clamp length.
115
+            $key = substr( sanitize_key( $atts['data'] ), 0, 64 );
116
+
117
+            // Map aliases -> handlers.
118
+            // Keep your original intent (filesystem paths vs URIs) but make it safe and explicit.
119
+            switch ( $key ) {
120
+                // Filesystem paths (escape as text).
121
+                case 'stylesheet_directory':
122
+                case 'child_template_directory':
123
+                    return esc_html( get_stylesheet_directory() );
124
+
125
+                case 'template_directory':
126
+                    return esc_html( get_template_directory() );
127
+
128
+                // Theme URIs.
129
+                case 'parent_template_url':
130
+                    return esc_url( get_template_directory_uri() );
131
+
132
+                case 'child_template_url':
133
+                case 'template_url':
134
+                    return esc_url( get_stylesheet_directory_uri() );
135
+
136
+                // URLs.
137
+                case 'url':
138
+                    return esc_url( home_url() );
139
+
140
+                case 'root_url':
141
+                    return esc_url( site_url() );
142
+
143
+                case 'stylesheet_url':
144
+                    return esc_url( get_stylesheet_uri() );
145
+
146
+                case 'logout_url':
147
+                    return esc_url( wp_logout_url() );
148
+
149
+                case 'login_url':
150
+                    return esc_url( wp_login_url() );
151
+
152
+                case 'register_url':
153
+                    return esc_url( wp_registration_url() );
154
+
155
+                case 'lostpassword_url':
156
+                case 'lost_password_url':
157
+                    return esc_url( wp_lostpassword_url() );
158
+
159
+                // Booleans.
160
+                case 'text_direction_bool':
161
+                case 'text_direction_boolean':
162
+                    return esc_html( is_rtl() ? '1' : '0' );
163
+
164
+                case 'is_multisite':
165
+                    return esc_html( is_multisite() ? '1' : '0' );
166
+
167
+                // Text direction as string.
168
+                case 'text_direction':
169
+                    return esc_html( is_rtl() ? 'rtl' : 'ltr' );
170
+
171
+                default:
172
+                    // Safe fallback: pull raw blog info, then escape as text.
173
+                    // (Avoid over-sanitizing: this is trusted core data).
174
+                    $value = get_bloginfo( $key );
175
+                    return esc_html( (string) $value );
176
+            }
177
+        }
178
+
179
+        /**
180
+         * Get theme info.
181
+         *
182
+         * @param array|string $atts    Attributes.
183
+         * @param string|null  $content Content.
184
+         *
185
+         * @return string
186
+         */
187
+        public function theme_info( array $atts = array(), ?string $content = null ): string {
188
+            // Normalize input and merge defaults.
189
+            $atts = wp_unslash( $atts );
190
+            $atts = shortcode_atts(
191
+                array(
192
+                    'data' => '',
193
+                ),
194
+                $atts
195
+            );
196
+
197
+            // Allow content as a fallback selector.
198
+            if ( null !== $content && '' === $atts['data'] ) {
199
+                $atts['data'] = $content;
200
+            }
201
+
202
+            // Validate selector as a key.
203
+            $key = sanitize_key( $atts['data'] );
204
+
205
+            // Map aliases -> canonical WP_Theme header keys or special handlers.
206
+            $map = array(
207
+                'name'        => 'Name',
208
+                'themeuri'    => 'ThemeURI',
209
+                'theme_uri'   => 'ThemeURI',
210
+                'description' => 'Description',
211
+                'author'      => 'Author',
212
+                'authoruri'   => 'AuthorURI',
213
+                'author_uri'  => 'AuthorURI',
214
+                'version'     => 'Version',
215
+                'template'    => 'Template',
216
+                'status'      => 'Status',
217
+                'tags'        => 'Tags',
218
+                'textdomain'  => 'TextDomain',
219
+                'text_domain' => 'TextDomain',
220
+                'domainpath'  => 'DomainPath',
221
+                'domain_path' => 'DomainPath',
222
+                'is_child'    => 'is_child', // special case.
223
+            );
224
+
225
+            // Default to "name" when empty or unknown.
226
+            if ( '' === $key || ! isset( $map[ $key ] ) ) {
227
+                $key = 'name';
228
+            }
229
+
230
+            // Cache theme object.
231
+            if ( empty( $this->theme_info ) ) {
232
+                $this->theme_info = wp_get_theme();
233
+            }
234
+
235
+            $canonical = $map[ $key ];
236
+
237
+            // Special case: is_child — return "1" or "0" as string.
238
+            if ( 'is_child' === $canonical ) {
239
+                $bool = Redux_Helpers::is_child_theme( get_template_directory() );
240
+                return esc_html( $bool ? '1' : '0' );
241
+            }
242
+
243
+            $value = $this->theme_info->get( $canonical );
244
+
245
+            // WP_Theme::get('Tags') may be array; normalize to string.
246
+            if ( is_array( $value ) ) {
247
+                $value = implode( ', ', array_filter( array_map( 'trim', $value ) ) );
248
+            }
249
+
250
+            $value = (string) $value;
251
+
252
+            // Escape by context.
253
+            switch ( $canonical ) {
254
+                case 'ThemeURI':
255
+                case 'AuthorURI':
256
+                    // If you ultimately print this inside an href, escape at that final context instead.
257
+                    // Here we assume the plain text output of the URL.
258
+                    return esc_url( $value );
259
+
260
+                default:
261
+                    return esc_html( $value );
262
+            }
263
+        }
264
+
265
+        /**
266
+         * Get date info.
267
+         *
268
+         * @param array|string $atts    Attributes.
269
+         * @param string|null  $content Content.
270
+         *
271
+         * @return string
272
+         */
273
+        public function date( $atts = array(), ?string $content = null ): string {
274
+
275
+            // 1) Normalize + unslash
276
+            $atts = is_array( $atts ) ? wp_unslash( $atts ) : array();
277
+
278
+            // 2) Default/merge (if this is a shortcode handler, pass the tag as the 3rd arg)
279
+            $atts = shortcode_atts(
280
+                array(
281
+                    'data' => '',
282
+                ),
283
+                $atts
284
+            );
285
+
286
+            // 3) Allow content as a fallback for the format
287
+            if ( null !== $content && '' === $atts['data'] ) {
288
+                // Keep content simple text; strip tags and control chars.
289
+                $atts['data'] = sanitize_text_field( wp_unslash( $content ) );
290
+            }
291
+
292
+            // 4) Validate and constrain the format string
293
+            $format = (string) $atts['data'];
294
+            $format = substr( $format, 0, 64 ); // avoid absurdly long inputs.
295
+
296
+            // Allow common date format tokens + typical literal punctuation and backslash for escaping.
297
+            // If invalid chars are present, fall back to a safe default.
298
+            if ( '' === $format || ! preg_match( '/^[A-Za-z0-9\s:\-.,\/\\\\T]+$/', $format ) ) {
299
+                $format = 'Y';
300
+            }
301
+
302
+            // 5) Use wp_date() to respect WP timezone and locale (date_i18n is deprecated).
303
+            $output = wp_date( $format );
304
+
305
+            // 6) Escape for HTML context before returning (safe default for shortcode/rendered output).
306
+            return esc_html( $output );
307
+        }
308
+    }
309 309
 }
Please login to merge, or discard this patch.
Spacing   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -172,7 +172,7 @@  discard block
 block discarded – undo
172 172
 					// Safe fallback: pull raw blog info, then escape as text.
173 173
 					// (Avoid over-sanitizing: this is trusted core data).
174 174
 					$value = get_bloginfo( $key );
175
-					return esc_html( (string) $value );
175
+					return esc_html( ( string ) $value );
176 176
 			}
177 177
 		}
178 178
 
@@ -223,7 +223,7 @@  discard block
 block discarded – undo
223 223
 			);
224 224
 
225 225
 			// Default to "name" when empty or unknown.
226
-			if ( '' === $key || ! isset( $map[ $key ] ) ) {
226
+			if ( '' === $key || ! isset( $map[$key] ) ) {
227 227
 				$key = 'name';
228 228
 			}
229 229
 
@@ -232,7 +232,7 @@  discard block
 block discarded – undo
232 232
 				$this->theme_info = wp_get_theme();
233 233
 			}
234 234
 
235
-			$canonical = $map[ $key ];
235
+			$canonical = $map[$key];
236 236
 
237 237
 			// Special case: is_child — return "1" or "0" as string.
238 238
 			if ( 'is_child' === $canonical ) {
@@ -247,7 +247,7 @@  discard block
 block discarded – undo
247 247
 				$value = implode( ', ', array_filter( array_map( 'trim', $value ) ) );
248 248
 			}
249 249
 
250
-			$value = (string) $value;
250
+			$value = ( string ) $value;
251 251
 
252 252
 			// Escape by context.
253 253
 			switch ( $canonical ) {
@@ -290,7 +290,7 @@  discard block
 block discarded – undo
290 290
 			}
291 291
 
292 292
 			// 4) Validate and constrain the format string
293
-			$format = (string) $atts['data'];
293
+			$format = ( string ) $atts['data'];
294 294
 			$format = substr( $format, 0, 64 ); // avoid absurdly long inputs.
295 295
 
296 296
 			// Allow common date format tokens + typical literal punctuation and backslash for escaping.
Please login to merge, or discard this patch.