MediaWiki/extensions/Contributors

Overview
This is a modification of an extension originally posted on mediawiki.org. If anyone wants to integrate these changes into the official release of that extension, please feel free to do so.

It adds the following features:
 * link to user's page, if available (with standard edit link if page doesn't exist)
 * allows display of user's real name, if available (configurable option)
 * more flexible formatting via LocalSettings options

Installation instructions are unchanged from those in the official release, except for the following new LocalSettings options:
 * $wgContributorsIncludeBefore: string to include before each contributor listing
 * $wgContributorsIncludeBetween: string to include between contributors (not before first or after last)
 * $wgContributorsIncludeBeforeOthers: string to include before the optional "and n others" listing
 * (text for after the "others" listing is set at Mediawiki:contributors-others)
 * $wgContributorsShowAnon: if FALSE, do not show anonymous (IP address) contributors
 * $wgContributorsShowOthers: if FALSE, do not show "and n others" line
 * $wgContributorsUseRealName: if TRUE, use real name if available (as entered by user in their "my preferences" page)

Code
The Contributors.i18n.php file is unaltered; use the one linked from mediawiki.org.

Contributors.php
, Nick (Woozle) Staddon */ /* 2007-11-13 (Woozle) Better formatting for included contrib list; added some config options: $wgContributorsIncludeBefore, $wgContributorsIncludeBetween, $wgContributorsIncludeBeforeOthers, $wgContributorsShowAnon, $wgContributorsShowOthers, $wgContributorsUseRealName 2007-11-15 (Woozle) Added ability to hide or alias certain usernames if( defined( 'MEDIAWIKI' ) ) { $wgExtensionFunctions[] = 'efContributors'; $wgExtensionCredits['specialpage'][] = array(		'name' => 'Contributors',		'author' => 'Rob Church, Nick (Woozle) Staddon',		'description' => 'Summarises the main contributors to an article',		'url' => 'http://htyp.org/MediaWiki_Contributors_extension',		'version' => '2007-11-15.wzl',	); $wgAutoloadClasses['SpecialContributors'] = dirname( __FILE__ ). '/Contributors.page.php'; $wgSpecialPages['Contributors'] = 'SpecialContributors'; /**	 * Intelligent cut-off limit; see below */	$wgContributorsLimit = 10; /**	 * After $wgContributorsLimit is reached, contributors with less than this * number of edits to a page won't be listed in normal or inclusion lists */	$wgContributorsThreshold = 2; /**	 * Some formatting specs for the included version of the contrib list: */	$wgContributorsIncludeBefore = '';	// include this string before each contributor //	$wgContributorsIncludeBetween = ' ';	// include this string after each contributor $wgContributorsIncludeBetween = ', ';	// include this string after each contributor $wgContributorsIncludeBeforeOthers = ' ... ';	// include this string before "others" // text for *after* "others" is set at Mediawiki:contributors-others $wgContributorsShowAnon = false;	// if FALSE, do not show anonymous contributors $wgContributorsShowOthers = false;	// if FALSE, do not show "and n others" line $wgContributorsUseRealName = true;	// if TRUE, use real name if available /**	 * Override to prevent certain users (e.g. internal authors) from being listed */ //	$wgUsernameAliases['username'] = 'alias';	// add as many different aliases as needed /* Where multiple usernames map to one alias, each one is still listed individually -- but grouping should be easy enough to add if anyone actually wants it. Empty string suppresses listing of that name, including the separation string. /**	 * Extension initialisation function */	function efContributors { global $wgMessageCache, $wgHooks; require_once( dirname( __FILE__ ) . '/Contributors.i18n.php' ); foreach( efContributorsMessages as $lang => $messages ) $wgMessageCache->addMessages( $messages, $lang ); $wgHooks['ArticleDeleteComplete'][] = 'efContributorsInvalidateCache'; $wgHooks['ArticleSaveComplete'][] = 'efContributorsInvalidateCache'; # Good god, this is ludicrous! $wgHooks['SkinTemplateBuildNavUrlsNav_urlsAfterPermalink'][] = 'efContributorsNavigation'; $wgHooks['MonoBookTemplateToolboxEnd'][] = 'efContributorsToolbox'; }	/**	 * Invalidate the cache we saved for a given title *	 * @param $article Article object that changed */	function efContributorsInvalidateCache( &$article ) { global $wgMemc; $wgMemc->delete( wfMemcKey( 'contributors', $article->getId ) ); return true; }	/**	 * Prepare the toolbox link */	function efContributorsNavigation( &$skintemplate, &$nav_urls, &$oldid, &$revid ) { if ( $skintemplate->mTitle->getNamespace === NS_MAIN && $revid !== 0 ) $nav_urls['contributors'] = array(				'text' => wfMsg( 'contributors-toolbox' ),				'href' => $skintemplate->makeSpecialUrl( 'Contributors', "target=". wfUrlEncode( "{$skintemplate->thispage}" ) )			); return true; }	/**	 * Output the toolbox link */	function efContributorsToolbox( &$monobook ) { if ( isset( $monobook->data['nav_urls']['contributors'] ) ) if ( $monobook->data['nav_urls']['contributors']['href'] == '' ) { ?>msg( 'contributors-toolbox' ); ?>data['nav_urls']['contributors']['href'] ) ?>">msg( 'contributors-toolbox' ); ?>
 * 2007-11-14 Oops, didn't mean to hog all the credit! Rob Church did most of the work. This version corrects the "author" data, and gives a more friendly URL.

