|
1 <?php |
|
2 /** |
|
3 * Sitemaps: WP_Sitemaps_Stylesheet class |
|
4 * |
|
5 * This class provides the XSL stylesheets to style all sitemaps. |
|
6 * |
|
7 * @package WordPress |
|
8 * @subpackage Sitemaps |
|
9 * @since 5.5.0 |
|
10 */ |
|
11 |
|
12 /** |
|
13 * Stylesheet provider class. |
|
14 * |
|
15 * @since 5.5.0 |
|
16 */ |
|
17 class WP_Sitemaps_Stylesheet { |
|
18 /** |
|
19 * Renders the XSL stylesheet depending on whether it's the sitemap index or not. |
|
20 * |
|
21 * @param string $type Stylesheet type. Either 'sitemap' or 'index'. |
|
22 */ |
|
23 public function render_stylesheet( $type ) { |
|
24 header( 'Content-type: application/xml; charset=UTF-8' ); |
|
25 |
|
26 if ( 'sitemap' === $type ) { |
|
27 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- All content escaped below. |
|
28 echo $this->get_sitemap_stylesheet(); |
|
29 } |
|
30 |
|
31 if ( 'index' === $type ) { |
|
32 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- All content escaped below. |
|
33 echo $this->get_sitemap_index_stylesheet(); |
|
34 } |
|
35 |
|
36 exit; |
|
37 } |
|
38 |
|
39 /** |
|
40 * Returns the escaped XSL for all sitemaps, except index. |
|
41 * |
|
42 * @since 5.5.0 |
|
43 */ |
|
44 public function get_sitemap_stylesheet() { |
|
45 $css = $this->get_stylesheet_css(); |
|
46 $title = esc_xml( __( 'XML Sitemap' ) ); |
|
47 $description = esc_xml( __( 'This XML Sitemap is generated by WordPress to make your content more visible for search engines.' ) ); |
|
48 $learn_more = sprintf( |
|
49 '<a href="%s">%s</a>', |
|
50 esc_url( __( 'https://www.sitemaps.org/' ) ), |
|
51 esc_xml( __( 'Learn more about XML sitemaps.' ) ) |
|
52 ); |
|
53 |
|
54 $text = sprintf( |
|
55 /* translators: %s: Number of URLs. */ |
|
56 esc_xml( __( 'Number of URLs in this XML Sitemap: %s.' ) ), |
|
57 '<xsl:value-of select="count( sitemap:urlset/sitemap:url )" />' |
|
58 ); |
|
59 |
|
60 $lang = get_language_attributes( 'html' ); |
|
61 $url = esc_xml( __( 'URL' ) ); |
|
62 $lastmod = esc_xml( __( 'Last Modified' ) ); |
|
63 $changefreq = esc_xml( __( 'Change Frequency' ) ); |
|
64 $priority = esc_xml( __( 'Priority' ) ); |
|
65 |
|
66 $xsl_content = <<<XSL |
|
67 <?xml version="1.0" encoding="UTF-8"?> |
|
68 <xsl:stylesheet |
|
69 version="1.0" |
|
70 xmlns:xsl="http://www.w3.org/1999/XSL/Transform" |
|
71 xmlns:sitemap="http://www.sitemaps.org/schemas/sitemap/0.9" |
|
72 exclude-result-prefixes="sitemap" |
|
73 > |
|
74 |
|
75 <xsl:output method="html" encoding="UTF-8" indent="yes"/> |
|
76 |
|
77 <!-- |
|
78 Set variables for whether lastmod, changefreq or priority occur for any url in the sitemap. |
|
79 We do this up front because it can be expensive in a large sitemap. |
|
80 --> |
|
81 <xsl:variable name="has-lastmod" select="count( /sitemap:urlset/sitemap:url/sitemap:lastmod )" /> |
|
82 <xsl:variable name="has-changefreq" select="count( /sitemap:urlset/sitemap:url/sitemap:changefreq )" /> |
|
83 <xsl:variable name="has-priority" select="count( /sitemap:urlset/sitemap:url/sitemap:priority )" /> |
|
84 |
|
85 <xsl:template match="/"> |
|
86 <html {$lang}> |
|
87 <head> |
|
88 <title>{$title}</title> |
|
89 <style> |
|
90 {$css} |
|
91 </style> |
|
92 </head> |
|
93 <body> |
|
94 <div id="sitemap"> |
|
95 <div id="sitemap__header"> |
|
96 <h1>{$title}</h1> |
|
97 <p>{$description}</p> |
|
98 <p>{$learn_more}</p> |
|
99 </div> |
|
100 <div id="sitemap__content"> |
|
101 <p class="text">{$text}</p> |
|
102 <table id="sitemap__table"> |
|
103 <thead> |
|
104 <tr> |
|
105 <th class="loc">{$url}</th> |
|
106 <xsl:if test="\$has-lastmod"> |
|
107 <th class="lastmod">{$lastmod}</th> |
|
108 </xsl:if> |
|
109 <xsl:if test="\$has-changefreq"> |
|
110 <th class="changefreq">{$changefreq}</th> |
|
111 </xsl:if> |
|
112 <xsl:if test="\$has-priority"> |
|
113 <th class="priority">{$priority}</th> |
|
114 </xsl:if> |
|
115 </tr> |
|
116 </thead> |
|
117 <tbody> |
|
118 <xsl:for-each select="sitemap:urlset/sitemap:url"> |
|
119 <tr> |
|
120 <td class="loc"><a href="{sitemap:loc}"><xsl:value-of select="sitemap:loc" /></a></td> |
|
121 <xsl:if test="\$has-lastmod"> |
|
122 <td class="lastmod"><xsl:value-of select="sitemap:lastmod" /></td> |
|
123 </xsl:if> |
|
124 <xsl:if test="\$has-changefreq"> |
|
125 <td class="changefreq"><xsl:value-of select="sitemap:changefreq" /></td> |
|
126 </xsl:if> |
|
127 <xsl:if test="\$has-priority"> |
|
128 <td class="priority"><xsl:value-of select="sitemap:priority" /></td> |
|
129 </xsl:if> |
|
130 </tr> |
|
131 </xsl:for-each> |
|
132 </tbody> |
|
133 </table> |
|
134 </div> |
|
135 </div> |
|
136 </body> |
|
137 </html> |
|
138 </xsl:template> |
|
139 </xsl:stylesheet> |
|
140 |
|
141 XSL; |
|
142 |
|
143 /** |
|
144 * Filters the content of the sitemap stylesheet. |
|
145 * |
|
146 * @since 5.5.0 |
|
147 * |
|
148 * @param string $xsl_content Full content for the XML stylesheet. |
|
149 */ |
|
150 return apply_filters( 'wp_sitemaps_stylesheet_content', $xsl_content ); |
|
151 } |
|
152 |
|
153 /** |
|
154 * Returns the escaped XSL for the index sitemaps. |
|
155 * |
|
156 * @since 5.5.0 |
|
157 */ |
|
158 public function get_sitemap_index_stylesheet() { |
|
159 $css = $this->get_stylesheet_css(); |
|
160 $title = esc_xml( __( 'XML Sitemap' ) ); |
|
161 $description = esc_xml( __( 'This XML Sitemap is generated by WordPress to make your content more visible for search engines.' ) ); |
|
162 $learn_more = sprintf( |
|
163 '<a href="%s">%s</a>', |
|
164 esc_url( __( 'https://www.sitemaps.org/' ) ), |
|
165 esc_xml( __( 'Learn more about XML sitemaps.' ) ) |
|
166 ); |
|
167 |
|
168 $text = sprintf( |
|
169 /* translators: %s: Number of URLs. */ |
|
170 esc_xml( __( 'Number of URLs in this XML Sitemap: %s.' ) ), |
|
171 '<xsl:value-of select="count( sitemap:sitemapindex/sitemap:sitemap )" />' |
|
172 ); |
|
173 |
|
174 $lang = get_language_attributes( 'html' ); |
|
175 $url = esc_xml( __( 'URL' ) ); |
|
176 $lastmod = esc_xml( __( 'Last Modified' ) ); |
|
177 |
|
178 $xsl_content = <<<XSL |
|
179 <?xml version="1.0" encoding="UTF-8"?> |
|
180 <xsl:stylesheet |
|
181 version="1.0" |
|
182 xmlns:xsl="http://www.w3.org/1999/XSL/Transform" |
|
183 xmlns:sitemap="http://www.sitemaps.org/schemas/sitemap/0.9" |
|
184 exclude-result-prefixes="sitemap" |
|
185 > |
|
186 |
|
187 <xsl:output method="html" encoding="UTF-8" indent="yes" /> |
|
188 |
|
189 <!-- |
|
190 Set variables for whether lastmod occurs for any sitemap in the index. |
|
191 We do this up front because it can be expensive in a large sitemap. |
|
192 --> |
|
193 <xsl:variable name="has-lastmod" select="count( /sitemap:sitemapindex/sitemap:sitemap/sitemap:lastmod )" /> |
|
194 |
|
195 <xsl:template match="/"> |
|
196 <html {$lang}> |
|
197 <head> |
|
198 <title>{$title}</title> |
|
199 <style> |
|
200 {$css} |
|
201 </style> |
|
202 </head> |
|
203 <body> |
|
204 <div id="sitemap"> |
|
205 <div id="sitemap__header"> |
|
206 <h1>{$title}</h1> |
|
207 <p>{$description}</p> |
|
208 <p>{$learn_more}</p> |
|
209 </div> |
|
210 <div id="sitemap__content"> |
|
211 <p class="text">{$text}</p> |
|
212 <table id="sitemap__table"> |
|
213 <thead> |
|
214 <tr> |
|
215 <th class="loc">{$url}</th> |
|
216 <xsl:if test="\$has-lastmod"> |
|
217 <th class="lastmod">{$lastmod}</th> |
|
218 </xsl:if> |
|
219 </tr> |
|
220 </thead> |
|
221 <tbody> |
|
222 <xsl:for-each select="sitemap:sitemapindex/sitemap:sitemap"> |
|
223 <tr> |
|
224 <td class="loc"><a href="{sitemap:loc}"><xsl:value-of select="sitemap:loc" /></a></td> |
|
225 <xsl:if test="\$has-lastmod"> |
|
226 <td class="lastmod"><xsl:value-of select="sitemap:lastmod" /></td> |
|
227 </xsl:if> |
|
228 </tr> |
|
229 </xsl:for-each> |
|
230 </tbody> |
|
231 </table> |
|
232 </div> |
|
233 </div> |
|
234 </body> |
|
235 </html> |
|
236 </xsl:template> |
|
237 </xsl:stylesheet> |
|
238 |
|
239 XSL; |
|
240 |
|
241 /** |
|
242 * Filters the content of the sitemap index stylesheet. |
|
243 * |
|
244 * @since 5.5.0 |
|
245 * |
|
246 * @param string $xsl_content Full content for the XML stylesheet. |
|
247 */ |
|
248 return apply_filters( 'wp_sitemaps_stylesheet_index_content', $xsl_content ); |
|
249 } |
|
250 |
|
251 /** |
|
252 * Gets the CSS to be included in sitemap XSL stylesheets. |
|
253 * |
|
254 * @since 5.5.0 |
|
255 * |
|
256 * @return string The CSS. |
|
257 */ |
|
258 public function get_stylesheet_css() { |
|
259 $text_align = is_rtl() ? 'right' : 'left'; |
|
260 |
|
261 $css = <<<EOF |
|
262 |
|
263 body { |
|
264 font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; |
|
265 color: #444; |
|
266 } |
|
267 |
|
268 #sitemap__table { |
|
269 border: solid 1px #ccc; |
|
270 border-collapse: collapse; |
|
271 } |
|
272 |
|
273 #sitemap__table tr td.loc { |
|
274 /* |
|
275 * URLs should always be LTR. |
|
276 * See https://core.trac.wordpress.org/ticket/16834 |
|
277 * and https://core.trac.wordpress.org/ticket/49949 |
|
278 */ |
|
279 direction: ltr; |
|
280 } |
|
281 |
|
282 #sitemap__table tr th { |
|
283 text-align: {$text_align}; |
|
284 } |
|
285 |
|
286 #sitemap__table tr td, |
|
287 #sitemap__table tr th { |
|
288 padding: 10px; |
|
289 } |
|
290 |
|
291 #sitemap__table tr:nth-child(odd) td { |
|
292 background-color: #eee; |
|
293 } |
|
294 |
|
295 a:hover { |
|
296 text-decoration: none; |
|
297 } |
|
298 |
|
299 EOF; |
|
300 |
|
301 /** |
|
302 * Filters the CSS only for the sitemap stylesheet. |
|
303 * |
|
304 * @since 5.5.0 |
|
305 * |
|
306 * @param string $css CSS to be applied to default XSL file. |
|
307 */ |
|
308 return apply_filters( 'wp_sitemaps_stylesheet_css', $css ); |
|
309 } |
|
310 } |