Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
77.87% covered (warning)
77.87%
197 / 253
66.67% covered (warning)
66.67%
4 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
Jetpack_Sitemap_Stylist
78.49% covered (warning)
78.49%
197 / 251
66.67% covered (warning)
66.67%
4 / 6
8.64
0.00% covered (danger)
0.00%
0 / 1
 sanitize_with_links
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
1
 sitemap_xsl
100.00% covered (success)
100.00%
44 / 44
100.00% covered (success)
100.00%
1 / 1
1
 sitemap_index_xsl
95.92% covered (success)
95.92%
47 / 49
0.00% covered (danger)
0.00%
0 / 1
2
 image_sitemap_xsl
100.00% covered (success)
100.00%
48 / 48
100.00% covered (success)
100.00%
1 / 1
1
 video_sitemap_xsl
0.00% covered (danger)
0.00%
0 / 52
0.00% covered (danger)
0.00%
0 / 1
2
 news_sitemap_xsl
100.00% covered (success)
100.00%
46 / 46
100.00% covered (success)
100.00%
1 / 1
1
 sitemap_xsl_css
n/a
0 / 0
n/a
0 / 0
1
1<?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
2/**
3 * The XSL used to style sitemaps is essentially a bunch of
4 * static strings. This class handles the construction of
5 * those strings.
6 *
7 * @package automattic/jetpack
8 * @since 4.8.0
9 */
10
11if ( ! defined( 'ABSPATH' ) ) {
12    exit( 0 );
13}
14
15/**
16 * Builds the XSL files required by Jetpack_Sitemap_Manager.
17 *
18 * @since 4.8.0
19 */
20class Jetpack_Sitemap_Stylist {
21
22    /**
23     * Convert named entities, strip all HTML except anchor tags,
24     * and interpolate with vsprintf. This is a helper function
25     * for all the internationalized UI strings in this class
26     * which have to include URLs.
27     *
28     * Note that $url_array should be indexed by integers like so:
29     *
30     * array(
31     *   1 => 'example.com',
32     *   2 => 'example.org',
33     * );
34     *
35     * Then '%1$s' in the format string will substitute 'example.com'
36     * and '%2$s' will substitute 'example.org'.
37     *
38     * @access private
39     * @since 4.8.0
40     * @link https://php.net/manual/en/function.vsprintf.php Format string documentation.
41     *
42     * @param string $format A vsprintf-style format string to be sanitized.
43     * @param array  $url_array The string substitution array to be passed to vsprintf.
44     *
45     * @return string The sanitized string.
46     */
47    private static function sanitize_with_links( $format, $url_array ) {
48        return vsprintf(
49            wp_kses(
50                ent2ncr( $format ),
51                array(
52                    'a' => array(
53                        'href'  => true,
54                        'title' => true,
55                    ),
56                )
57            ),
58            $url_array
59        );
60    }
61
62    /**
63     * Returns the xsl of a sitemap xml file as a string.
64     *
65     * @access public
66     * @since 4.8.0
67     *
68     * @return string The contents of the xsl file.
69     */
70    public static function sitemap_xsl() {
71        $title          = esc_html( ent2ncr( __( 'XML Sitemap', 'jetpack' ) ) );
72        $header_url     = esc_html( ent2ncr( __( 'URL', 'jetpack' ) ) );
73        $header_lastmod = esc_html( ent2ncr( __( 'Last Modified', 'jetpack' ) ) );
74
75        $description = self::sanitize_with_links(
76            /* translators: %1$s: jetpack.com URL. %2$s: google.com URL. %3$s: bing.com URL. */
77            __(
78                'This is an XML Sitemap generated by <a href="%1$s" rel="noopener noreferrer" target="_blank">Jetpack</a>, meant to be consumed by search engines like <a href="%2$s" rel="noopener noreferrer" target="_blank">Google</a> or <a href="%3$s" rel="noopener noreferrer" target="_blank">Bing</a>.',
79                'jetpack'
80            ),
81            array(
82                1 => 'https://jetpack.com/',
83                2 => 'https://www.google.com/',
84                3 => 'https://www.bing.com/',
85            )
86        );
87
88        $more_info = self::sanitize_with_links(
89            /* translators: %1$s: sitemaps.org URL. */
90            __(
91                'You can find more information on XML sitemaps at <a href="%1$s" rel="noopener noreferrer" target="_blank">sitemaps.org</a>',
92                'jetpack'
93            ),
94            array(
95                1 => 'https://sitemaps.org',
96            )
97        );
98
99        $generated_by = self::sanitize_with_links(
100            /* translators: %s: jetpack.com URL. */
101            __(
102                'Generated by <a href="%s" rel="noopener noreferrer" target="_blank">Jetpack for WordPress</a>',
103                'jetpack'
104            ),
105            array(
106                1 => 'https://jetpack.com',
107            )
108        );
109
110        $css = self::sitemap_xsl_css();
111
112        return <<<XSL
113<?xml version='1.0' encoding='UTF-8'?>
114<xsl:stylesheet version='2.0'
115    xmlns:html='http://www.w3.org/TR/REC-html40'
116    xmlns:sitemap='http://www.sitemaps.org/schemas/sitemap/0.9'
117    xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
118<xsl:output method='html' version='1.0' encoding='UTF-8' indent='yes'/>
119<xsl:template match="/">
120<html xmlns="http://www.w3.org/1999/xhtml">
121<head>
122    <title>$title</title>
123    <meta http-equiv='Content-Type' content='text/html; charset=utf-8'/>
124    <style type='text/css'>
125$css
126    </style>
127</head>
128<body>
129    <div id='description'>
130        <h1>$title</h1>
131        <p>$description</p>
132        <p>$more_info</p>
133    </div>
134    <div id='content'>
135        <!-- <xsl:value-of select="count(sitemap:urlset/sitemap:url)"/> -->
136        <table>
137            <tr>
138                <th>#</th>
139                <th>$header_url</th>
140                <th>$header_lastmod</th>
141            </tr>
142            <xsl:for-each select="sitemap:urlset/sitemap:url">
143                <tr>
144                    <xsl:choose>
145                        <xsl:when test='position() mod 2 != 1'>
146                            <xsl:attribute name="class">odd</xsl:attribute>
147                        </xsl:when>
148                    </xsl:choose>
149                    <td>
150                        <xsl:value-of select = "position()" />
151                    </td>
152                    <td>
153                        <xsl:variable name='itemURL'>
154                            <xsl:value-of select='sitemap:loc'/>
155                        </xsl:variable>
156                        <a href='{\$itemURL}'>
157                            <xsl:value-of select='sitemap:loc'/>
158                        </a>
159                    </td>
160                    <td>
161                        <xsl:value-of select='sitemap:lastmod'/>
162                    </td>
163                </tr>
164            </xsl:for-each>
165        </table>
166    </div>
167    <div id='footer'>
168        <p>$generated_by</p>
169    </div>
170</body>
171</html>
172</xsl:template>
173</xsl:stylesheet>\n
174XSL;
175    }
176
177    /**
178     * Returns the xsl of a sitemap index xml file as a string.
179     *
180     * @access public
181     * @since 4.8.0
182     *
183     * @return string The contents of the xsl file.
184     */
185    public static function sitemap_index_xsl() {
186        $title          = esc_html( ent2ncr( __( 'XML Sitemap Index', 'jetpack' ) ) );
187        $header_url     = esc_html( ent2ncr( __( 'Sitemap URL', 'jetpack' ) ) );
188        $header_lastmod = esc_html( ent2ncr( __( 'Last Modified', 'jetpack' ) ) );
189
190        $description = self::sanitize_with_links(
191            /* translators: %1$s: jetpack.com URL. %2$s: google.com URL. %3$s: bing.com URL. */
192            __(
193                'This is an XML Sitemap Index generated by <a href="%1$s" rel="noopener noreferrer" target="_blank">Jetpack</a>, meant to be consumed by search engines like <a href="%2$s" rel="noopener noreferrer" target="_blank">Google</a> or <a href="%3$s" rel="noopener noreferrer" target="_blank">Bing</a>.',
194                'jetpack'
195            ),
196            array(
197                1 => 'https://jetpack.com/',
198                2 => 'https://www.google.com/',
199                3 => 'https://www.bing.com/',
200            )
201        );
202
203        if ( current_user_can( 'manage_options' ) ) {
204            $next = human_time_diff( wp_next_scheduled( 'jp_sitemap_cron_hook' ) );
205            /* translators: %s is a human_time_diff until next sitemap generation. */
206            $no_nodes_warning = sprintf( __( 'No sitemap found. The system will try to build it again in %s.', 'jetpack' ), $next );
207        } else {
208            $no_nodes_warning = '';
209        }
210
211        $more_info = self::sanitize_with_links(
212            /* translators: %1$s: sitemaps.org URL. */
213            __(
214                'You can find more information on XML sitemaps at <a href="%1$s" rel="noopener noreferrer" target="_blank">sitemaps.org</a>',
215                'jetpack'
216            ),
217            array(
218                1 => 'https://sitemaps.org',
219            )
220        );
221
222        $generated_by = self::sanitize_with_links(
223            /* translators: %s: jetpack.com URL. */
224            __(
225                'Generated by <a href="%s" rel="noopener noreferrer" target="_blank">Jetpack for WordPress</a>',
226                'jetpack'
227            ),
228            array(
229                1 => 'https://jetpack.com',
230            )
231        );
232
233        $css = self::sitemap_xsl_css();
234
235        return <<<XSL
236<?xml version='1.0' encoding='UTF-8'?>
237<xsl:stylesheet version='2.0'
238    xmlns:html='http://www.w3.org/TR/REC-html40'
239    xmlns:sitemap='http://www.sitemaps.org/schemas/sitemap/0.9'
240    xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
241<xsl:output method='html' version='1.0' encoding='UTF-8' indent='yes'/>
242<xsl:template match="/">
243<html xmlns="http://www.w3.org/1999/xhtml">
244<head>
245    <title>$title</title>
246    <meta http-equiv='Content-Type' content='text/html; charset=utf-8'/>
247    <style type='text/css'>
248$css
249    </style>
250</head>
251<body>
252    <div id='description'>
253        <h1>$title</h1>
254        <xsl:choose>
255            <xsl:when test='not(sitemap:sitemapindex/sitemap:sitemap)'>
256                <p><strong>$no_nodes_warning</strong></p>
257            </xsl:when>
258        </xsl:choose>
259        <p>$description</p>
260        <p>$more_info</p>
261    </div>
262    <div id='content'>
263        <table>
264            <tr>
265                <th>#</th>
266                <th>$header_url</th>
267                <th>$header_lastmod</th>
268            </tr>
269            <xsl:for-each select='sitemap:sitemapindex/sitemap:sitemap'>
270                <tr>
271                    <xsl:choose>
272                        <xsl:when test='position() mod 2 != 1'>
273                            <xsl:attribute name="class">odd</xsl:attribute>
274                        </xsl:when>
275                    </xsl:choose>
276                    <td>
277                        <xsl:value-of select = "position()" />
278                    </td>
279                    <td>
280                        <xsl:variable name='itemURL'>
281                            <xsl:value-of select='sitemap:loc'/>
282                        </xsl:variable>
283                        <a href='{\$itemURL}'>
284                            <xsl:value-of select='sitemap:loc'/>
285                        </a>
286                    </td>
287                    <td>
288                        <xsl:value-of select='sitemap:lastmod'/>
289                    </td>
290                </tr>
291            </xsl:for-each>
292        </table>
293    </div>
294    <div id='footer'>
295        <p>$generated_by</p>
296    </div>
297</body>
298</html>
299</xsl:template>
300</xsl:stylesheet>\n
301XSL;
302    }
303
304    /**
305     * Returns the xsl of an image sitemap xml file as a string.
306     *
307     * @access public
308     * @since 4.8.0
309     *
310     * @return string The contents of the xsl file.
311     */
312    public static function image_sitemap_xsl() {
313        $title            = esc_html( ent2ncr( __( 'XML Image Sitemap', 'jetpack' ) ) );
314        $header_url       = esc_html( ent2ncr( __( 'Page URL', 'jetpack' ) ) );
315        $header_image_url = esc_html( ent2ncr( __( 'Image URL', 'jetpack' ) ) );
316        $header_thumbnail = esc_html( ent2ncr( __( 'Thumbnail', 'jetpack' ) ) );
317        $header_lastmod   = esc_html( ent2ncr( __( 'Last Modified', 'jetpack' ) ) );
318
319        $description = self::sanitize_with_links(
320            /* translators: %1$s: jetpack.com URL. %2$s: google.com URL. %3$s: bing.com URL. */
321            __(
322                'This is an XML Image Sitemap generated by <a href="%1$s" rel="noopener noreferrer" target="_blank">Jetpack</a>, meant to be consumed by search engines like <a href="%2$s" rel="noopener noreferrer" target="_blank">Google</a> or <a href="%3$s" rel="noopener noreferrer" target="_blank">Bing</a>.',
323                'jetpack'
324            ),
325            array(
326                1 => 'https://jetpack.com/',
327                2 => 'https://www.google.com/',
328                3 => 'https://www.bing.com/',
329            )
330        );
331
332        $more_info = self::sanitize_with_links(
333            /* translators: %1$s: sitemaps.org URL. */
334            __(
335                'You can find more information on XML sitemaps at <a href="%1$s" rel="noopener noreferrer" target="_blank">sitemaps.org</a>',
336                'jetpack'
337            ),
338            array(
339                1 => 'https://sitemaps.org',
340            )
341        );
342
343        $generated_by = self::sanitize_with_links(
344            /* translators: %s: jetpack.com URL. */
345            __(
346                'Generated by <a href="%s" rel="noopener noreferrer" target="_blank">Jetpack for WordPress</a>',
347                'jetpack'
348            ),
349            array(
350                1 => 'https://jetpack.com',
351            )
352        );
353
354        $css = self::sitemap_xsl_css();
355
356        return <<<XSL
357<?xml version='1.0' encoding='UTF-8'?>
358<xsl:stylesheet version='2.0'
359    xmlns:html='http://www.w3.org/TR/REC-html40'
360    xmlns:sitemap='http://www.sitemaps.org/schemas/sitemap/0.9'
361    xmlns:image='http://www.google.com/schemas/sitemap-image/1.1'
362    xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
363<xsl:output method='html' version='1.0' encoding='UTF-8' indent='yes'/>
364<xsl:template match="/">
365<html xmlns="http://www.w3.org/1999/xhtml">
366<head>
367    <title>$title</title>
368    <meta http-equiv='Content-Type' content='text/html; charset=utf-8'/>
369    <style type='text/css'>
370$css
371    </style>
372</head>
373<body>
374    <div id='description'>
375        <h1>$title</h1>
376        <p>$description</p>
377        <p>$more_info</p>
378    </div>
379    <div id='content'>
380        <!-- <xsl:value-of select="count(sitemap:urlset/sitemap:url)"/> -->
381        <table>
382            <tr>
383                <th>#</th>
384                <th>$header_url</th>
385                <th>$header_image_url</th>
386                <th>$header_lastmod</th>
387                <th>$header_thumbnail</th>
388            </tr>
389            <xsl:for-each select="sitemap:urlset/sitemap:url">
390                <tr>
391                    <xsl:choose>
392                        <xsl:when test='position() mod 2 != 1'>
393                            <xsl:attribute name="class">odd</xsl:attribute>
394                        </xsl:when>
395                    </xsl:choose>
396                    <td>
397                        <xsl:value-of select = "position()" />
398                    </td>
399                    <td>
400                        <xsl:variable name='pageURL'>
401                            <xsl:value-of select='sitemap:loc'/>
402                        </xsl:variable>
403                        <a href='{\$pageURL}'>
404                            <xsl:value-of select='sitemap:loc'/>
405                        </a>
406                    </td>
407                    <xsl:variable name='itemURL'>
408                        <xsl:value-of select='image:image/image:loc'/>
409                    </xsl:variable>
410                    <td>
411                        <a href='{\$itemURL}'>
412                            <xsl:value-of select='image:image/image:loc'/>
413                        </a>
414                    </td>
415                    <td>
416                        <xsl:value-of select='sitemap:lastmod'/>
417                    </td>
418                    <td>
419                        <a href='{\$itemURL}'>
420                            <img class='thumbnail' src='{\$itemURL}'/>
421                        </a>
422                    </td>
423                </tr>
424            </xsl:for-each>
425        </table>
426    </div>
427    <div id='footer'>
428        <p>$generated_by</p>
429    </div>
430</body>
431</html>
432</xsl:template>
433</xsl:stylesheet>\n
434XSL;
435    }
436
437    /**
438     * Returns the xsl of a video sitemap xml file as a string.
439     *
440     * @access public
441     * @since 4.8.0
442     *
443     * @return string The contents of the xsl file.
444     */
445    public static function video_sitemap_xsl() {
446        $title              = esc_html( ent2ncr( __( 'XML Video Sitemap', 'jetpack' ) ) );
447        $header_url         = esc_html( ent2ncr( __( 'Page URL', 'jetpack' ) ) );
448        $header_image_url   = esc_html( ent2ncr( __( 'Video URL', 'jetpack' ) ) );
449        $header_thumbnail   = esc_html( ent2ncr( __( 'Thumbnail', 'jetpack' ) ) );
450        $header_title       = esc_html( ent2ncr( __( 'Title', 'jetpack' ) ) );
451        $header_lastmod     = esc_html( ent2ncr( __( 'Last Modified', 'jetpack' ) ) );
452        $header_description = esc_html( ent2ncr( __( 'Description', 'jetpack' ) ) );
453
454        $description = self::sanitize_with_links(
455            /* translators: %1$s: jetpack.com URL. %2$s: google.com URL. %3$s: bing.com URL. */
456            __(
457                'This is an XML Video Sitemap generated by <a href="%1$s" rel="noopener noreferrer" target="_blank">Jetpack</a>, meant to be consumed by search engines like <a href="%2$s" rel="noopener noreferrer" target="_blank">Google</a> or <a href="%3$s" rel="noopener noreferrer" target="_blank">Bing</a>.',
458                'jetpack'
459            ),
460            array(
461                1 => 'https://jetpack.com/',
462                2 => 'https://www.google.com/',
463                3 => 'https://www.bing.com/',
464            )
465        );
466
467        $more_info = self::sanitize_with_links(
468            /* translators: %1$s: sitemaps.org URL. */
469            __(
470                'You can find more information on XML sitemaps at <a href="%1$s" rel="noopener noreferrer" target="_blank">sitemaps.org</a>',
471                'jetpack'
472            ),
473            array(
474                1 => 'https://sitemaps.org',
475            )
476        );
477
478        $generated_by = self::sanitize_with_links(
479            /* translators: %s: jetpack.com URL. */
480            __(
481                'Generated by <a href="%s" rel="noopener noreferrer" target="_blank">Jetpack for WordPress</a>',
482                'jetpack'
483            ),
484            array(
485                1 => 'https://jetpack.com',
486            )
487        );
488
489        $css = self::sitemap_xsl_css();
490
491        return <<<XSL
492<?xml version='1.0' encoding='UTF-8'?>
493<xsl:stylesheet version='2.0'
494    xmlns:html='http://www.w3.org/TR/REC-html40'
495    xmlns:sitemap='http://www.sitemaps.org/schemas/sitemap/0.9'
496    xmlns:video='http://www.google.com/schemas/sitemap-video/1.1'
497    xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
498<xsl:output method='html' version='1.0' encoding='UTF-8' indent='yes'/>
499<xsl:template match="/">
500<html xmlns="http://www.w3.org/1999/xhtml">
501<head>
502    <title>$title</title>
503    <meta http-equiv='Content-Type' content='text/html; charset=utf-8'/>
504    <style type='text/css'>
505$css
506    </style>
507</head>
508<body>
509    <div id='description'>
510        <h1>$title</h1>
511        <p>$description</p>
512        <p>$more_info</p>
513    </div>
514    <div id='content'>
515        <!-- <xsl:value-of select="count(sitemap:urlset/sitemap:url)"/> -->
516        <table>
517            <tr>
518                <th>#</th>
519                <th>$header_url</th>
520                <th>$header_image_url</th>
521                <th>$header_title</th>
522                <th>$header_description</th>
523                <th>$header_lastmod</th>
524                <th>$header_thumbnail</th>
525            </tr>
526            <xsl:for-each select="sitemap:urlset/sitemap:url">
527                <tr>
528                    <xsl:choose>
529                        <xsl:when test='position() mod 2 != 1'>
530                            <xsl:attribute name="class">odd</xsl:attribute>
531                        </xsl:when>
532                    </xsl:choose>
533                    <td>
534                        <xsl:value-of select = "position()" />
535                    </td>
536                    <td>
537                        <xsl:variable name='pageURL'>
538                            <xsl:value-of select='sitemap:loc'/>
539                        </xsl:variable>
540                        <a href='{\$pageURL}'>
541                            <xsl:value-of select='sitemap:loc'/>
542                        </a>
543                    </td>
544                    <xsl:variable name='itemURL'>
545                        <xsl:value-of select='video:video/video:content_loc'/>
546                    </xsl:variable>
547                    <td>
548                        <a href='{\$itemURL}'>
549                            <xsl:value-of select='video:video/video:content_loc'/>
550                        </a>
551                    </td>
552                    <td>
553                        <xsl:value-of select='video:video/video:title'/>
554                    </td>
555                    <td>
556                        <xsl:value-of select='video:video/video:description' disable-output-escaping='yes'/>
557                    </td>
558                    <td>
559                        <xsl:value-of select='sitemap:lastmod'/>
560                    </td>
561                    <td>
562                        <xsl:variable name='thumbURL'>
563                            <xsl:value-of select='video:video/video:thumbnail_loc'/>
564                        </xsl:variable>
565                        <a href='{\$thumbURL}'>
566                            <img class='thumbnail' src='{\$thumbURL}'/>
567                        </a>
568                    </td>
569                </tr>
570            </xsl:for-each>
571        </table>
572    </div>
573    <div id='footer'>
574        <p>$generated_by</p>
575    </div>
576</body>
577</html>
578</xsl:template>
579</xsl:stylesheet>\n
580XSL;
581    }
582
583    /**
584     * Returns the xsl of a news sitemap xml file as a string.
585     *
586     * @access public
587     * @since 4.8.0
588     *
589     * @return string The contents of the xsl file.
590     */
591    public static function news_sitemap_xsl() {
592        $title          = esc_html( ent2ncr( __( 'XML News Sitemap', 'jetpack' ) ) );
593        $header_url     = esc_html( ent2ncr( __( 'Page URL', 'jetpack' ) ) );
594        $header_title   = esc_html( ent2ncr( __( 'Title', 'jetpack' ) ) );
595        $header_pubdate = esc_html( ent2ncr( __( 'Publication Date', 'jetpack' ) ) );
596
597        $description = self::sanitize_with_links(
598            /* translators: %1$s: jetpack.com URL. %2$s: google.com URL. %3$s: bing.com URL. */
599            __(
600                'This is an XML News Sitemap generated by <a href="%1$s" rel="noopener noreferrer" target="_blank">Jetpack</a>, meant to be consumed by search engines like <a href="%2$s" rel="noopener noreferrer" target="_blank">Google</a> or <a href="%3$s" rel="noopener noreferrer" target="_blank">Bing</a>.',
601                'jetpack'
602            ),
603            array(
604                1 => 'https://jetpack.com/',
605                2 => 'https://www.google.com/',
606                3 => 'https://www.bing.com/',
607            )
608        );
609
610        $more_info = self::sanitize_with_links(
611            /* translators: %1$s: sitemaps.org URL. */
612            __(
613                'You can find more information on XML sitemaps at <a href="%1$s" rel="noopener noreferrer" target="_blank">sitemaps.org</a>',
614                'jetpack'
615            ),
616            array(
617                1 => 'https://sitemaps.org',
618            )
619        );
620
621        $generated_by = self::sanitize_with_links(
622            /* translators: %s: jetpack.com URL. */
623            __(
624                'Generated by <a href="%s" rel="noopener noreferrer" target="_blank">Jetpack for WordPress</a>',
625                'jetpack'
626            ),
627            array(
628                1 => 'https://jetpack.com',
629            )
630        );
631
632        $css = self::sitemap_xsl_css();
633
634        return <<<XSL
635<?xml version='1.0' encoding='UTF-8'?>
636<xsl:stylesheet version='2.0'
637    xmlns:html='http://www.w3.org/TR/REC-html40'
638    xmlns:sitemap='http://www.sitemaps.org/schemas/sitemap/0.9'
639    xmlns:news='http://www.google.com/schemas/sitemap-news/0.9'
640    xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
641<xsl:output method='html' version='1.0' encoding='UTF-8' indent='yes'/>
642<xsl:template match="/">
643<html xmlns="http://www.w3.org/1999/xhtml">
644<head>
645    <title>$title</title>
646    <meta http-equiv='Content-Type' content='text/html; charset=utf-8'/>
647    <style type='text/css'>
648$css
649    </style>
650</head>
651<body>
652    <div id='description'>
653        <h1>$title</h1>
654        <p>$description</p>
655        <p>$more_info</p>
656    </div>
657    <div id='content'>
658        <!-- <xsl:value-of select="count(sitemap:urlset/sitemap:url)"/> -->
659        <table>
660            <tr>
661                <th>#</th>
662                <th>$header_url</th>
663                <th>$header_title</th>
664                <th>$header_pubdate</th>
665            </tr>
666            <xsl:for-each select="sitemap:urlset/sitemap:url">
667                <tr>
668                    <xsl:choose>
669                        <xsl:when test='position() mod 2 != 1'>
670                            <xsl:attribute name="class">odd</xsl:attribute>
671                        </xsl:when>
672                    </xsl:choose>
673                    <td>
674                        <xsl:value-of select = "position()" />
675                    </td>
676                    <xsl:variable name='pageURL'>
677                        <xsl:value-of select='sitemap:loc'/>
678                    </xsl:variable>
679                    <td>
680                        <a href='{\$pageURL}'>
681                            <xsl:value-of select='sitemap:loc'/>
682                        </a>
683                    </td>
684                    <td>
685                        <a href='{\$pageURL}'>
686                            <xsl:value-of select='news:news/news:title'/>
687                        </a>
688                    </td>
689                    <td>
690                        <xsl:value-of select='news:news/news:publication_date'/>
691                    </td>
692                </tr>
693            </xsl:for-each>
694        </table>
695    </div>
696    <div id='footer'>
697        <p>$generated_by</p>
698    </div>
699</body>
700</html>
701</xsl:template>
702</xsl:stylesheet>\n
703XSL;
704    }
705
706    /**
707     * The CSS to be included in sitemap xsl stylesheets;
708     * factored out for uniformity.
709     *
710     * @access public
711     * @since 4.8.0
712     *
713     * @return string The CSS.
714     */
715    public static function sitemap_xsl_css() {
716        return <<<'CSS'
717        body {
718            font: 14px 'Open Sans', Helvetica, Arial, sans-serif;
719            margin: 0;
720        }
721
722        a {
723            color: #3498db;
724            text-decoration: none;
725        }
726
727        h1 {
728            margin: 0;
729        }
730
731        #description {
732            background-color: #f0f2eb;
733            color: #000;
734            padding: 30px 30px 20px;
735        }
736
737        #description a {
738            color: #008710;
739        }
740
741        #content {
742            padding: 10px 30px 30px;
743            background: #fff;
744        }
745
746        a:hover {
747            border-bottom: 1px solid;
748        }
749
750        th, td {
751            font-size: 12px;
752        }
753
754        th {
755            text-align: left;
756            border-bottom: 1px solid #ccc;
757        }
758
759        th, td {
760            padding: 10px 15px;
761        }
762
763        .odd {
764            background: linear-gradient( 159.87deg, #f6f6f4 7.24%, #f7f4ea 64.73%, #ddedd5 116.53% );
765        }
766
767        #footer {
768            margin: 20px 30px;
769            font-size: 12px;
770            color: #999;
771        }
772
773        #footer a {
774            color: inherit;
775        }
776
777        #description a, #footer a {
778            border-bottom: 1px solid;
779        }
780
781        #description a:hover, #footer a:hover {
782            border-bottom: none;
783        }
784
785        img {
786            max-height: 100px;
787            max-width: 100px;
788        }
789CSS;
790    }
791}