From: Happy-melon Date: Mon, 31 Aug 2009 19:19:12 +0000 (+0000) Subject: (bug14900) Make __INDEX__ and __NOINDEX__ not override $wgArticleRobotPolicies where... X-Git-Tag: 1.31.0-rc.0~39986 X-Git-Url: http://git.cyclocoop.org/%40spipnet%40?a=commitdiff_plain;h=a0e83700a678dd813bf5173bac7f30e67d48c706;p=lhc%2Fweb%2Fwiklou.git (bug14900) Make __INDEX__ and __NOINDEX__ not override $wgArticleRobotPolicies where the two conflict. --- diff --git a/RELEASE-NOTES b/RELEASE-NOTES index d256afd746..7b20f0e5a2 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -449,6 +449,8 @@ this. Was used when mwEmbed was going to be an extension. (analogous to EditFilter hook) * (bug 2257) Tag extensions can expand template parameters provided to the tag, by using a new parameter added to the recursiveTagParse function +* (bug 14900) __INDEX__ and __NOINDEX__ no longer override site config set in + $wgArticleRobotPolicies. == API changes in 1.16 == diff --git a/includes/Article.php b/includes/Article.php index 5c37d9badf..8824f72379 100644 --- a/includes/Article.php +++ b/includes/Article.php @@ -41,6 +41,7 @@ class Article { var $mUser = -1; //!< Not loaded var $mUserText = ''; //!< var $mParserOptions; //!< + var $mParserOutput; //!< /**@}}*/ /** @@ -772,7 +773,6 @@ class Article { } $wgOut->setArticleFlag( true ); - $wgOut->setRobotPolicy( $this->getRobotPolicyForView() ); # Set page title (may be overridden by DISPLAYTITLE) $wgOut->setPageTitle( $this->mTitle->getPrefixedText() ); @@ -794,8 +794,8 @@ class Article { # For the main page, overwrite the element with the con- # tents of 'pagetitle-view-mainpage' instead of the default (if # that's not empty). - if( $this->mTitle->equals( Title::newMainPage() ) - && wfMsgForContent( 'pagetitle-view-mainpage' ) !== '' ) + if( $this->mTitle->equals( Title::newMainPage() ) + && wfMsgForContent( 'pagetitle-view-mainpage' ) !== '' ) { $wgOut->setHTMLTitle( wfMsgForContent( 'pagetitle-view-mainpage' ) ); } @@ -803,108 +803,123 @@ class Article { $wasRedirected = $this->showRedirectedFromHeader(); $this->showNamespaceHeader(); + # Iterate through the possible ways of constructing the output text. + # Keep going until $outputDone is set, or we run out of things to do. + $pass = 0; $outputDone = false; - wfRunHooks( 'ArticleViewHeader', array( &$this, &$outputDone, &$useParserCache ) ); - - # Try the parser cache - if( !$outputDone && $useParserCache ) { - $parserOutput = $parserCache->get( $this, $parserOptions ); - if ( $parserOutput !== false ) { - wfDebug( __METHOD__.": showing parser cache contents\n" ); - $wgOut->addParserOutput( $parserOutput ); - // Ensure that UI elements requiring revision ID have - // the correct version information. - $wgOut->setRevisionId( $this->mLatest ); - $outputDone = true; - } - } + while( !$outputDone && ++$pass ){ + switch( $pass ){ + + case 1: + wfRunHooks( 'ArticleViewHeader', array( &$this, &$outputDone, &$useParserCache ) ); + break; + + case 2: + # Try the parser cache + if( $useParserCache ) { + $this->mParserOutput = $parserCache->get( $this, $parserOptions ); + if ( $this->mParserOutput !== false ) { + wfDebug( __METHOD__.": showing parser cache contents\n" ); + $wgOut->addParserOutput( $this->mParserOutput ); + # Ensure that UI elements requiring revision ID have + # the correct version information. + $wgOut->setRevisionId( $this->mLatest ); + $outputDone = true; + } + } + break; + + case 3: + $text = $this->getContent(); + if( $text === false || $this->getID() == 0 ) { + wfDebug( __METHOD__.": showing missing article\n" ); + $this->showMissingArticle(); + wfProfileOut( __METHOD__ ); + return; + } - if ( $outputDone ) { - $this->showViewFooter(); - $this->viewUpdates(); - wfProfileOut( __METHOD__ ); - return; - } + # Another whitelist check in case oldid is altering the title + if( !$this->mTitle->userCanRead() ) { + wfDebug( __METHOD__.": denied on secondary read check\n" ); + $wgOut->loginToUse(); + $wgOut->output(); + $wgOut->disable(); + wfProfileOut( __METHOD__ ); + return; + } - $text = $this->getContent(); - if( $text === false || $this->getID() == 0 ) { - wfDebug( __METHOD__.": showing missing article\n" ); - $this->showMissingArticle(); - wfProfileOut( __METHOD__ ); - return; - } + # Are we looking at an old revision + if( $oldid && !is_null( $this->mRevision ) ) { + $this->setOldSubtitle( $oldid ); + if ( !$this->showDeletedRevisionHeader() ) { + wfDebug( __METHOD__.": cannot view deleted revision\n" ); + wfProfileOut( __METHOD__ ); + return; + } - # Another whitelist check in case oldid is altering the title - if( !$this->mTitle->userCanRead() ) { - wfDebug( __METHOD__.": denied on secondary read check\n" ); - $wgOut->loginToUse(); - $wgOut->output(); - $wgOut->disable(); - wfProfileOut( __METHOD__ ); - return; - } + if ( $oldid === $this->getLatest() && $this->useParserCache( false ) ) { + $this->mParserOutput = $parserCache->get( $this, $parserOptions ); + if ( $this->mParserOutput ) { + wfDebug( __METHOD__.": showing parser cache for current rev permalink\n" ); + $wgOut->addParserOutput( $this->mParserOutput ); + $this->showViewFooter(); + $this->viewUpdates(); + wfProfileOut( __METHOD__ ); + return; + } + } + } - # We're looking at an old revision - if( $oldid && !is_null( $this->mRevision ) ) { - $this->setOldSubtitle( $oldid ); - if ( !$this->showDeletedRevisionHeader() ) { - wfDebug( __METHOD__.": cannot view deleted revision\n" ); - wfProfileOut( __METHOD__ ); - return; - } + # Ensure that UI elements requiring revision ID have + # the correct version information. + $wgOut->setRevisionId( $this->getRevIdFetched() ); + + # Pages containing custom CSS or JavaScript get special treatment + if( $this->mTitle->isCssOrJsPage() || $this->mTitle->isCssJsSubpage() ) { + wfDebug( __METHOD__.": showing CSS/JS source\n" ); + $this->showCssOrJsPage(); + $outputDone = true; + } else if( $rt = Title::newFromRedirectArray( $text ) ) { + wfDebug( __METHOD__.": showing redirect=no page\n" ); + # Viewing a redirect page (e.g. with parameter redirect=no) + # Don't append the subtitle if this was an old revision + $wgOut->addHTML( $this->viewRedirect( $rt, !$wasRedirected && $this->isCurrent() ) ); + # Parse just to get categories, displaytitle, etc. + $this->mParserOutput = $wgParser->parse( $text, $this->mTitle, $parserOptions ); + $wgOut->addParserOutputNoText( $this->mParserOutput ); + $outputDone = true; + } + break; + + case 4: + # Run the parse, protected by a pool counter + wfDebug( __METHOD__.": doing uncached parse\n" ); + $key = $parserCache->getKey( $this, $parserOptions ); + $poolCounter = PoolCounter::factory( 'Article::view', $key ); + $dirtyCallback = $useParserCache ? array( $this, 'tryDirtyCache' ) : false; + $status = $poolCounter->executeProtected( array( $this, 'doViewParse' ), $dirtyCallback ); + + if ( !$status->isOK() ) { + # Connection or timeout error + $this->showPoolError( $status ); + wfProfileOut( __METHOD__ ); + return; + } else { + $outputDone = true; + } + break; - if ( $oldid === $this->getLatest() && $this->useParserCache( false ) ) { - $parserOutput = $parserCache->get( $this, $parserOptions ); - if ( $parserOutput ) { - wfDebug( __METHOD__.": showing parser cache for current rev permalink\n" ); - $wgOut->addParserOutput( $parserOutput ); - $this->showViewFooter(); - $this->viewUpdates(); - wfProfileOut( __METHOD__ ); - return; - } + # Should be unreachable, but just in case... + default: + break 2; } } - // Ensure that UI elements requiring revision ID have - // the correct version information. - $wgOut->setRevisionId( $this->getRevIdFetched() ); - - // Pages containing custom CSS or JavaScript get special treatment - if( $this->mTitle->isCssOrJsPage() || $this->mTitle->isCssJsSubpage() ) { - wfDebug( __METHOD__.": showing CSS/JS source\n" ); - $this->showCssOrJsPage(); - $outputDone = true; - } else if( $rt = Title::newFromRedirectArray( $text ) ) { - wfDebug( __METHOD__.": showing redirect=no page\n" ); - # Viewing a redirect page (e.g. with parameter redirect=no) - # Don't append the subtitle if this was an old revision - $wgOut->addHTML( $this->viewRedirect( $rt, !$wasRedirected && $this->isCurrent() ) ); - # Parse just to get categories, displaytitle, etc. - $parserOutput = $wgParser->parse( $text, $this->mTitle, $parserOptions ); - $wgOut->addParserOutputNoText( $parserOutput ); - $outputDone = true; - } - if ( $outputDone ) { - $this->showViewFooter(); - $this->viewUpdates(); - wfProfileOut( __METHOD__ ); - return; - } - - # Run the parse, protected by a pool counter - wfDebug( __METHOD__.": doing uncached parse\n" ); - $key = $parserCache->getKey( $this, $parserOptions ); - $poolCounter = PoolCounter::factory( 'Article::view', $key ); - $dirtyCallback = $useParserCache ? array( $this, 'tryDirtyCache' ) : false; - $status = $poolCounter->executeProtected( array( $this, 'doViewParse' ), $dirtyCallback ); - - if ( !$status->isOK() ) { - # Connection or timeout error - $this->showPoolError( $status ); - wfProfileOut( __METHOD__ ); - return; - } + # Now that we've filled $this->mParserOutput, we know whether + # there are any __NOINDEX__ tags on the page + $policy = $this->getRobotPolicy( 'view' ); + $wgOut->setIndexPolicy( $policy['index'] ); + $wgOut->setFollowPolicy( $policy['follow'] ); $this->showViewFooter(); $this->viewUpdates(); @@ -962,8 +977,24 @@ class Article { /** * Get the robot policy to be used for the current action=view request. + * @return String the policy that should be set + * @deprecated use getRobotPolicy() instead, which returns an associative + * array */ public function getRobotPolicyForView() { + wfDeprecated( __FUNC__ ); + $policy = $this->getRobotPolicy( 'view' ); + return $policy['index'] . ',' . $policy['follow']; + } + + /** + * Get the robot policy to be used for the current view + * @param $action String the action= GET parameter + * @return Array the policy that should be set + * TODO: actions other than 'view' + */ + public function getRobotPolicy( $action ){ + global $wgOut, $wgArticleRobotPolicies, $wgNamespaceRobotPolicies; global $wgDefaultRobotPolicy, $wgRequest; @@ -973,27 +1004,77 @@ class Article { if( !$this->mTitle->isSubpage() ) { $block = new Block(); if( $block->load( $this->mTitle->getText() ) ) { - return 'noindex,nofollow'; + return array( 'index' => 'noindex', + 'follow' => 'nofollow' ); } } } if( $this->getID() === 0 || $this->getOldID() ) { - return 'noindex,nofollow'; + # Non-articles (special pages etc), and old revisions + return array( 'index' => 'noindex', + 'follow' => 'nofollow' ); } elseif( $wgOut->isPrintable() ) { # Discourage indexing of printable versions, but encourage following - return 'noindex,follow'; + return array( 'index' => 'noindex', + 'follow' => 'follow' ); } elseif( $wgRequest->getInt('curid') ) { # For ?curid=x urls, disallow indexing - return 'noindex,follow'; - } elseif( isset( $wgArticleRobotPolicies[$this->mTitle->getPrefixedText()] ) ) { - return $wgArticleRobotPolicies[$this->mTitle->getPrefixedText()]; - } elseif( isset( $wgNamespaceRobotPolicies[$ns] ) ) { + return array( 'index' => 'noindex', + 'follow' => 'follow' ); + } + + # Otherwise, construct the policy based on the various config variables. + $policy = self::formatRobotPolicy( $wgDefaultRobotPolicy ); + + if( isset( $wgNamespaceRobotPolicies[$ns] ) ){ # Honour customised robot policies for this namespace - return $wgNamespaceRobotPolicies[$ns]; - } else { - return $wgDefaultRobotPolicy; + $policy = array_merge( $policy, + self::formatRobotPolicy( $wgNamespaceRobotPolicies[$ns] ) ); + } + + if( $this->mTitle->canUseNoindex() && $this->mParserOutput->getIndexPolicy() ){ + # __INDEX__ and __NOINDEX__ magic words, if allowed. + $policy = array_merge( $policy, + array( 'index' => $this->mParserOutput->getIndexPolicy() ) ); } + + if( isset( $wgArticleRobotPolicies[$this->mTitle->getPrefixedText()] ) ){ + # (bug 14900) site config can override user-defined __INDEX__ or __NOINDEX__ + $policy = array_merge( $policy, + self::formatRobotPolicy( $wgArticleRobotPolicies[$this->mTitle->getPrefixedText()] ) ); + } + + return $policy; + + } + + /** + * Converts a String robot policy into an associative array, to allow + * merging of several policies using array_merge(). + * @param $policy Mixed, returns empty array on null/false/'', transparent + * to already-converted arrays, converts String. + * @return associative Array: 'index' => <indexpolicy>, 'follow' => <followpolicy> + */ + public static function formatRobotPolicy( $policy ){ + if( is_array( $policy ) ){ + return $policy; + } elseif( !$policy ){ + return array(); + } + + $policy = explode( ',', $policy ); + $policy = array_map( 'trim', $policy ); + + $arr = array(); + foreach( $policy as $var ){ + if( in_array( $var, array('index','noindex') ) ){ + $arr['index'] = $var; + } elseif( in_array( $var, array('follow','nofollow') ) ){ + $arr['follow'] = $var; + } + } + return $arr; } /** @@ -3848,9 +3929,9 @@ class Article { */ public function outputWikiText( $text, $cache = true, $parserOptions = false ) { global $wgOut; - - $parserOutput = $this->getOutputFromWikitext( $text, $cache, $parserOptions ); - $wgOut->addParserOutput( $parserOutput ); + + $this->mParserOutput = $this->getOutputFromWikitext( $text, $cache, $parserOptions ); + $wgOut->addParserOutput( $this->mParserOutput ); } /** @@ -3866,7 +3947,7 @@ class Article { } $time = -wfTime(); - $parserOutput = $wgParser->parse( $text, $this->mTitle, + $this->mParserOutput = $wgParser->parse( $text, $this->mTitle, $parserOptions, true, true, $this->getRevIdFetched() ); $time += wfTime(); @@ -3876,18 +3957,18 @@ class Article { $this->mTitle->getPrefixedDBkey())); } - if( $wgEnableParserCache && $cache && $this && $parserOutput->getCacheTime() != -1 ) { + if( $wgEnableParserCache && $cache && $this && $this->mParserOutput->getCacheTime() != -1 ) { $parserCache = ParserCache::singleton(); - $parserCache->save( $parserOutput, $this, $parserOptions ); + $parserCache->save( $this->mParserOutput, $this, $parserOptions ); } // Make sure file cache is not used on uncacheable content. // Output that has magic words in it can still use the parser cache // (if enabled), though it will generally expire sooner. - if( $parserOutput->getCacheTime() == -1 || $parserOutput->containsOldMagic() ) { + if( $this->mParserOutput->getCacheTime() == -1 || $this->mParserOutput->containsOldMagic() ) { $wgUseFileCache = false; } - $this->doCascadeProtectionUpdates( $parserOutput ); - return $parserOutput; + $this->doCascadeProtectionUpdates( $this->mParserOutput ); + return $this->mParserOutput; } /** diff --git a/includes/OutputPage.php b/includes/OutputPage.php index ea99d2d267..4bb2f95737 100644 --- a/includes/OutputPage.php +++ b/includes/OutputPage.php @@ -434,22 +434,14 @@ class OutputPage { * @return null */ public function setRobotPolicy( $policy ) { - $policy = explode( ',', $policy ); - $policy = array_map( 'trim', $policy ); + $policy = Article::formatRobotPolicy( $policy ); - # The default policy is follow, so if nothing is said explicitly, we - # do that. - if( in_array( 'nofollow', $policy ) ) { - $this->mFollowPolicy = 'nofollow'; - } else { - $this->mFollowPolicy = 'follow'; - } - - if( in_array( 'noindex', $policy ) ) { - $this->mIndexPolicy = 'noindex'; - } else { - $this->mIndexPolicy = 'index'; - } + if( isset( $policy['index'] ) ){ + $this->setIndexPolicy( $policy['index'] ); + } + if( isset( $policy['follow'] ) ){ + $this->setFollowPolicy( $policy['follow'] ); + } } /** @@ -721,17 +713,6 @@ class OutputPage { $this->mNewSectionLink = $parserOutput->getNewSection(); $this->mHideNewSectionLink = $parserOutput->getHideNewSection(); - if( is_null( $wgExemptFromUserRobotsControl ) ) { - $bannedNamespaces = $wgContentNamespaces; - } else { - $bannedNamespaces = $wgExemptFromUserRobotsControl; - } - if( !in_array( $this->getTitle()->getNamespace(), $bannedNamespaces ) ) { - # FIXME (bug 14900): This overrides $wgArticleRobotPolicies, and it - # shouldn't - $this->setIndexPolicy( $parserOutput->getIndexPolicy() ); - } - $this->mParseWarnings = $parserOutput->getWarnings(); if ( $parserOutput->getCacheTime() == -1 ) { $this->enableClientCache( false ); diff --git a/includes/Title.php b/includes/Title.php index d65e2aca72..5abc368a33 100644 --- a/includes/Title.php +++ b/includes/Title.php @@ -3717,4 +3717,21 @@ class Title { } return $this->mBacklinkCache; } + + /** + * Whether the magic words __INDEX__ and __NOINDEX__ function for + * this page. + * @return Bool + */ + public function canUseNoindex(){ + global $wgArticleRobotPolicies, $wgContentNamespaces, + $wgExemptFromUserRobotsControl; + + $bannedNamespaces = is_null( $wgExemptFromUserRobotsControl ) + ? $wgContentNamespaces + : $wgExemptFromUserRobotsControl; + + return !in_array( $this->mNamespace, $bannedNamespaces ); + + } }