Contributors.page.php
 */ class SpecialContributors extends IncludableSpecialPage { protected $target; public function __construct { parent::__construct( 'Contributors' ); }	public function execute( $target ) { wfProfileIn( __METHOD__ ); global $wgOut, $wgRequest; $this->setHeaders; $this->determineTarget( $wgRequest, $target ); # What are we doing? Different execution paths for inclusion, # direct access and raw access if( $this->including ) { $this->showInclude; } elseif( $wgRequest->getText( 'action' ) == 'raw' ) { $this->showRaw; } else { $wgOut->addHtml( $this->makeForm ); if( is_object( $this->target ) ) $this->showNormal; }		wfProfileOut( __METHOD__ ); }	private function showInclude { global $wgContributorsIncludeBefore, $wgContributorsIncludeBetween, $wgContributorsIncludeBeforeOthers, $wgContributorsShowAnon, $wgContributorsShowOthers, $wgContributorsUseRealName, $wgUsernameAliases; wfProfileIn( __METHOD__ ); global $wgOut; if( is_object( $this->target ) ) { if( $this->target->exists ) { $names = array; list( $contributors, $others ) = $this->getMainContributors; foreach( $contributors as $username => $info ) { $idUser = $info[0]; if ($idUser) { // logged-in user $strUserSeek = strtolower($username); /**/						if (array_key_exists($strUserSeek,$wgUsernameAliases)) { $strUserName = $wgUsernameAliases[$strUserSeek]; $strUser = $wgContributorsIncludeBefore.$strUserName; } else { /**/ $objUser = User::newFromName($username); $strUserName = $username; if ($wgContributorsUseRealName) { $strUserFull = $objUser->getRealName; if ($strUserFull) { $strUserName = $strUserFull; }							}							$objUserTitle = $objUser->getUserPage; if ($objUserTitle->exists) { $strUserURL = $objUserTitle->getLocalURL; $strClass = ''; } else { $strUserURL = $objUserTitle->getEditURL; $strClass = ' class="new"'; }							$strUser = $wgContributorsIncludeBefore.''.$strUserName.''; /**/						}	/**/					} else { if ($wgContributorsShowAnon) { $strUser = $wgContributorsIncludeBefore.$username; } else { $strUser = ''; }					}					if ($strUser != '') { $names[] = $strUser; }				}				$output = implode( $wgContributorsIncludeBetween, $names ); if( ($others > 0) && $wgContributorsShowOthers) $output .= $wgContributorsIncludeBeforeOthers. wfMsgForContent( 'contributors-others', $others ); //				$wgOut->addHtml( htmlspecialchars( $output ) ); $wgOut->addHtml( $output ); } else { $wgOut->addHtml( ' ' . htmlspecialchars( wfMsgForContent( 'contributors-nosuchpage', $this->target->getPrefixedText ) ) . ' ' ); }		} else { $wgOut->addHtml( ' ' . htmlspecialchars( wfMsgForContent( 'contributors-badtitle' ) ) . ' ' ); }		wfProfileOut( __METHOD__ ); }	/**	 * Output a machine-readable form of the raw information */	private function showRaw { wfProfileIn( __METHOD__ ); global $wgOut; $wgOut->disable; if( is_object( $this->target ) && $this->target->exists ) { foreach( $this->getContributors as $username => $info ) { list( $userid, $count ) = $info; header( 'Content-type: text/plain; charset=utf-8', true ); echo( htmlspecialchars( "{$username} = {$count}\n" ) ); }		} else { header( 'Status: 404 Not Found', true, 404 ); echo( 'The requested target page does not exist.' ); }		wfProfileOut( __METHOD__ ); }	private function showNormal { wfProfileIn( __METHOD__ ); global $wgOut, $wgUser, $wgLang; if( $this->target->exists ) { $total = 0; $skin =& $wgUser->getSkin; $link = $skin->makeKnownLinkObj( $this->target ); $wgOut->addHtml( ' ' . wfMsgHtml( 'contributors-subtitle', $link ) . ' ' ); list( $contributors, $others ) = $this->getMainContributors; $wgOut->addHtml( '<ul>' ); foreach( $contributors as $username => $info ) { list( $id, $count ) = $info; $line = $skin->userLink( $id, $username ). $skin->userToolLinks( $id, $username ); $line .= ' ['. $wgLang->formatNum( $count ). ']';				$wgOut->addHtml( '' . $line . '</li>' ); }			$wgOut->addHtml( '</ul>' ); if( $others > 0 ) { $others = $wgLang->formatNum( $others ); $wgOut->addWikiText( wfMsgNoTrans( 'contributors-others-long', $others ) ); }		} else { $wgOut->addHtml( ' ' . htmlspecialchars( wfMsg( 'contributors-nosuchpage', $this->target->getPrefixedText ) ) . ' ' ); }		wfProfileOut( __METHOD__ ); }	/**	 * Retrieve all contributors for the target page worth listing, at least * according to the limit and threshold defined in the configuration *	 * Also returns the number of contributors who weren't considered * "important enough" *	 * @return array */	protected function getMainContributors { wfProfileIn( __METHOD__ ); global $wgContributorsLimit, $wgContributorsThreshold; $total = 0; $ret = array; $all = $this->getContributors; foreach( $all as $username => $info ) { list( $id, $count ) = $info; if( $total >= $wgContributorsLimit && $count < $wgContributorsThreshold ) break; $ret[$username] = array( $id, $count ); $total++; }		$others = count( $all ) - count( $ret ); wfProfileOut( __METHOD__ ); return array( $ret, $others ); }	/**	 * Retrieve the contributors for the target page with their contribution numbers *	 * @return array */	protected function getContributors { wfProfileIn( __METHOD__ ); global $wgMemc; $k = wfMemcKey( 'contributors', $this->target->getArticleId ); $contributors = $wgMemc->get( $k ); if( !$contributors ) { $contributors = array; $dbr = wfGetDB( DB_SLAVE ); $res = $dbr->select(				'revision',				array( 'COUNT(*) AS count', 'rev_user', 'rev_user_text', ),				$this->getConditions,				__METHOD__,				array( 'GROUP BY' => 'rev_user_text', 'ORDER BY' => 'count DESC', )			);			if( $res && $dbr->numRows( $res ) > 0 ) { while( $row = $dbr->fetchObject( $res ) ) $contributors[ $row->rev_user_text ] = array( $row->rev_user, $row->count ); }			$wgMemc->set( $k, $contributors, 84600 ); }		wfProfileOut( __METHOD__ ); return $contributors; }	/**	 * Get conditions for the main query *	 * @return array */	protected function getConditions { global $wgVersion; $conds['rev_page'] = $this->target->getArticleId; if( version_compare( $wgVersion, '1.11alpha', '>=' ) ) $conds[] = 'rev_deleted & '. Revision::DELETED_USER. ' = 0';		return $conds; }	/**	 * Given the web request, and a possible override from a subpage, work * out which we want to use *	 * @param $request WebRequest we're serving * @param $override Possible subpage override * @return string */	private function determineTarget( &$request, $override ) { $target = $request->getText( 'target', $override ); $this->target = Title::newFromUrl( $target ); }	/**	 * Make a nice little form so the user can enter a title and so forth * in normal output mode *	 * @return string */	private function makeForm { global $wgScript; $self = parent::getTitleFor( 'Contributors' ); $target = is_object( $this->target ) ? $this->target->getPrefixedText : ''; $form = '<form method="get" action="' . htmlspecialchars( $wgScript ) . '">'; $form .= Xml::hidden( 'title', $self->getPrefixedText ); $form .= ' '. wfMsgHtml( 'contributors-legend' ). ' ';		$form .= ' '; $form .= ' '; $form .= ' '; return $form; } } ?>