18c2e8227SGreg Roach<?php 28c2e8227SGreg Roach/** 38c2e8227SGreg Roach * webtrees: online genealogy 46bdf7674SGreg Roach * Copyright (C) 2017 webtrees development team 58c2e8227SGreg Roach * This program is free software: you can redistribute it and/or modify 68c2e8227SGreg Roach * it under the terms of the GNU General Public License as published by 78c2e8227SGreg Roach * the Free Software Foundation, either version 3 of the License, or 88c2e8227SGreg Roach * (at your option) any later version. 98c2e8227SGreg Roach * This program is distributed in the hope that it will be useful, 108c2e8227SGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of 118c2e8227SGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 128c2e8227SGreg Roach * GNU General Public License for more details. 138c2e8227SGreg Roach * You should have received a copy of the GNU General Public License 148c2e8227SGreg Roach * along with this program. If not, see <http://www.gnu.org/licenses/>. 158c2e8227SGreg Roach */ 1676692c8bSGreg Roachnamespace Fisharebest\Webtrees\Module; 1776692c8bSGreg Roach 180e62c4b8SGreg Roachuse Fisharebest\Webtrees\Auth; 19*15d603e7SGreg Roachuse Fisharebest\Webtrees\Bootstrap4; 200e62c4b8SGreg Roachuse Fisharebest\Webtrees\Controller\PageController; 210e62c4b8SGreg Roachuse Fisharebest\Webtrees\Database; 220e62c4b8SGreg Roachuse Fisharebest\Webtrees\Filter; 230e62c4b8SGreg Roachuse Fisharebest\Webtrees\I18N; 240e62c4b8SGreg Roachuse Fisharebest\Webtrees\Individual; 250e62c4b8SGreg Roachuse Fisharebest\Webtrees\Media; 260e62c4b8SGreg Roachuse Fisharebest\Webtrees\Note; 270e62c4b8SGreg Roachuse Fisharebest\Webtrees\Repository; 280e62c4b8SGreg Roachuse Fisharebest\Webtrees\Source; 290e62c4b8SGreg Roachuse Fisharebest\Webtrees\Tree; 308c2e8227SGreg Roach 318c2e8227SGreg Roach/** 328c2e8227SGreg Roach * Class SiteMapModule 338c2e8227SGreg Roach */ 34e2a378d3SGreg Roachclass SiteMapModule extends AbstractModule implements ModuleConfigInterface { 358c2e8227SGreg Roach const RECORDS_PER_VOLUME = 500; // Keep sitemap files small, for memory, CPU and max_allowed_packet limits. 368c2e8227SGreg Roach const CACHE_LIFE = 1209600; // Two weeks 378c2e8227SGreg Roach 388c2e8227SGreg Roach /** {@inheritdoc} */ 398c2e8227SGreg Roach public function getTitle() { 408c2e8227SGreg Roach return /* I18N: Name of a module - see http://en.wikipedia.org/wiki/Sitemaps */ I18N::translate('Sitemaps'); 418c2e8227SGreg Roach } 428c2e8227SGreg Roach 438c2e8227SGreg Roach /** {@inheritdoc} */ 448c2e8227SGreg Roach public function getDescription() { 458c2e8227SGreg Roach return /* I18N: Description of the “Sitemaps” module */ I18N::translate('Generate sitemap files for search engines.'); 468c2e8227SGreg Roach } 478c2e8227SGreg Roach 4876692c8bSGreg Roach /** 4976692c8bSGreg Roach * This is a general purpose hook, allowing modules to respond to routes 5076692c8bSGreg Roach * of the form module.php?mod=FOO&mod_action=BAR 5176692c8bSGreg Roach * 5276692c8bSGreg Roach * @param string $mod_action 5376692c8bSGreg Roach */ 548c2e8227SGreg Roach public function modAction($mod_action) { 558c2e8227SGreg Roach switch ($mod_action) { 568c2e8227SGreg Roach case 'admin': 578c2e8227SGreg Roach $this->admin(); 588c2e8227SGreg Roach break; 598c2e8227SGreg Roach case 'generate': 608c2e8227SGreg Roach $this->generate(Filter::get('file')); 618c2e8227SGreg Roach break; 628c2e8227SGreg Roach default: 638c2e8227SGreg Roach http_response_code(404); 648c2e8227SGreg Roach } 658c2e8227SGreg Roach } 668c2e8227SGreg Roach 678c2e8227SGreg Roach /** 6876692c8bSGreg Roach * Generate an XML file. 6976692c8bSGreg Roach * 708c2e8227SGreg Roach * @param string $file 718c2e8227SGreg Roach */ 728c2e8227SGreg Roach private function generate($file) { 738c2e8227SGreg Roach if ($file == 'sitemap.xml') { 748c2e8227SGreg Roach $this->generateIndex(); 758c2e8227SGreg Roach } elseif (preg_match('/^sitemap-(\d+)-([isrmn])-(\d+).xml$/', $file, $match)) { 768c2e8227SGreg Roach $this->generateFile($match[1], $match[2], $match[3]); 778c2e8227SGreg Roach } else { 788c2e8227SGreg Roach http_response_code(404); 798c2e8227SGreg Roach } 808c2e8227SGreg Roach } 818c2e8227SGreg Roach 828c2e8227SGreg Roach /** 838c2e8227SGreg Roach * The index file contains references to all the other files. 848c2e8227SGreg Roach * These files are the same for visitors/users/admins. 858c2e8227SGreg Roach */ 868c2e8227SGreg Roach private function generateIndex() { 878c2e8227SGreg Roach // Check the cache 88*15d603e7SGreg Roach $timestamp = (int) $this->getPreference('sitemap.timestamp'); 898c2e8227SGreg Roach if ($timestamp > WT_TIMESTAMP - self::CACHE_LIFE) { 90*15d603e7SGreg Roach $data = $this->getPreference('sitemap.xml'); 918c2e8227SGreg Roach } else { 928c2e8227SGreg Roach $data = ''; 938c2e8227SGreg Roach $lastmod = '<lastmod>' . date('Y-m-d') . '</lastmod>'; 948c2e8227SGreg Roach foreach (Tree::getAll() as $tree) { 958c2e8227SGreg Roach if ($tree->getPreference('include_in_sitemap')) { 968c2e8227SGreg Roach $n = Database::prepare( 978c2e8227SGreg Roach "SELECT COUNT(*) FROM `##individuals` WHERE i_file = :tree_id" 9813abd6f3SGreg Roach )->execute(['tree_id' => $tree->getTreeId()])->fetchOne(); 998c2e8227SGreg Roach for ($i = 0; $i <= $n / self::RECORDS_PER_VOLUME; ++$i) { 1008c2e8227SGreg Roach $data .= '<sitemap><loc>' . WT_BASE_URL . 'module.php?mod=' . $this->getName() . '&mod_action=generate&file=sitemap-' . $tree->getTreeId() . '-i-' . $i . '.xml</loc>' . $lastmod . '</sitemap>' . PHP_EOL; 1018c2e8227SGreg Roach } 1028c2e8227SGreg Roach $n = Database::prepare( 1038c2e8227SGreg Roach "SELECT COUNT(*) FROM `##sources` WHERE s_file = :tree_id" 10413abd6f3SGreg Roach )->execute(['tree_id' => $tree->getTreeId()])->fetchOne(); 1058c2e8227SGreg Roach if ($n) { 1068c2e8227SGreg Roach for ($i = 0; $i <= $n / self::RECORDS_PER_VOLUME; ++$i) { 1078c2e8227SGreg Roach $data .= '<sitemap><loc>' . WT_BASE_URL . 'module.php?mod=' . $this->getName() . '&mod_action=generate&file=sitemap-' . $tree->getTreeId() . '-s-' . $i . '.xml</loc>' . $lastmod . '</sitemap>' . PHP_EOL; 1088c2e8227SGreg Roach } 1098c2e8227SGreg Roach } 1108c2e8227SGreg Roach $n = Database::prepare( 1118c2e8227SGreg Roach "SELECT COUNT(*) FROM `##other` WHERE o_file = :tree_id AND o_type = 'REPO'" 11213abd6f3SGreg Roach )->execute(['tree_id' => $tree->getTreeId()])->fetchOne(); 1138c2e8227SGreg Roach if ($n) { 1148c2e8227SGreg Roach for ($i = 0; $i <= $n / self::RECORDS_PER_VOLUME; ++$i) { 1158c2e8227SGreg Roach $data .= '<sitemap><loc>' . WT_BASE_URL . 'module.php?mod=' . $this->getName() . '&mod_action=generate&file=sitemap-' . $tree->getTreeId() . '-r-' . $i . '.xml</loc>' . $lastmod . '</sitemap>' . PHP_EOL; 1168c2e8227SGreg Roach } 1178c2e8227SGreg Roach } 1188c2e8227SGreg Roach $n = Database::prepare( 1198c2e8227SGreg Roach "SELECT COUNT(*) FROM `##other` WHERE o_file = :tree_id AND o_type = 'NOTE'" 12013abd6f3SGreg Roach )->execute(['tree_id' => $tree->getTreeId()])->fetchOne(); 1218c2e8227SGreg Roach if ($n) { 1228c2e8227SGreg Roach for ($i = 0; $i <= $n / self::RECORDS_PER_VOLUME; ++$i) { 1238c2e8227SGreg Roach $data .= '<sitemap><loc>' . WT_BASE_URL . 'module.php?mod=' . $this->getName() . '&mod_action=generate&file=sitemap-' . $tree->getTreeId() . '-n-' . $i . '.xml</loc>' . $lastmod . '</sitemap>' . PHP_EOL; 1248c2e8227SGreg Roach } 1258c2e8227SGreg Roach } 1268c2e8227SGreg Roach $n = Database::prepare( 1278c2e8227SGreg Roach "SELECT COUNT(*) FROM `##media` WHERE m_file = :tree_id" 12813abd6f3SGreg Roach )->execute(['tree_id' => $tree->getTreeId()])->fetchOne(); 1298c2e8227SGreg Roach if ($n) { 1308c2e8227SGreg Roach for ($i = 0; $i <= $n / self::RECORDS_PER_VOLUME; ++$i) { 1318c2e8227SGreg Roach $data .= '<sitemap><loc>' . WT_BASE_URL . 'module.php?mod=' . $this->getName() . '&mod_action=generate&file=sitemap-' . $tree->getTreeId() . '-m-' . $i . '.xml</loc>' . $lastmod . '</sitemap>' . PHP_EOL; 1328c2e8227SGreg Roach } 1338c2e8227SGreg Roach } 1348c2e8227SGreg Roach } 1358c2e8227SGreg Roach } 1368c2e8227SGreg Roach $data = '<' . '?xml version="1.0" encoding="UTF-8" ?' . '>' . PHP_EOL . '<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">' . PHP_EOL . $data . '</sitemapindex>' . PHP_EOL; 1378c2e8227SGreg Roach // Cache this data. 138*15d603e7SGreg Roach $this->setPreference('sitemap.xml', $data); 139*15d603e7SGreg Roach $this->setPreference('sitemap.timestamp', WT_TIMESTAMP); 1408c2e8227SGreg Roach } 1418c2e8227SGreg Roach header('Content-Type: application/xml'); 1428c2e8227SGreg Roach header('Content-Length: ' . strlen($data)); 1438c2e8227SGreg Roach echo $data; 1448c2e8227SGreg Roach } 1458c2e8227SGreg Roach 1468c2e8227SGreg Roach /** 1478c2e8227SGreg Roach * A separate file for each family tree and each record type. 1488c2e8227SGreg Roach * These files depend on access levels, so only cache for visitors. 1498c2e8227SGreg Roach * 150cbc1590aSGreg Roach * @param int $ged_id 1518c2e8227SGreg Roach * @param string $rec_type 1528c2e8227SGreg Roach * @param string $volume 1538c2e8227SGreg Roach */ 1548c2e8227SGreg Roach private function generateFile($ged_id, $rec_type, $volume) { 15524ec66ceSGreg Roach $tree = Tree::findById($ged_id); 1568c2e8227SGreg Roach // Check the cache 157*15d603e7SGreg Roach $timestamp = (int) $this->getPreference('sitemap-' . $ged_id . '-' . $rec_type . '-' . $volume . '.timestamp'); 1588c2e8227SGreg Roach if ($timestamp > WT_TIMESTAMP - self::CACHE_LIFE && !Auth::check()) { 159*15d603e7SGreg Roach $data = $this->getPreference('sitemap-' . $ged_id . '-' . $rec_type . '-' . $volume . '.xml'); 1608c2e8227SGreg Roach } else { 1618c2e8227SGreg Roach $data = '<url><loc>' . WT_BASE_URL . 'index.php?ctype=gedcom&ged=' . $tree->getNameUrl() . '</loc></url>' . PHP_EOL; 16213abd6f3SGreg Roach $records = []; 1638c2e8227SGreg Roach switch ($rec_type) { 1648c2e8227SGreg Roach case 'i': 1658c2e8227SGreg Roach $rows = Database::prepare( 16624ec66ceSGreg Roach "SELECT i_id AS xref, i_gedcom AS gedcom" . 1678c2e8227SGreg Roach " FROM `##individuals`" . 1688c2e8227SGreg Roach " WHERE i_file = :tree_id" . 1698c2e8227SGreg Roach " ORDER BY i_id" . 1708c2e8227SGreg Roach " LIMIT :limit OFFSET :offset" 17113abd6f3SGreg Roach )->execute([ 1728c2e8227SGreg Roach 'tree_id' => $ged_id, 1738c2e8227SGreg Roach 'limit' => self::RECORDS_PER_VOLUME, 1748c2e8227SGreg Roach 'offset' => self::RECORDS_PER_VOLUME * $volume, 17513abd6f3SGreg Roach ])->fetchAll(); 1768c2e8227SGreg Roach foreach ($rows as $row) { 17724ec66ceSGreg Roach $records[] = Individual::getInstance($row->xref, $tree, $row->gedcom); 1788c2e8227SGreg Roach } 1798c2e8227SGreg Roach break; 1808c2e8227SGreg Roach case 's': 1818c2e8227SGreg Roach $rows = Database::prepare( 18224ec66ceSGreg Roach "SELECT s_id AS xref, s_gedcom AS gedcom" . 1838c2e8227SGreg Roach " FROM `##sources`" . 1848c2e8227SGreg Roach " WHERE s_file = :tree_id" . 1858c2e8227SGreg Roach " ORDER BY s_id" . 1868c2e8227SGreg Roach " LIMIT :limit OFFSET :offset" 18713abd6f3SGreg Roach )->execute([ 1888c2e8227SGreg Roach 'tree_id' => $ged_id, 1898c2e8227SGreg Roach 'limit' => self::RECORDS_PER_VOLUME, 1908c2e8227SGreg Roach 'offset' => self::RECORDS_PER_VOLUME * $volume, 19113abd6f3SGreg Roach ])->fetchAll(); 1928c2e8227SGreg Roach foreach ($rows as $row) { 19324ec66ceSGreg Roach $records[] = Source::getInstance($row->xref, $tree, $row->gedcom); 1948c2e8227SGreg Roach } 1958c2e8227SGreg Roach break; 1968c2e8227SGreg Roach case 'r': 1978c2e8227SGreg Roach $rows = Database::prepare( 19824ec66ceSGreg Roach "SELECT o_id AS xref, o_gedcom AS gedcom" . 1998c2e8227SGreg Roach " FROM `##other`" . 2008c2e8227SGreg Roach " WHERE o_file = :tree_id AND o_type = 'REPO'" . 2018c2e8227SGreg Roach " ORDER BY o_id" . 2028c2e8227SGreg Roach " LIMIT :limit OFFSET :offset" 20313abd6f3SGreg Roach )->execute([ 2048c2e8227SGreg Roach 'tree_id' => $ged_id, 2058c2e8227SGreg Roach 'limit' => self::RECORDS_PER_VOLUME, 2068c2e8227SGreg Roach 'offset' => self::RECORDS_PER_VOLUME * $volume, 20713abd6f3SGreg Roach ])->fetchAll(); 2088c2e8227SGreg Roach foreach ($rows as $row) { 20924ec66ceSGreg Roach $records[] = Repository::getInstance($row->xref, $tree, $row->gedcom); 2108c2e8227SGreg Roach } 2118c2e8227SGreg Roach break; 2128c2e8227SGreg Roach case 'n': 2138c2e8227SGreg Roach $rows = Database::prepare( 21424ec66ceSGreg Roach "SELECT o_id AS xref, o_gedcom AS gedcom" . 2158c2e8227SGreg Roach " FROM `##other`" . 2168c2e8227SGreg Roach " WHERE o_file = :tree_id AND o_type = 'NOTE'" . 2178c2e8227SGreg Roach " ORDER BY o_id" . 2188c2e8227SGreg Roach " LIMIT :limit OFFSET :offset" 21913abd6f3SGreg Roach )->execute([ 2208c2e8227SGreg Roach 'tree_id' => $ged_id, 2218c2e8227SGreg Roach 'limit' => self::RECORDS_PER_VOLUME, 2228c2e8227SGreg Roach 'offset' => self::RECORDS_PER_VOLUME * $volume, 22313abd6f3SGreg Roach ])->fetchAll(); 2248c2e8227SGreg Roach foreach ($rows as $row) { 22524ec66ceSGreg Roach $records[] = Note::getInstance($row->xref, $tree, $row->gedcom); 2268c2e8227SGreg Roach } 2278c2e8227SGreg Roach break; 2288c2e8227SGreg Roach case 'm': 2298c2e8227SGreg Roach $rows = Database::prepare( 23024ec66ceSGreg Roach "SELECT m_id AS xref, m_gedcom AS gedcom" . 2318c2e8227SGreg Roach " FROM `##media`" . 2328c2e8227SGreg Roach " WHERE m_file = :tree_id" . 2338c2e8227SGreg Roach " ORDER BY m_id" . 2348c2e8227SGreg Roach " LIMIT :limit OFFSET :offset" 23513abd6f3SGreg Roach )->execute([ 2368c2e8227SGreg Roach 'tree_id' => $ged_id, 2378c2e8227SGreg Roach 'limit' => self::RECORDS_PER_VOLUME, 2388c2e8227SGreg Roach 'offset' => self::RECORDS_PER_VOLUME * $volume, 23913abd6f3SGreg Roach ])->fetchAll(); 2408c2e8227SGreg Roach foreach ($rows as $row) { 24124ec66ceSGreg Roach $records[] = Media::getInstance($row->xref, $tree, $row->gedcom); 2428c2e8227SGreg Roach } 2438c2e8227SGreg Roach break; 2448c2e8227SGreg Roach } 2458c2e8227SGreg Roach foreach ($records as $record) { 2468c2e8227SGreg Roach if ($record->canShowName()) { 2478c2e8227SGreg Roach $data .= '<url>'; 2488c2e8227SGreg Roach $data .= '<loc>' . WT_BASE_URL . $record->getHtmlUrl() . '</loc>'; 2498c2e8227SGreg Roach $chan = $record->getFirstFact('CHAN'); 2508c2e8227SGreg Roach if ($chan) { 2518c2e8227SGreg Roach $date = $chan->getDate(); 2528c2e8227SGreg Roach if ($date->isOK()) { 2532a05b1e4SGreg Roach $data .= '<lastmod>' . $date->minimumDate()->Format('%Y-%m-%d') . '</lastmod>'; 2548c2e8227SGreg Roach } 2558c2e8227SGreg Roach } 2568c2e8227SGreg Roach $data .= '</url>' . PHP_EOL; 2578c2e8227SGreg Roach } 2588c2e8227SGreg Roach } 2598c2e8227SGreg Roach $data = '<' . '?xml version="1.0" encoding="UTF-8" ?' . '>' . PHP_EOL . '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">' . PHP_EOL . $data . '</urlset>' . PHP_EOL; 2608c2e8227SGreg Roach // Cache this data - but only for visitors, as we don’t want 261cdc90107SGreg Roach // visitors to see data created by signed-in users. 2628c2e8227SGreg Roach if (!Auth::check()) { 263*15d603e7SGreg Roach $this->setPreference('sitemap-' . $ged_id . '-' . $rec_type . '-' . $volume . '.xml', $data); 264*15d603e7SGreg Roach $this->setPreference('sitemap-' . $ged_id . '-' . $rec_type . '-' . $volume . '.timestamp', WT_TIMESTAMP); 2658c2e8227SGreg Roach } 2668c2e8227SGreg Roach } 2678c2e8227SGreg Roach header('Content-Type: application/xml'); 2688c2e8227SGreg Roach header('Content-Length: ' . strlen($data)); 2698c2e8227SGreg Roach echo $data; 2708c2e8227SGreg Roach } 2718c2e8227SGreg Roach 2728c2e8227SGreg Roach /** 2738c2e8227SGreg Roach * Edit the configuration 2748c2e8227SGreg Roach */ 2758c2e8227SGreg Roach private function admin() { 2768c2e8227SGreg Roach $controller = new PageController; 2778c2e8227SGreg Roach $controller 2788c2e8227SGreg Roach ->restrictAccess(Auth::isAdmin()) 2798c2e8227SGreg Roach ->setPageTitle($this->getTitle()) 2808c2e8227SGreg Roach ->pageHeader(); 2818c2e8227SGreg Roach 2828c2e8227SGreg Roach // Save the updated preferences 2838c2e8227SGreg Roach if (Filter::post('action') == 'save') { 2848c2e8227SGreg Roach foreach (Tree::getAll() as $tree) { 2858c2e8227SGreg Roach $tree->setPreference('include_in_sitemap', Filter::postBool('include' . $tree->getTreeId())); 2868c2e8227SGreg Roach } 2878c2e8227SGreg Roach // Clear cache and force files to be regenerated 2888c2e8227SGreg Roach Database::prepare( 2898c2e8227SGreg Roach "DELETE FROM `##module_setting` WHERE setting_name LIKE 'sitemap%'" 2908c2e8227SGreg Roach )->execute(); 2918c2e8227SGreg Roach } 2928c2e8227SGreg Roach 2938c2e8227SGreg Roach $include_any = false; 2948c2e8227SGreg Roach 295*15d603e7SGreg Roach echo Bootstrap4::breadcrumbs([ 296*15d603e7SGreg Roach 'admin.php' => I18N::translate('Control panel'), 297*15d603e7SGreg Roach 'admin_modules.php' => I18N::translate('Module administration'), 298*15d603e7SGreg Roach ], $controller->getPageTitle()); 2998c2e8227SGreg Roach ?> 300*15d603e7SGreg Roach 301*15d603e7SGreg Roach <h1><?= $controller->getPageTitle() ?></h1> 3028c2e8227SGreg Roach <?php 3038c2e8227SGreg Roach 3048c2e8227SGreg Roach echo 3058c2e8227SGreg Roach '<p>', 3068c2e8227SGreg Roach /* I18N: The www.sitemaps.org site is translated into many languages (e.g. http://www.sitemaps.org/fr/) - choose an appropriate URL. */ 3078c2e8227SGreg Roach I18N::translate('Sitemaps are a way for webmasters to tell search engines about the pages on a website that are available for crawling. All major search engines support sitemaps. For more information, see <a href="http://www.sitemaps.org/">www.sitemaps.org</a>.') . 3088c2e8227SGreg Roach '</p>', 309a4d5a9c2SGreg Roach '<p>', /* I18N: Label for a configuration option */ I18N::translate('Which family trees should be included in the sitemaps'), '</p>', 3108c2e8227SGreg Roach '<form method="post" action="module.php?mod=' . $this->getName() . '&mod_action=admin">', 3118c2e8227SGreg Roach '<input type="hidden" name="action" value="save">'; 3128c2e8227SGreg Roach foreach (Tree::getAll() as $tree) { 313adffb21dSGreg Roach echo '<div class="checkbox"><label><input type="checkbox" name="include', $tree->getTreeId(), '" '; 3148c2e8227SGreg Roach if ($tree->getPreference('include_in_sitemap')) { 3158c2e8227SGreg Roach echo 'checked'; 3168c2e8227SGreg Roach $include_any = true; 3178c2e8227SGreg Roach } 318adffb21dSGreg Roach echo '>', $tree->getTitleHtml(), '</label></div>'; 3198c2e8227SGreg Roach } 3208c2e8227SGreg Roach echo 3218c2e8227SGreg Roach '<input type="submit" value="', I18N::translate('save'), '">', 3228c2e8227SGreg Roach '</form>', 3238c2e8227SGreg Roach '<hr>'; 3248c2e8227SGreg Roach 3258c2e8227SGreg Roach if ($include_any) { 3268c2e8227SGreg Roach $site_map_url1 = WT_BASE_URL . 'module.php?mod=' . $this->getName() . '&mod_action=generate&file=sitemap.xml'; 3278c2e8227SGreg Roach $site_map_url2 = rawurlencode(WT_BASE_URL . 'module.php?mod=' . $this->getName() . '&mod_action=generate&file=sitemap.xml'); 3288c2e8227SGreg Roach echo 3298c2e8227SGreg Roach '<p>', I18N::translate('To tell search engines that sitemaps are available, you should add the following line to your robots.txt file.'), '</p>', 3308c2e8227SGreg Roach '<pre>Sitemap: ', $site_map_url1, '</pre>', 3318c2e8227SGreg Roach '<hr>', 3328c2e8227SGreg Roach '<p>', I18N::translate('To tell search engines that sitemaps are available, you can use the following links.'), '</p>', 3338c2e8227SGreg Roach '<ul>', 3348c2e8227SGreg Roach // This list comes from http://en.wikipedia.org/wiki/Sitemaps 3352032bcddSRobert Scheck '<li><a href="https://www.bing.com/webmaster/ping.aspx?siteMap=' . $site_map_url2 . '">Bing</a></li>', 3362032bcddSRobert Scheck '<li><a href="https://www.google.com/webmasters/tools/ping?sitemap=' . $site_map_url2 . '">Google</a></li>', 3378c2e8227SGreg Roach '</ul>'; 3388c2e8227SGreg Roach 3398c2e8227SGreg Roach } 3408c2e8227SGreg Roach } 3418c2e8227SGreg Roach 3428c2e8227SGreg Roach /** {@inheritdoc} */ 3438c2e8227SGreg Roach public function getConfigLink() { 3448c2e8227SGreg Roach return 'module.php?mod=' . $this->getName() . '&mod_action=admin'; 3458c2e8227SGreg Roach } 3468c2e8227SGreg Roach} 347