+
+ /**
+ * Get the namespace text of the talk page
+ *
+ * @return string Namespace text
+ */
+ public function getTalkNsText() {
+ global $wgContLang;
+ return $wgContLang->getNsText( MWNamespace::getTalk( $this->mNamespace ) );
+ }
+
+ /**
+ * Can this title have a corresponding talk page?
+ *
+ * @deprecated since 1.30, use canHaveTalkPage() instead.
+ *
+ * @return bool True if this title either is a talk page or can have a talk page associated.
+ */
+ public function canTalk() {
+ return $this->canHaveTalkPage();
+ }
+
+ /**
+ * Can this title have a corresponding talk page?
+ *
+ * @see MWNamespace::hasTalkNamespace
+ * @since 1.30
+ *
+ * @return bool True if this title either is a talk page or can have a talk page associated.
+ */
+ public function canHaveTalkPage() {
+ return MWNamespace::hasTalkNamespace( $this->mNamespace );
+ }
+
+ /**
+ * Is this in a namespace that allows actual pages?
+ *
+ * @return bool
+ */
+ public function canExist() {
+ return $this->mNamespace >= NS_MAIN;
+ }
+
+ /**
+ * Can this title be added to a user's watchlist?
+ *
+ * @return bool
+ */
+ public function isWatchable() {
+ return !$this->isExternal() && MWNamespace::isWatchable( $this->getNamespace() );
+ }
+
+ /**
+ * Returns true if this is a special page.
+ *
+ * @return bool
+ */
+ public function isSpecialPage() {
+ return $this->getNamespace() == NS_SPECIAL;
+ }
+
+ /**
+ * Returns true if this title resolves to the named special page
+ *
+ * @param string $name The special page name
+ * @return bool
+ */
+ public function isSpecial( $name ) {
+ if ( $this->isSpecialPage() ) {
+ list( $thisName, /* $subpage */ ) = SpecialPageFactory::resolveAlias( $this->getDBkey() );
+ if ( $name == $thisName ) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * If the Title refers to a special page alias which is not the local default, resolve
+ * the alias, and localise the name as necessary. Otherwise, return $this
+ *
+ * @return Title
+ */
+ public function fixSpecialName() {
+ if ( $this->isSpecialPage() ) {
+ list( $canonicalName, $par ) = SpecialPageFactory::resolveAlias( $this->mDbkeyform );
+ if ( $canonicalName ) {
+ $localName = SpecialPageFactory::getLocalNameFor( $canonicalName, $par );
+ if ( $localName != $this->mDbkeyform ) {
+ return self::makeTitle( NS_SPECIAL, $localName );
+ }
+ }
+ }
+ return $this;
+ }
+
+ /**
+ * Returns true if the title is inside the specified namespace.
+ *
+ * Please make use of this instead of comparing to getNamespace()
+ * This function is much more resistant to changes we may make
+ * to namespaces than code that makes direct comparisons.
+ * @param int $ns The namespace
+ * @return bool
+ * @since 1.19
+ */
+ public function inNamespace( $ns ) {
+ return MWNamespace::equals( $this->getNamespace(), $ns );
+ }
+
+ /**
+ * Returns true if the title is inside one of the specified namespaces.
+ *
+ * @param int|int[] $namespaces,... The namespaces to check for
+ * @return bool
+ * @since 1.19
+ */
+ public function inNamespaces( /* ... */ ) {
+ $namespaces = func_get_args();
+ if ( count( $namespaces ) > 0 && is_array( $namespaces[0] ) ) {
+ $namespaces = $namespaces[0];
+ }
+
+ foreach ( $namespaces as $ns ) {
+ if ( $this->inNamespace( $ns ) ) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns true if the title has the same subject namespace as the
+ * namespace specified.
+ * For example this method will take NS_USER and return true if namespace
+ * is either NS_USER or NS_USER_TALK since both of them have NS_USER
+ * as their subject namespace.
+ *
+ * This is MUCH simpler than individually testing for equivalence
+ * against both NS_USER and NS_USER_TALK, and is also forward compatible.
+ * @since 1.19
+ * @param int $ns
+ * @return bool
+ */
+ public function hasSubjectNamespace( $ns ) {
+ return MWNamespace::subjectEquals( $this->getNamespace(), $ns );
+ }
+
+ /**
+ * Is this Title in a namespace which contains content?
+ * In other words, is this a content page, for the purposes of calculating
+ * statistics, etc?
+ *
+ * @return bool
+ */
+ public function isContentPage() {
+ return MWNamespace::isContent( $this->getNamespace() );
+ }
+
+ /**
+ * Would anybody with sufficient privileges be able to move this page?
+ * Some pages just aren't movable.
+ *
+ * @return bool
+ */
+ public function isMovable() {
+ if ( !MWNamespace::isMovable( $this->getNamespace() ) || $this->isExternal() ) {
+ // Interwiki title or immovable namespace. Hooks don't get to override here
+ return false;
+ }
+
+ $result = true;
+ Hooks::run( 'TitleIsMovable', [ $this, &$result ] );
+ return $result;
+ }
+
+ /**
+ * Is this the mainpage?
+ * @note Title::newFromText seems to be sufficiently optimized by the title
+ * cache that we don't need to over-optimize by doing direct comparisons and
+ * accidentally creating new bugs where $title->equals( Title::newFromText() )
+ * ends up reporting something differently than $title->isMainPage();
+ *
+ * @since 1.18
+ * @return bool
+ */
+ public function isMainPage() {
+ return $this->equals( self::newMainPage() );
+ }
+
+ /**
+ * Is this a subpage?
+ *
+ * @return bool
+ */
+ public function isSubpage() {
+ return MWNamespace::hasSubpages( $this->mNamespace )
+ ? strpos( $this->getText(), '/' ) !== false
+ : false;
+ }
+
+ /**
+ * Is this a conversion table for the LanguageConverter?
+ *
+ * @return bool
+ */
+ public function isConversionTable() {
+ // @todo ConversionTable should become a separate content model.
+
+ return $this->getNamespace() == NS_MEDIAWIKI &&
+ strpos( $this->getText(), 'Conversiontable/' ) === 0;
+ }
+
+ /**
+ * Does that page contain wikitext, or it is JS, CSS or whatever?
+ *
+ * @return bool
+ */
+ public function isWikitextPage() {
+ return $this->hasContentModel( CONTENT_MODEL_WIKITEXT );
+ }
+
+ /**
+ * Could this page contain custom CSS or JavaScript for the global UI.
+ * This is generally true for pages in the MediaWiki namespace having CONTENT_MODEL_CSS
+ * or CONTENT_MODEL_JAVASCRIPT.
+ *
+ * This method does *not* return true for per-user JS/CSS. Use isCssJsSubpage()
+ * for that!
+ *
+ * Note that this method should not return true for pages that contain and
+ * show "inactive" CSS or JS.
+ *
+ * @return bool
+ * @todo FIXME: Rename to isSiteConfigPage() and remove deprecated hook
+ */
+ public function isCssOrJsPage() {
+ $isCssOrJsPage = NS_MEDIAWIKI == $this->mNamespace
+ && ( $this->hasContentModel( CONTENT_MODEL_CSS )
+ || $this->hasContentModel( CONTENT_MODEL_JAVASCRIPT ) );
+
+ return $isCssOrJsPage;
+ }
+
+ /**
+ * Is this a .css or .js subpage of a user page?
+ * @return bool
+ * @todo FIXME: Rename to isUserConfigPage()
+ */
+ public function isCssJsSubpage() {
+ return ( NS_USER == $this->mNamespace && $this->isSubpage()
+ && ( $this->hasContentModel( CONTENT_MODEL_CSS )
+ || $this->hasContentModel( CONTENT_MODEL_JAVASCRIPT ) ) );
+ }
+
+ /**
+ * Trim down a .css or .js subpage title to get the corresponding skin name
+ *
+ * @return string Containing skin name from .css or .js subpage title
+ */
+ public function getSkinFromCssJsSubpage() {
+ $subpage = explode( '/', $this->mTextform );
+ $subpage = $subpage[count( $subpage ) - 1];
+ $lastdot = strrpos( $subpage, '.' );
+ if ( $lastdot === false ) {
+ return $subpage; # Never happens: only called for names ending in '.css' or '.js'
+ }
+ return substr( $subpage, 0, $lastdot );
+ }
+
+ /**
+ * Is this a .css subpage of a user page?
+ *
+ * @return bool
+ */
+ public function isCssSubpage() {
+ return ( NS_USER == $this->mNamespace && $this->isSubpage()
+ && $this->hasContentModel( CONTENT_MODEL_CSS ) );
+ }
+
+ /**
+ * Is this a .js subpage of a user page?
+ *
+ * @return bool
+ */
+ public function isJsSubpage() {
+ return ( NS_USER == $this->mNamespace && $this->isSubpage()
+ && $this->hasContentModel( CONTENT_MODEL_JAVASCRIPT ) );
+ }
+
+ /**
+ * Is this a talk page of some sort?
+ *
+ * @return bool
+ */
+ public function isTalkPage() {
+ return MWNamespace::isTalk( $this->getNamespace() );
+ }
+
+ /**
+ * Get a Title object associated with the talk page of this article
+ *
+ * @return Title The object for the talk page
+ */
+ public function getTalkPage() {
+ return self::makeTitle( MWNamespace::getTalk( $this->getNamespace() ), $this->getDBkey() );
+ }
+
+ /**
+ * Get a Title object associated with the talk page of this article,
+ * if such a talk page can exist.
+ *
+ * @since 1.30
+ *
+ * @return Title|null The object for the talk page,
+ * or null if no associated talk page can exist, according to canHaveTalkPage().
+ */
+ public function getTalkPageIfDefined() {
+ if ( !$this->canHaveTalkPage() ) {
+ return null;
+ }
+
+ return $this->getTalkPage();
+ }
+
+ /**
+ * Get a title object associated with the subject page of this
+ * talk page
+ *
+ * @return Title The object for the subject page
+ */
+ public function getSubjectPage() {
+ // Is this the same title?
+ $subjectNS = MWNamespace::getSubject( $this->getNamespace() );
+ if ( $this->getNamespace() == $subjectNS ) {
+ return $this;
+ }
+ return self::makeTitle( $subjectNS, $this->getDBkey() );
+ }
+