Working with page titles using Title, TitleValue, TitleFormatter, and related services.
MediaWiki represents page titles in several complementary types, from the mutable, feature-rich Title class to lightweight immutable value objects and narrow identity interfaces. Understanding when to use each avoids unnecessary coupling to global state.
Mutable class implementing both LinkTarget and PageIdentity. Fetches data from the database and uses global state. Use in presentation code and legacy entry points; prefer lighter types in services.
TitleValue
Immutable value object implementing LinkTarget. No global state, no DB access. Holds namespace, DB key, fragment, and interwiki prefix. Preferred for data transfer between services.
PageReference
Minimal interface: getNamespace(), getDBkey(), getWikiId(). Used as the most general parameter type for services that only need to identify a page.
PageIdentity
Extends PageReference with getId(). Represents a page that may or may not exist. Title implements this interface.
TitleValue is the preferred type for internal data transfer. It is immutable, causes no side effects, and does not depend on global state. Prefer TitleValue (or PageReference / PageIdentity) over Title in service constructors and method signatures.
use MediaWiki\Title\Title;// Parse user-supplied or wikitext title strings$title = Title::newFromText( 'Talk:Foo bar' );if ( $title === null ) { // Title string was invalid}// With an explicit default namespace$title = Title::newFromText( 'Foo', NS_TEMPLATE ); // Template:Foo
Title::newFromText() maintains an in-process LRU cache of up to 1000 entries. It may return a previously constructed instance. If you need a guaranteed-fresh object, use makeTitle() or clone the returned instance.
$title = Title::newFromText( 'Talk:Foo bar#Section' );// Text form (spaces, no namespace prefix)$title->getText(); // 'Foo bar'// Full text including namespace and fragment$title->getFullText(); // 'Talk:Foo bar#Section'// Prefixed text (namespace + title, no fragment)$title->getPrefixedText(); // 'Talk:Foo bar'// Database key form (underscores)$title->getDBkey(); // 'Foo_bar'$title->getPrefixedDBkey(); // 'Talk:Foo_bar'// Namespace integer$title->getNamespace(); // NS_TALK (= 1)// Fragment$title->getFragment(); // 'Section'// Article ID (0 if page does not exist; triggers DB lookup)$title->getArticleID(); // e.g. 42// Existence checks$title->isKnown(); // true if the page exists or is a special page$title->exists(); // true only if the page exists in the database$title->isSpecialPage(); // true for NS_SPECIAL titles// URL$title->getLocalURL(); // '/wiki/Talk:Foo_bar'$title->getFullURL(); // 'https://example.org/wiki/Talk:Foo_bar'// Related titles$title->getTalkPage(); // Title for the talk page$title->getSubjectPage(); // Title for the subject page$title->getBaseTitle(); // Title without the last subpage component
TitleValue (namespace MediaWiki\Title, since 1.23) is an immutable value object implementing LinkTarget. It stores namespace, DB key, fragment, and interwiki prefix.
use MediaWiki\Title\TitleValue;// Direct construction (trusted data only — no validation beyond basic checks)$tv = new TitleValue( NS_MAIN, 'Main_Page' );$tv = new TitleValue( NS_USER, 'Alice', 'Contributions' ); // with fragment$tv = new TitleValue( NS_MAIN, 'Foo', '', 'de' ); // interwiki// Safe construction (returns null on invalid input)$tv = TitleValue::tryNew( NS_MAIN, 'Main_Page' );// From a PageReference$tv = TitleValue::newFromPage( $pageReference );// From another LinkTarget$tv = TitleValue::newFromLinkTarget( $linkTarget );// Accessors$tv->getNamespace(); // int$tv->getDBkey(); // string, underscored$tv->getText(); // string, spaces (from LinkTargetTrait)$tv->getFragment(); // string$tv->getInterwiki(); // string// Create a copy with a different fragment$tv2 = $tv->createFragmentTarget( 'NewSection' );
Use TitleParser::makeTitleValueSafe() when constructing TitleValue from user input or untrusted sources. It applies full normalization and validation and returns null on failure.
TitleFormatter (MediaWiki\Title\TitleFormatter, since 1.23, @since 1.28 in MediaWikiServices) converts title objects into display strings. Obtain it from the DI container:
use MediaWiki\Title\TitleValue;$tv = new TitleValue( NS_USER, 'Alice' );// Display text without namespace$formatter->getText( $tv ); // 'Alice'// Display text with namespace (spaces)$formatter->getPrefixedText( $tv ); // 'User:Alice'// DB key with namespace (underscores)$formatter->getPrefixedDBkey( $tv ); // 'User:Alice' (underscored if spaces in title)// Full text with namespace and fragment$formatter->getFullText( $tv ); // 'User:Alice'// Format from raw parts$formatter->formatTitle( NS_USER_TALK, // namespace 'Alice', // page text 'Talk', // fragment (optional) '' // interwiki prefix (optional)); // 'User talk:Alice#Talk'// Namespace name (respects gender-sensitive languages)$formatter->getNamespaceName( NS_USER, 'Alice' ); // 'User'
TitleFormatter::getText() and getPrefixedText() accept both LinkTarget and PageReference objects.
use MediaWiki\Title\TitleValue;use Wikimedia\HtmlArmor\HtmlArmor;$target = new TitleValue( NS_MAIN, 'Main_Page' );// Auto-detect existence (DB lookup if not cached)$html = $linkRenderer->makeLink( $target );// <a href="/wiki/Main_Page">Main Page</a> (blue or red depending on existence)// Force blue-link style (no DB lookup)$html = $linkRenderer->makeKnownLink( $target, 'Go to main page', // custom text (string or HtmlArmor) [ 'class' => 'mw-redirect' ], // extra <a> attributes [ 'action' => 'history' ] // query string parameters);// Force red-link style$html = $linkRenderer->makeBrokenLink( $target, null, // null = use default title text [], []);// Blue link with pre-trusted HTML as the link text$html = $linkRenderer->makeKnownLink( $target, new HtmlArmor( '<b>Main Page</b>' ));// External link (since 1.43)$html = $linkRenderer->makeExternalLink( 'https://example.org', 'Example', $currentTitle);
makeLink() performs a database lookup to determine page existence if the title is not in LinkCache. Use makeKnownLink() when you know the page exists, or makePreloadedLink() when you want a blue-link style without any DB overhead.