User:Socoljam/DynamicArticleList (enhanced)

 
A proposal to move this page to MediaWiki.org was rejected.

Dynamic Article List is a great extension, but it had two little problems for me:

  • You could not parse Wikitext in the title field (for example, to add a link)
  • All the information was too wide or caused weird linebreaks

So I updated it a little. Now the opening tag accepts three optional parameters, showtimestamp, showeditor, and showviews. These all default to 1, but if set to 0, will hide the timestamp, the editor, or the view count, respectively, if they were generated by whatever type of list you have. I also let the $parser object take a crack at the title, and now you can add wikimarkup to that field.

Installation edit

See Dynamic_Article_List#Installation

This installs exactly like Dynamic Article List, except replace DynamicArticleList.php with the code below. You still need the other files listed on the main site:

  • Download these files and copy the content to appropriately named PHP files:
  • Save the three PHP files into your includes directory.
  • Copy and paste the code (below) into your favorite editor and save it as DynamicArticleList.php in your extensions directory.
  • Add the following line to your LocalSettings.php file, after require_once( "DefaultSettings.php" ); :
    require_once( "extensions/DynamicArticleList.php" );

Usage edit

Tag and its Attributes and Parameters edit

Tag Name DynamicArticleList
Attributes Attribute Description Default
showeditor (optional) If set to 0, hides the last editor in new/update/discussion lists 1
showtimestamp (optional) If set to 0, hides the timestamp in new/update/discussion lists 1
showviews (optional) If set to 0, hides the number of views in a hot list 1
Parameters Parameter Description Default
title (optional) Title of the output article list blank
type (optional) Type of dynamic article list (new/update/discussion/hot) new
count (optional) Output count of articles 5
categoryRoot (optional) Name of category where (including its children) all articles reside blank

Note:

  • If "categoryRoot" is set, Dynamic Article List will only retrieve articles in this category and its children. If not, all articles will be candidates.
  • The value of parameter "type" could be one of the following (default is new ):
    • new => Newly Posted Articles
    • update => Recently Updated Articles
    • discussion => Recent Discussions
    • hot => Most Popular Articles

Examples edit

So, for example, the following code would create a "new article" style list, with a link in the title to an article, and would show the timestamp but not the last editor:

<DynamicArticleList showeditor=0>
title=New Articles in [[History]]
type=new
categoryRoot=History
</DynamicArticleList>

This example would create a discussion list, but would hide the timestamp:

<DynamicArticleList showtimestamp=0>
title=Recent [[Project:Talk pages|Discussion]]
type=discussion
count=10
</DynamicArticleList>

This would create a "hot" list, but hide the view counts:

<DynamicArticleList showviews=0>
type=hot
</DynamicArticleList>

Compatibility edit

This version is not compatible with MediaWiki pre-1.5, since it assumes the tag attributes are passed as an array. (It would be very easy to add backwards compatibility.) And since DynamicArticleList requires PHP5 anyway, that should not pose much of a problem. (Just upgrade to 1.7.1.)

Code edit

So here's the code. Save the following as DynamicArticleList.php and put it in your extensions directory. (See #Installation)

<?php
/*
* Purpose: Dynamic Output of Article List (Main Page always not in list)
* Note: Currently support four types (new, hot, update, discussion).
* new => Newly Posted Articles
* update => Recently Updated Articles
* hot => Most Popular Articles
* discussion => Recently Updated Discussion
* @author: Zeng Ji (zengji@gmail.com)
*
* To install, add following to LocalSettings.php
* require_once ("extensions/DynamicArticleList.php");
*/

$wgExtensionFunctions[] = "wfDynamicArticleList";

function wfDynamicArticleList() {
	global $wgParser;
	$wgParser->setHook( "DynamicArticleList", "DynamicArticleList" );
}

