Page MenuHomeWickedGov Phorge

SitemapGenerator.php
No OneTemporary

Size
6 KB
Referenced Files
None
Subscribers
None

SitemapGenerator.php

<?php
namespace MediaWiki\Page;
use MediaWiki\Cache\GenderCache;
use MediaWiki\Config\Config;
use MediaWiki\Language\Language;
use MediaWiki\Languages\LanguageConverterFactory;
use MediaWiki\MainConfigNames;
use MediaWiki\Title\Title;
use MediaWiki\Xml\Xml;
use Wikimedia\Rdbms\IReadableDatabase;
/**
* Utility for generating a sitemap
*
* @internal
*/
class SitemapGenerator {
private ?array $namespaces = null;
private ?array $excludedNamespaces = null;
private ?int $startId = null;
private ?int $endId = null;
private array $variants = [];
private bool $skipRedirects = false;
private ?int $limit = null;
private ?int $nextBatchStart = null;
/**
* The gender cache, or null if the content language has no gendered namespaces
* @var GenderCache|null
*/
private ?GenderCache $genderCache;
/** @return array */
public static function getVariants(
Language $contLang,
LanguageConverterFactory $languageConverterFactory,
) {
$converter = $languageConverterFactory->getLanguageConverter( $contLang );
$variants = [];
foreach ( $converter->getVariants() as $vCode ) {
// We don't want the default variant
if ( $vCode !== $contLang->getCode() ) {
$variants[] = $vCode;
}
}
return $variants;
}
public function __construct(
Language $contLang,
LanguageConverterFactory $languageConverterFactory,
GenderCache $genderCache,
) {
$this->variants = self::getVariants( $contLang, $languageConverterFactory );
$this->genderCache = $contLang->needsGenderDistinction() ? $genderCache : null;
}
/**
* Optionally limit the namespace IDs
*
* @param int[]|null $namespaces
* @return $this
*/
public function namespaces( ?array $namespaces ) {
$this->namespaces = $namespaces;
return $this;
}
/**
* Set the included/excluded namespace list based on configuration
*
* @param Config $config
* @return $this
*/
public function namespacesFromConfig( Config $config ) {
$this->namespaces = null;
$this->excludedNamespaces = null;
$namespaces = $config->get( MainConfigNames::SitemapNamespaces );
if ( $namespaces ) {
$this->namespaces = $namespaces;
return $this;
}
$defaultPolicy = $config->get( MainConfigNames::DefaultRobotPolicy );
$namespacePolicies = $config->get( MainConfigNames::NamespaceRobotPolicies );
if ( self::isNoIndex( $defaultPolicy ) ) {
$namespaces = [];
foreach ( $namespacePolicies as $ns => $policy ) {
if ( !self::isNoIndex( $policy ) ) {
$namespaces[] = $ns;
}
}
$this->namespaces = $namespaces;
} else {
$excluded = [];
foreach ( $namespacePolicies as $ns => $policy ) {
if ( self::isNoIndex( $policy ) ) {
$excluded[] = $ns;
}
}
if ( $excluded ) {
$this->excludedNamespaces = $excluded;
}
}
return $this;
}
/**
* Interpret a configured robots policy
*
* @param string|array $policy
* @return bool
*/
private static function isNoIndex( $policy ) {
$policyArray = Article::formatRobotPolicy( $policy );
return ( $policyArray['index'] ?? '' ) === 'noindex';
}
/**
* Limit the page_id range to the given half-open interval
*
* @param int|null $startId The start ID, or null for unlimited
* @param int|null $endId The end ID, or null for unlimited. Only pages
* with a page_id less than this value will be returned.
* @return $this
*/
public function idRange( ?int $startId, ?int $endId ) {
$this->startId = $startId;
$this->endId = $endId;
return $this;
}
/**
* Skip redirects
*
* @param bool $skip
* @return $this
*/
public function skipRedirects( bool $skip = true ) {
$this->skipRedirects = $skip;
return $this;
}
/**
* Limit the number of returned results.
*
* @param int $limit
* @return $this
*/
public function limit( int $limit ) {
$this->limit = $limit;
return $this;
}
/**
* If a previous call to getXml() reached the limit set by limit() and there
* were still more rows, calling this will advance an internal cursor to the
* start of the next batch, and return true.
*
* If there were no more rows, return false.
*
* @return bool
*/
public function nextBatch() {
if ( $this->nextBatchStart !== null ) {
$this->startId = $this->nextBatchStart;
return true;
} else {
return false;
}
}
/**
* Use the previously set options to generate an XML sitemap
*
* @param IReadableDatabase $dbr
* @return string
*/
public function getXml( IReadableDatabase $dbr ) {
$empty = false;
$sqb = $dbr->newSelectQueryBuilder()
->select( [ 'page_id', 'page_namespace', 'page_title', 'page_touched' ] )
->from( 'page' )
->leftJoin( 'page_props', null, [ 'page_id = pp_page', 'pp_propname' => 'noindex' ] )
->where( [ 'pp_propname' => null ] )
->orderBy( 'page_id' )
->caller( __METHOD__ );
if ( $this->startId !== null ) {
$sqb->where( $dbr->expr( 'page_id', '>=', $this->startId ) );
}
if ( $this->endId !== null ) {
$sqb->where( $dbr->expr( 'page_id', '<', $this->endId ) );
}
if ( $this->namespaces !== null ) {
if ( $this->namespaces === [] ) {
$empty = true;
} else {
$sqb->where( [ 'page_namespace' => $this->namespaces ] );
}
}
if ( $this->excludedNamespaces !== null ) {
$sqb->where( [ $dbr->expr( 'page_namespace', '!=', $this->excludedNamespaces ) ] );
}
if ( $this->skipRedirects ) {
$sqb->where( [ 'page_is_redirect' => 0 ] );
}
$variants = [ null, ...$this->variants ];
if ( $this->limit ) {
$pageLimit = (int)( $this->limit / count( $variants ) );
$sqb->limit( $pageLimit + 1 );
} else {
$pageLimit = null;
}
$res = $empty ? [] : $sqb->fetchResultSet();
$this->genderCache?->doPageRows( $res );
$xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" .
"<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">\n";
$count = 0;
$nextBatchStart = 0;
foreach ( $res as $row ) {
if ( $pageLimit !== null && ++$count > $pageLimit ) {
$nextBatchStart = (int)$row->page_id;
break;
}
$title = Title::makeTitle( $row->page_namespace, $row->page_title );
foreach ( $variants as $variant ) {
$query = $variant === null ? '' : 'variant=' . urlencode( $variant );
$xml .= '<url>' .
Xml::element( 'loc', null, $title->getCanonicalURL( $query ) ) .
Xml::element( 'lastmod', null, wfTimestamp( TS_ISO_8601, $row->page_touched ) ) .
"</url>\n";
}
}
$xml .= "</urlset>\n";
if ( $nextBatchStart ) {
$this->nextBatchStart = $nextBatchStart;
} else {
$this->nextBatchStart = null;
}
return $xml;
}
}

File Metadata

Mime Type
text/x-php
Expires
Aug 16 2026, 11:20 (12 w, 6 h ago)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
2b/f1/b4cfee3ccc7ae6c62b910a27c0aa
Default Alt Text
SitemapGenerator.php (6 KB)

Event Timeline