[FEATURE] Add properties changefreq and priority to XML sitemap entries
[Packages/TYPO3.CMS.git] / typo3 / sysext / seo / Classes / XmlSitemap / PagesXmlSitemapDataProvider.php
1 <?php
2 declare(strict_types = 1);
3
4 namespace TYPO3\CMS\Seo\XmlSitemap;
5
6 /*
7 * This file is part of the TYPO3 CMS project.
8 *
9 * It is free software; you can redistribute it and/or modify it under
10 * the terms of the GNU General Public License, either version 2
11 * of the License, or any later version.
12 *
13 * For the full copyright and license information, please read the
14 * LICENSE.txt file that was distributed with this source code.
15 *
16 * The TYPO3 project - inspiring people to share!
17 */
18
19 use Psr\Http\Message\ServerRequestInterface;
20 use TYPO3\CMS\Core\Context\Context;
21 use TYPO3\CMS\Core\Context\LanguageAspect;
22 use TYPO3\CMS\Core\Database\ConnectionPool;
23 use TYPO3\CMS\Core\Database\Query\QueryHelper;
24 use TYPO3\CMS\Core\Utility\GeneralUtility;
25 use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
26 use TYPO3\CMS\Frontend\Page\PageRepository;
27
28 /**
29 * Class to generate a XML sitemap for pages
30 * @internal this class is not part of TYPO3's Core API.
31 */
32 class PagesXmlSitemapDataProvider extends AbstractXmlSitemapDataProvider
33 {
34 public function __construct(ServerRequestInterface $request, string $key, array $config = [], ContentObjectRenderer $cObj = null)
35 {
36 parent::__construct($request, $key, $config, $cObj);
37
38 $this->generateItems($this->request);
39 }
40
41 /**
42 * @param ServerRequestInterface $request
43 * @throws \TYPO3\CMS\Core\Context\Exception\AspectNotFoundException
44 */
45 public function generateItems(ServerRequestInterface $request): void
46 {
47 $languageId = $this->getCurrentLanguageAspect()->getId();
48 foreach ($this->getPages() as $page) {
49 /**
50 * @todo Checking if the page has to be shown/hidden should normally be handled by the
51 * PageRepository but to prevent major breaking changes this is checked here for now
52 */
53 if (
54 !(
55 GeneralUtility::hideIfDefaultLanguage($page['l18n_cfg'])
56 && (!$languageId || ($languageId && !$page['_PAGES_OVERLAY']))
57 )
58 &&
59 !(
60 $languageId
61 && GeneralUtility::hideIfNotTranslated($page['l18n_cfg'])
62 && !$page['_PAGES_OVERLAY']
63 )
64 ) {
65 $lastMod = $page['SYS_LASTCHANGED'] ?: $page['tstamp'];
66
67 $this->items[] = [
68 'uid' => $page['uid'],
69 'lastMod' => (int)$lastMod,
70 'changefreq' => $page['sitemap_changefreq'],
71 'priority' => (float)$page['sitemap_priority'],
72 ];
73 }
74 }
75 }
76
77 /**
78 * @return array
79 */
80 protected function getPages(): array
81 {
82 if (!empty($this->config['rootPage'])) {
83 $rootPageId = (int)$this->config['rootPage'];
84 } else {
85 $site = $this->request->getAttribute('site');
86 $rootPageId = $site->getRootPageId();
87 }
88
89 $cObj = GeneralUtility::makeInstance(ContentObjectRenderer::class);
90 $treeList = $cObj->getTreeList(-$rootPageId, 99);
91 $treeListArray = GeneralUtility::intExplode(',', $treeList);
92
93 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
94 ->getQueryBuilderForTable('pages');
95
96 $constraints = [
97 $queryBuilder->expr()->in('uid', $treeListArray)
98 ];
99
100 if (!empty($this->config['additionalWhere'])) {
101 $constraints[] = QueryHelper::stripLogicalOperatorPrefix($this->config['additionalWhere']);
102 }
103
104 if (!empty($this->config['excludedDoktypes'])) {
105 $excludedDoktypes = GeneralUtility::intExplode(',', $this->config['excludedDoktypes']);
106 if (!empty($excludedDoktypes)) {
107 $constraints[] = $queryBuilder->expr()->notIn('doktype', implode(',', $excludedDoktypes));
108 }
109 }
110 $pages = $queryBuilder->select('*')
111 ->from('pages')
112 ->where(...$constraints)
113 ->orderBy('uid', 'ASC')
114 ->execute()
115 ->fetchAll();
116
117 $pageRepository = GeneralUtility::makeInstance(PageRepository::class);
118 return $pageRepository->getPagesOverlay($pages);
119 }
120
121 /**
122 * @return LanguageAspect
123 * @throws \TYPO3\CMS\Core\Context\Exception\AspectNotFoundException
124 */
125 protected function getCurrentLanguageAspect(): LanguageAspect
126 {
127 return GeneralUtility::makeInstance(Context::class)->getAspect('language');
128 }
129
130 /**
131 * @param array $data
132 * @return array
133 */
134 protected function defineUrl(array $data): array
135 {
136 $typoLinkConfig = [
137 'parameter' => $data['uid'],
138 'forceAbsoluteUrl' => 1,
139 ];
140
141 $data['loc'] = $this->cObj->typoLink_URL($typoLinkConfig);
142
143 return $data;
144 }
145 }