// The callback function for converting the input text to HTML output
function DynamicArticleList( $input, $getOpts, &$parser ) {

	require_once ('CategoryUtil.php');
	$dbr =& wfGetDB( DB_SLAVE );
	
	// INVALIDATE CACHE
	global $wgTitle;
	$wgTitle->invalidateCache();
	
	// Default Values
	$listTitle = false;
	$listType = 'new';
	$listCount = 5;
	$categoryRoot = false;
	$options = array('showeditor' => 1,
		'showtimestamp' => 1,
		'showviews' => 1 );
	foreach ( $getOpts as $k => $v ) {
		$options[$k] = $v;
	}
	
	// ###### PARSE PARAMETERS ######
	$aParams = explode("\n", $input);
	foreach($aParams as $sParam) {
		$aParam = explode("=", $sParam);
		if( count( $aParam ) < 2 )
			continue;
		$sType = trim($aParam[0]);
		$sArg = trim($aParam[1]);
		switch ($sType) {
			case 'title':
				$listTitle = $sArg;
				break;
			case 'type':
				if ( in_array($sArg, array('new','hot','update', 'discussion')) )
					$listType = $sArg;
					break;
			case 'count':
				$listCount = IntVal( $sArg );
				break;
			case 'categoryRoot':
				$categoryRoot = $sArg;
				break;
		}
	}

	// ###### CHECKS ON PARAMETERS ######
	if ($listTitle!=false && strlen($listTitle)==0) {
		$listTitle=false;
	} else {
		$parseTitle = $parser->parse($listTitle, $parser->mTitle, $parser->mOptions, false, false);
		$listTitle = $parseTitle->getText();
	}

	// ###### BUILD SQL QUERY ######
	$sql = genSQL($listType, $listCount, $categoryRoot);

	// ###### PROCESS SQL QUERY ######
	global $wgUser;
	global $wgLang;
	global $wgContLang;

	$res = $dbr->query($sql);
	$sk =& $wgUser->getSkin();

	if ($dbr->numRows( $res ) != 0) {
		while( $row = $dbr->fetchObject ( $res ) ) {
			$title = Title::makeTitle( $row->namespace, $row->title);
			if ($listType == 'discussion')
				$sLink = $sk->makeKnownLinkObj($title, $wgContLang->convertHtml($title->getText()), '', '', 'Discussion: ');
			else
				$sLink = $sk->makeKnownLinkObj($title, $wgContLang->convertHtml($title->getText()));
		
			// Generate 'View Count' String (for 'hot')
			if ($listType == 'hot')
				$aViews[] = ' - ( ' . $row->count . ' views ) ';
			else
				$aViews = false;
			// Generate 'Time' String (for 'new', 'update', 'discussion')
			if ($listType != 'hot') {
				$aDates[] = ' - [ ' . $wgLang->timeanddate($row->timestamp, true) . ' ] ';
				$editorID = $row->user;
				if ($editorID == 0) {
					$editor = wfMsg('anonymous');
					$aEditors[] = ' (' . $editor . ')';
				} else {
					$editor = User::whoIs($editorID);
					$aEditors[] = ' ( ' . $sk->makeLink($wgContLang->getNsText(NS_USER) . ':' . $editor, htmlspecialchars($editor)) . ' )';
				}
			} else {
				$aDates = false;
				$aEditors = false;
			}
			$aArticles[] = $sLink;
		}
	}
	$dbr->freeResult( $res );

	// ###### GENERATE OUTPUT ######
	return OutputList($aArticles, $aEditors, $aDates, $aViews, $listTitle, $options);
}

function genSQL( $type, $count, $categoryRoot=false ) {

	$dbr =& wfGetDB( DB_SLAVE );
	$sPageTable = $dbr->tableName( 'page' );
	$sRevisionTable = $dbr->tableName( 'revision' );
	$sRecentChangesTable = $dbr->tableName( 'recentchanges' );
	$sCategoryLinksTable = $dbr->tableName( 'categorylinks' );
	$categoryUtil = new CategoryUtil();
	$sql = '';

	if ($type == 'hot') {
		if ($categoryRoot != false) {
			$cNameList = $categoryUtil->getCNameList($categoryRoot);
			$sql = "
			SELECT DISTINCT
			page_title as title,
			page_namespace AS namespace,
			page_counter as count
			FROM $sPageTable
			INNER JOIN $sCategoryLinksTable ON page_id=cl_from
			WHERE page_namespace=".NS_MAIN." AND page_is_redirect=0 AND page_id!=1 AND cl_to IN ".$cNameList."
			ORDER by count DESC
			LIMIT $count
			";
		} else {
			$sql = "
			SELECT DISTINCT
			page_title as title,
			page_namespace AS namespace,
			page_counter as count
			FROM $sPageTable
			WHERE page_namespace=".NS_MAIN." AND page_is_redirect=0 AND page_id!=1
			ORDER by count DESC
			LIMIT $count
			";
		}
	} elseif ($type == 'update') {
		// Step 1: Get revision list order by rev_id
		if ($categoryRoot != false) {
			$cNameList = $categoryUtil->getCNameList($categoryRoot);
			$sql = "
			SELECT
			page_id,
			MAX(rev_id) AS max_rev_id
			FROM $sPageTable
			INNER JOIN $sRevisionTable ON page_id=rev_page
			INNER JOIN $sCategoryLinksTable ON page_id=cl_from
			WHERE page_is_new!=1 AND page_namespace=0 AND page_is_redirect=0 AND page_id!=1 AND cl_to IN ".$cNameList."
			GROUP BY page_id
			ORDER by max_rev_id DESC
			LIMIT $count
			";
		} else {
			$sql = "
			SELECT
			page_id,
			MAX(rev_id) AS max_rev_id
			FROM $sPageTable
			INNER JOIN $sRevisionTable ON page_id=rev_page
			WHERE page_is_new!=1 AND page_namespace=0 AND page_is_redirect=0 AND page_id!=1
			GROUP BY page_id
			ORDER by max_rev_id DESC
			LIMIT $count
			";
		}
		// Step 2: According to revision list, generate SQL to retrieve article page information.
		$res = $dbr->query($sql);
		$inClause = '';
		if ($dbr->numRows( $res ) == 0) {
			$inClause = "-1";
		} else {
			while( $obj = $dbr->fetchObject( $res ) ) {
				if( isset( $obj->max_rev_id ) ) {
					$inClause .= $obj->max_rev_id . ',';
				}
			}
			$inClause = substr($inClause, 0, -1); //delete tailing ','
		}
		$dbr->freeResult( $res );
		$sql = "
		SELECT
		page_title AS title,
		page_namespace AS namespace,
		rev_user AS user,
		rev_timestamp AS timestamp
		FROM $sRevisionTable, $sPageTable
		WHERE rev_page=page_id AND rev_id IN (". $inClause . ")
		ORDER BY rev_id DESC";
	} elseif ($type == 'discussion') {
		// Step 1: Get revision list order by rev_id.
		if ($categoryRoot != false) {
		$cNameList = $categoryUtil->getCNameList($categoryRoot);
		$sql = "
		SELECT
		p1.page_id,
		MAX(rev_id) AS max_rev_id
		FROM $sPageTable AS p1
		INNER JOIN $sPageTable AS p2 ON p1.page_title=p2.page_title
		INNER JOIN $sRevisionTable ON p1.page_id=rev_page
		INNER JOIN $sCategoryLinksTable ON p2.page_id=cl_from
		WHERE p1.page_is_redirect=0 AND p1.page_namespace=1 AND p2.page_namespace=0 AND cl_to IN ".$cNameList."
		GROUP BY rev_page
		ORDER by max_rev_id DESC
		LIMIT $count
		";
		} else {
		$sql = "
		SELECT
		p1.page_id,
		MAX(rev_id) AS max_rev_id
		FROM $sPageTable AS p1
		INNER JOIN $sRevisionTable ON p1.page_id=rev_page
		WHERE p1.page_is_redirect=0 AND p1.page_namespace=1
		GROUP BY rev_page
		ORDER by max_rev_id DESC
		LIMIT $count
		";
		}
		// Step 2: According to revision list, generate SQL to retrieve discussion page information.
		$res = $dbr->query($sql);
		$inClause = '';
		if ($dbr->numRows( $res ) == 0) {
			$inClause = "-1";
		} else {
			while( $obj = $dbr->fetchObject( $res ) ) {
				if( isset( $obj->max_rev_id ) ) {
					$inClause .= $obj->max_rev_id . ',';
				}
			}
			$inClause = substr($inClause, 0, -1); //delete tailing ','
		}
		$dbr->freeResult( $res );
		$sql = "
		SELECT
		page_title AS title,
		page_namespace AS namespace,
		rev_user AS user,
		rev_timestamp AS timestamp
		FROM $sRevisionTable, $sPageTable
		WHERE rev_page=page_id AND rev_id IN (". $inClause . ")
		ORDER BY rev_id DESC";
		} else { // default type is 'new'
		if ($categoryRoot != false) {
			$cNameList = $categoryUtil->getCNameList($categoryRoot);
			$sql = "
			SELECT DISTINCT
			page_title AS title,
			page_namespace AS namespace,
			rc_user AS user,
			rc_timestamp AS timestamp
			FROM $sPageTable
			INNER JOIN $sRecentChangesTable ON page_id=rc_cur_id
			INNER JOIN $sCategoryLinksTable ON page_id=cl_from
			WHERE rc_new=1 AND rc_namespace=0 AND page_is_redirect=0 AND page_id!=1 AND cl_to IN ".$cNameList."
			ORDER by rc_id DESC
			LIMIT $count
			";
		} else {
			$sql = "
			SELECT DISTINCT
			page_title AS title,
			page_namespace AS namespace,
			rc_user AS user,
			rc_timestamp AS timestamp
			FROM $sPageTable
			INNER JOIN $sRecentChangesTable ON page_id=rc_cur_id
			WHERE rc_new=1 AND rc_namespace=0 AND page_is_redirect=0 AND page_id!=1
			ORDER by rc_id DESC
			LIMIT $count
			";
		}
	}
	return $sql;
}

function OutputList ( $aArticles, $aEditors, $aDates, $aViews, $listTitle, $options ) {
	if ($listTitle != false) {
		$r .= " <h3>" . $listTitle . "</h3>\n";
		$r .= " <hr/>\n";
	}

	$sStartList = '<ul>';
	$sEndList = '</ul>';
	$sStartItem = '<li>';
	$sEndItem = '</li>';

	$r .= $sStartList . "\n";

	for ($i=0; $i<count($aArticles); $i++) {
		$editorString = "";
		$dateString = "";
		$viewString = "";

		if (($options['showeditor'] != 0)&&($aEditors != false))
			$editorString = "<font size=-2>" . $aEditors[$i] . "</font>";

		if (($options['showtimestamp'] != 0)&&($aDates != false))
			$dateString = "<font size=-2>" . $aDates[$i] . "</font>";

		if (($options['showviews'] !=0)&&($aViews != false))
			$viewString = "<font size=-2>" . $aViews[$i] . "</font>";

		$r .= $sStartItem . $aArticles[$i] . $editorString . $dateString . $viewString . $sEndItem . "\n";
	}

	$r .= $sEndList . "\n";

	return $r;
}
?>