Extension talk:CategoryCloud

From mediawiki.org
Latest comment: 11 years ago by WhiteTigerItaly in topic What is the right version?

Exclude categories and maximum limit of categories shown[edit]

I used the code provided at the bottom of this page and modified it so now we have the exclude parameter and the maximum limit of categories shown works.

<?php
/**
 * Parser hook extension adds a <category-cloud> tag to wiki markup. The
 * following attributes are used:
 *    category = The category, minus the "Category:". if category is "" then All.
 *    order = "name" or "count"
 *    minsize = The minimum size, as percentage. Defaults to 80.
 *    maxsize = The maximum size, as a percentage. Defaults to 125.
 *    maxitems = Limiting tag cloud size. Defaults to 80
 *    class = The CSS class to assign to the outer div, defaults
 *            to "category-cloud"
 *	  exclude = The list of categories to be excluded from the tag cloud. If not present, then none.
 * 
 * There is also a parser function that uses {{#category-cloud:CategoryName}}
 * with optional parameters being includes as "|param=value".
 *
 * @addtogroup Extensions
 * @author Dylan R. E. Moonfire <contact@mfgames.com>
 * @copyright 2007 Dylan R. E. Moonfire
 * @licence GNU General Public Licence 2.0
 * Last Modified: Isaac Contreras Sandoval
 * 			August 25th 2011
 * 			Changed SQL query to include all categories - not only those which have an article created
 */
 
// Make sure we are being properly
if( !defined( 'MEDIAWIKI' ) ) {
    echo( "This file is an extension to the MediaWiki software "
                . "and cannot be used standalone.\n" );
    die( -1 );
}
 
// Hook up into MediaWiki
$wgExtensionFunctions[] = 'categoryCloud';
$wgHooks['LanguageGetMagic'][]   = 'categoryCloudMagic';
$wgExtensionCredits['parserhook'][] = array(
    'name' => 'Category Cloud',
    'author' => 'Dylan R. E. Moonfire',
    'description' => 'Create a tag cloud using categories.',
    'url' => 'http://www.mediawiki.org/wiki/Extension:CategoryCloud',
    'version' => '0.4.0'
);
 
function categoryCloud()
{
        global $wgParser, $wgMessageCache;
 
        // Set the hooks
        $wgParser->setHook('category-cloud', 'categoryCloudRender');
        $wgParser->setFunctionHook('category-cloud', 'categoryCloudFunction');
 
        // Set our messages
        $wgMessageCache->addMessages( array(
                    'categorycloud_missingcategory'
                        => 'CategoryCloud: Cannot find category attribute',
                    'categorycloud_emptycategory'
                        => 'CategoryCloud: Category is empty: ',
                    'categorycloud_cannotparse'
                        => 'CategoryCloud: Cannot parse parameter: ',
                ));
}
 
// This manipulates the results of the CategoryCloud extension
// into the same function as the <category-cloud> tag.
function categoryCloudFunction($parser)
{
        // Get the arguments
        $fargs = func_get_args();
        $input = array_shift($fargs);
 
        // The first category is required
        $category = array_shift($fargs);
        $params = array();
        $params["category"] = $category;
        $params["donotparse"] = 1;
 
        // Split the rest of the arguments
        foreach ($fargs as $parm)
        {
                // Split it into its components
                $split = split("=", $parm);
 
                if (!$split[1])
                {
                        return htmlspecialchars(wfMsg(
                                'categorycloud_cannotparse')
                                . $parm);
                }
 
                // Save it
                $params[$split[0]] = $split[1];
        }
 
        // Return the cloud
        return categoryCloudRender($input, $params, $parser);
}
 
// Sets up the magic for the parser functions
function categoryCloudMagic(&$magicWords, $langCode)
{
        $magicWords['category-cloud'] = array(0, 'category-cloud');
        return true;
}
 
// The actual processing
function categoryCloudRender($input, $args, &$parser)
{
        // Imports
        global $wgOut;
 
        // Profiling
        wfProfileIn('CategoryCloud::Render');
 
        // Disable the cache, otherwise the cloud will only update
        // itself when a user edits and saves the page.
        $parser->disableCache();
 
        // Get the database handler and specific controls
        $dbr =& wfGetDB( DB_SLAVE );
        $pageTable = $dbr->tableName('page');
        $categoryLinksTable = $dbr->tableName('categorylinks');
 
        // Normalize the order
        $order = "count";
        if (array_key_exists("order", $args)) $order = $args["order"];
 
        if ($order != "count")
                $order = "name";
        else // we want reverse
                $order = "count DESC";
 
        // Get the list of the subcategories and the number of children
        if (!array_key_exists("category", $args))
        {
                return htmlspecialchars(wfMsg(
                        'categorycloud_missingcategory'));
        }
 
        $categoryName = $args["category"];
 
        $maxitems=80;
        if(array_key_exists("maxitems",$args))
        	$maxitems = $args["maxitems"];
 
        // Build up an SQL of everything
        
        $sql = "SELECT DISTINCT $categoryLinksTable.cl_to as name, count(*) as count "
        		. "FROM $pageTable "
        		. "JOIN $categoryLinksTable ON $categoryLinksTable.cl_from = $pageTable.page_id "
        		. "GROUP BY name "
                . "ORDER BY $order "
                . "LIMIT $maxitems OFFSET 0";
 		
        $res = $dbr->query($sql);
 
        if ($dbr->numRows( $res ) == 0)
        {
                // Can't find category
                return htmlspecialchars(wfMsg(
                        'categorycloud_emptycategory')
                        . $categoryName);
        }
        // Build up an array and keep track of mins and maxes
        $minCount = -1;
        $maxCount = -1;
        $countAll = 0;
        $total = 0;
        $categories = array();
        $names = array();
        if (array_key_exists("exclude", $args))
	        $excluded_categories = explode(",",$args["exclude"]);
	        
        while ($row = $dbr->fetchObject($res))
        {
	        // Pull out the fields
	        $name = $row->name;
	        $count = $row->count;
	        
	        if (array_key_exists("exclude", $args)){
		        if(!in_array($name,$excluded_categories)){
		        	if(!in_array($name,$names)){
				        // Add it to the array and keep track of min/max
				        $categories[$name] = $count;
				        $names[] = $name;
				        $countAll++;
				        $total += $count;
				
				        if ($minCount < 0 || $minCount > $count)
				        	$minCount = $count;
				
				        if ($maxCount < 0 || $maxCount < $count)
				        	$maxCount = $count;
		        	}
		        }
	        }
	        else{
	          	$categories[$name] = $count;
		        $names[] = $name;
		        $countAll++;
		        $total += $count;
		
		        if ($minCount < 0 || $minCount > $count)
		        	$minCount = $count;
		
		        if ($maxCount < 0 || $maxCount < $count)
		        	$maxCount = $count;
	         
	        }
        }
 
        // Figure out the averages and font sizes
        $minSize = 80;
        $maxSize = 125;
 
        if (array_key_exists("minsize", $args)) $minSize = $args["minsize"];
        if (array_key_exists("maxsize", $args)) $maxSize = $args["maxsize"];
 
        $countDelta = $maxCount - $minCount;
        $sizeDelta = $maxSize - $minSize;
        $average = $total / $countAll;
 
        // Create the tag cloud div
        $class = "category-cloud";
 
        if (array_key_exists("class", $args)) $class = $args["class"];
 
        $text  = "<div class='$class'";
 
        if (array_key_exists("style", $args))
                $text .= " style='" . $args["style"]. "'";
 
        $text .= ">";
 
        // Go through the categories by name
        foreach ($names as $cat)
        {
                // Wrap the link in a size
                if ($countDelta == 0)
                        $size = 100;
                else
                        $size = (($categories[$cat] - $minCount)
                                * $sizeDelta / $countDelta) + $minSize;
 
                // Get the link
                $cat = str_replace("_", " ", $cat);
                $text .= " <span style='font-size: $size%;'>"
                        . "[[:Category:$cat|$cat]]</span>";
        }
 
        // Finish up
        $text .= "</div>";
 
        // If donotparse is set to a value, then we don't want
        // to parse it into wiki text.
        if (array_key_exists("donotparse", $args))
        {
                wfProfileOut('CategoryCloud::RenderNoParse');
                return $text;
        }
 
        // Parse the results into wiki text
        $output = $parser->parse($text,
                        $parser->mTitle, $parser->mOptions,
                        true, false);
 
        // Finish up and return the results
        wfProfileOut('CategoryCloud::Render');
        return $output->getText();
}
<category-cloud category="" minsize="80" maxsize="200" order="count" maxitems="15" exclude="Templates"></category-cloud> 

--Fladei 18:00, 25 August 2011 (UTC)Reply

Using it on Mediawiki 1.6.10[edit]

I'm using MediWiki version 1.6.10, and just changing the query, it started to work. I've used the query taken from SpecialCategories.php. It's:

	$NScat = NS_CATEGORY;	
	$categorylinks = $dbr->tableName( 'categorylinks' );
	$sql= "SELECT cl_to as name,			
		COUNT(*) as count
		FROM $categorylinks
		GROUP BY cl_to";

You will have to check where to put it, but I tested and it works. Thanks! --Fernando Negrotto

Using it on Mediawiki 1.9.3[edit]

I'm using a german MediaWiki Version 1.9.3. The Extension doesn't work, every Category seems to be empty. I changed the SQL-Statement to:

$sql = 'SELECT cl.cl_to as name, count(*) as count '
       . ' FROM categorylinks cl'
       . ' LEFT JOIN page AS p on p.page_title = cl.cl_to'
       . ' WHERE cl.cl_to LIKE ' . $dbr->addQuotes($categoryName)
       . ' GROUP BY cl.cl_to'
       . ' ORDER BY ' . $order;

Now it works. Have fun.

Proposed Extension[edit]

Well... I added a tag in mine so it displays the article/subcategory count for each category. Just add this after line 221:

                if ($args["showcount"]) {
                  $catCount = $categories[str_replace(" ", "_", $cat)];
                  $text .= "<span style='font-size: 8px;vertical-align:sub;'>$catCount</span>";
                }

Then it's as easy as {{#category-cloud:CategoryOfTopics|minsize=80|maxsize=125|showcount=1}}

Of course I could've saved the category name var before the "_"s where changed to " ", but I wanted to keep your code unscathed. --Phenome 15:35, 2 June 2007 (UTC)Reply

I'll add that into the next version, seems like a very useful feature. --Dylan Moonfire 16:09, 5 October 2007 (UTC)Reply

Recursivity[edit]

"the extension does not recursively go through the sub-categories for additional categories." - Pity... it would be great if it did that. :) -- Schneelocke 20:09, 21 June 2007 (UTC)Reply

I'll add "recurse=X" where X is the number of levels to recurse. While I don't use it, it seems like a useful one to have. --Dylan Moonfire 16:10, 5 October 2007 (UTC)Reply

Tag for every article in the given category[edit]

It generates a tag for every sub-category, but not article, in the given category. >> It should ;) And besides the option as tag cloud maybe like the regular list but different font sizes. --Sub

The main reason I didn't do that is because it wouldn't really create different font sizes. Since there would be one and only one of an article inside a category, it would always have a count of 1. In effect, it would just be a link of everything inside the category, with no font sizes. --Dylan Moonfire 16:21, 5 October 2007 (UTC)Reply

Installation/Use[edit]

Could someone perhaps add a section of Installation and Use? I'm assuming you save it as TagCloud.php in the extension directory and then in LocalSettings.php you use

require_once("$IP/extensions/TagCloud.php");

Can anyone confirm? I would even make the section myself if this is correct.

--Dopple 11:00, 22 August 2007 (UTC)Reply

Yes, that is how you add it. I'll block in a section the next time I do an update (hopefully in a week or three). --Dylan Moonfire 16:11, 5 October 2007 (UTC)Reply

1.10.1 Problems[edit]

Notice: Undefined index: class in MYWIKIPATH/extensions/CategoryCloud/CategoryCloud.php on line 199

Notice: Undefined index: style in MYWIKIPATH/extensions/CategoryCloud/CategoryCloud.php on line 203

The above error occurs consistently with CategoryCloud enabled on my mediawiki 1.10.1 website. If anyone knows how to fix this or has had this problem before any assistance would be appreciated. Otherwise I'm going to take a look at the wikitagcloud extension and see if it can do (or can be modified to do) the same thing as the categorycloud extension. --Diploid 20:27, 24 August 2007 (UTC)Reply

Are you using a recent version of the CategoryCloud? I thought I fixed that with one of the later versions, by checking the key existence first. Which version of PHP are you using? You should be able to bypass it by just putting in class="" and style="" depending on your use. --Dylan Moonfire 16:19, 5 October 2007 (UTC)Reply


I've the exact same problem with my Wiki :/

[Wed Dec  3 13:08:06 2008] [error] PHP Notice:  Undefined index:  class in MYWIKIPATH/extensions/CategoryCloud/category-cloud.php on line 199
[Wed Dec  3 13:08:06 2008] [error] PHP Notice:  Undefined index:  style in MYWIKIPATH/extensions/CategoryCloud/category-cloud.php on line 203

My installed software: MediaWiki v. 1.13.1, PHP v. 5.1.6 (apache), MySQL v. 4.1.22-log. --Danny373 12:05, 3 December 2008 (UTC)Reply

Limiting tag cloud size[edit]

A couple of other useful options would be:

  1. An attribute to limit the maximum number of tags in the cloud, such as maxitems="50" to show only the top 50 categories. This would be useful to prevent tag clouds getting out of control, especially if used in conjunction with the recursion option discussed above.
  2. Some way of excluding categories that contain less than a certain number of articles. This would default to 1 to replicate the current behaviour of omitting empty categories, but could be set to 0 to include all categories, or some higher number to omit categories containing just a few entries. Again, this would be useful in controlling the maximum size of a tag cloud, but without putting an upper limit on the number of tags that can be displayed.

Other than that, it's a great extension. I've put it to work on the main page of PhilosophyWiki.

-- Keith Wilson 23:13, 17 December 2008 (UTC)Reply

Version of My Fix[edit]

<?php
/**
 * Parser hook extension adds a <category-cloud> tag to wiki markup. The
 * following attributes are used:
 *    category = The category, minus the "Category:". if category is "" then All.
 *    order = "name" or "count"
 *    minsize = The minimum size, as percentage. Defaults to 80.
 *    maxsize = The maximum size, as a percentage. Defaults to 125.
 *    maxitems = Limiting tag cloud size. Defaults to 80. if order != "name".
 *    class = The CSS class to assign to the outer div, defaults
 *            to "category-cloud"
 *
 * There is also a parser function that uses {{#category-cloud:CategoryName}}
 * with optional parameters being includes as "|param=value".
 *
 * @addtogroup Extensions
 * @author Dylan R. E. Moonfire <contact@mfgames.com>
 * @copyright ďż˝ 2007 Dylan R. E. Moonfire
 * @licence GNU General Public Licence 2.0
 */

// Make sure we are being properly
if( !defined( 'MEDIAWIKI' ) ) {
    echo( "This file is an extension to the MediaWiki software "
		. "and cannot be used standalone.\n" );
    die( -1 );
}

// Hook up into MediaWiki
$wgExtensionFunctions[] = 'categoryCloud';
$wgHooks['LanguageGetMagic'][]	= 'categoryCloudMagic';
$wgExtensionCredits['parserhook'][] = array(
    'name' => 'Category Cloud',
    'author' => 'Dylan R. E. Moonfire',
    'description' => 'Create a tag cloud using categories.',
    'url' => 'http://www.mediawiki.org/wiki/Extension:CategoryCloud',
    'version' => '0.4.0'
);

function categoryCloud()
{
        global $wgParser, $wgMessageCache;

	// Set the hooks
        $wgParser->setHook('category-cloud', 'categoryCloudRender');
	$wgParser->setFunctionHook('category-cloud', 'categoryCloudFunction');

	// Set our messages
	$wgMessageCache->addMessages( array(
                    'categorycloud_missingcategory'
			=> 'CategoryCloud: Cannot find category attribute',
                    'categorycloud_emptycategory'
			=> 'CategoryCloud: Category is empty: ',
                    'categorycloud_cannotparse'
			=> 'CategoryCloud: Cannot parse parameter: ',
		));
}

// This manipulates the results of the CategoryCloud extension
// into the same function as the <category-cloud> tag.
function categoryCloudFunction($parser)
{
	// Get the arguments
        $fargs = func_get_args();
        $input = array_shift($fargs);

	// The first category is required
	$category = array_shift($fargs);
	$params = array();
	$params["category"] = $category;
	$params["donotparse"] = 1;

	// Split the rest of the arguments
	foreach ($fargs as $parm)
	{
		// Split it into its components
		$split = split("=", $parm);

		if (!$split[1])
		{
			return htmlspecialchars(wfMsg(
				'categorycloud_cannotparse')
				. $parm);
		}

		// Save it
		$params[$split[0]] = $split[1];
	}

	// Return the cloud
	return categoryCloudRender($input, $params, $parser);
}

// Sets up the magic for the parser functions
function categoryCloudMagic(&$magicWords, $langCode)
{
	$magicWords['category-cloud'] = array(0, 'category-cloud');
	return true;
}

// The actual processing
function categoryCloudRender($input, $args, &$parser)
{
	// Imports
	global $wgOut;

	// Profiling
        wfProfileIn('CategoryCloud::Render');

	// Disable the cache, otherwise the cloud will only update
	// itself when a user edits and saves the page.
	$parser->disableCache();

	// Get the database handler and specific controls
        $dbr =& wfGetDB( DB_SLAVE );
        $pageTable = $dbr->tableName('page');
    	$categoryLinksTable = $dbr->tableName('categorylinks');

	// Normalize the order
	$order = "name";
	if (array_key_exists("order", $args)) $order = $args["order"];

	if ($order != "count")
		$order = "name";
	else // we want reverse
		$order = "count desc";

	// Get the list of the subcategories and the number of children
	if (!array_key_exists("category", $args))
	{
		return htmlspecialchars(wfMsg(
			'categorycloud_missingcategory'));
	}

	$categoryName = $args["category"];

	$maxitems = 80;
	if (array_key_exists("maxitems", $args)) $outsize = $args["maxitems"];

	// Build up an SQL of everything
	$categoryNamespace = 14;

		$sql = "SELECT p1.page_title as name, count(*) as count "
			. "FROM $categoryLinksTable cl, $categoryLinksTable cl2, "
			. "  $pageTable p1, $pageTable p2 "
			. "WHERE";

	if ($categoryName)
	{
		$sql .=   " cl.cl_to = " . $dbr->addQuotes($categoryName) 
			. " AND ";
	}
		$sql .=	  "     cl.cl_from  = p1.page_id "
			. " AND cl2.cl_to   = p1.page_title "
			. " AND cl2.cl_from = p2.page_id "
			. " AND p1.page_namespace = $categoryNamespace "
			. " AND p1.page_id != p2.page_id "
			. " GROUP BY p1.page_title "
			. " ORDER BY $order ";
	if ($order != "name")
	{
		$sql .=	"LIMIT $maxitems OFFSET 0";
	} 

	$res = $dbr->query($sql);

    	if ($dbr->numRows( $res ) == 0)
	{
		// Can't find category
		return htmlspecialchars(wfMsg(
			'categorycloud_emptycategory')
			. $categoryName);
	}

	// Build up an array and keep track of mins and maxes
	$minCount = -1;
	$maxCount = -1;
        $countAll = 0;
        $total = 0;
	$categories = array();
	$names = array();

	while ($row = $dbr->fetchObject($res))
	{
		// Pull out the fields
		$name = $row->name;
		$count = $row->count;

		// Add it to the array and keep track of min/max
		$categories[$name] = $count;
		$names[] = $name;
		$countAll++;
		$total += $count;
		
		if ($minCount < 0 || $minCount > $count)
			$minCount = $count;

		if ($maxCount < 0 || $maxCount < $count)
			$maxCount = $count;
	}

	// Figure out the averages and font sizes
	$minSize = 80;
	$maxSize = 125;

	if (array_key_exists("minsize", $args)) $minSize = $args["minsize"];
	if (array_key_exists("maxsize", $args)) $maxSize = $args["maxsize"];

	$countDelta = $maxCount - $minCount;
	$sizeDelta = $maxSize - $minSize;
	$average = $total / $countAll;

	// Create the tag cloud div
	$class = "category-cloud";

	if ($args["class"]) $class = $args["class"];

	$text  = "<div class='$class'";

	if ($args["style"])
		$text .= " style='" . $args["style"]. "'";

	$text .= ">";

	// Go through the categories by name
	foreach ($names as $cat)
	{
		// Wrap the link in a size
		if ($countDelta == 0)
			$size = 100;
		else
			$size = (($categories[$cat] - $minCount)
				* $sizeDelta / $countDelta) + $minSize;

		// Get the link
		$cat = str_replace("_", " ", $cat);
		$text .= " <span style='font-size: $size%;'>"
			. "[[:Category:$cat|$cat]]</span>";
	}

	// Finish up
	$text .= "</div>";

	// If donotparse is set to a value, then we don't want
	// to parse it into wiki text.
	if (array_key_exists("donotparse", $args))
	{
	        wfProfileOut('CategoryCloud::RenderNoParse');
		return $text;
	}

	// Parse the results into wiki text
	$output = $parser->parse($text,
			$parser->mTitle, $parser->mOptions,
			true, false);

	// Finish up and return the results
        wfProfileOut('CategoryCloud::Render');
        return $output->getText();
}
?>
<category-cloud category="" minsize="80" maxsize="200" order="count" maxitems="50"></category-cloud> 

Cloud text bunching up[edit]

I'm trying to display the category cloud within a table on my main page, but the text is bunching up on top of itself, rendering it illegible. Is there a way to stop this from happening? --205.194.74.10 20:20, 20 April 2010 (UTC)Reply

What is the right version?[edit]

Please, what is the right version? I copied the first source used on Wikiprogress, saved with name CategoryCloud.php and con syntax

<category-cloud category="" minsize="80" maxsize="200" order="count" maxitems="15" exclude="Templates"></category-cloud> 

but I get Error 500 just in Main Page on my MW 1.19.2.(PHP 5.3)

Thanks in advance --WhiteTigerItaly (talk) 16:19, 4 October 2012 (UTC)Reply

Using it on MediaWiki 1.26.2[edit]

Tried installing it on MediaWiki 1.26.2. I had to do some changes because MessageCache was removed in 1.18.0. The following code

	// Set our messages
	$wgMessageCache->addMessages( array(
                    'categorycloud_missingcategory'
			=> 'CategoryCloud: Cannot find category attribute',
                    'categorycloud_emptycategory'
			=> 'CategoryCloud: Category is empty: ',
                    'categorycloud_cannotparse'
			=> 'CategoryCloud: Cannot parse parameter: ',
		));

was replaced by:

	$wgHooks['categorycloud_missingcategory'][] = 'CategoryCloud: Cannot find category attribute';
	$wgHooks['categorycloud_emptycategory'][] = 'CategoryCloud: Category is empty: ';
	$wgHooks['categorycloud_cannotparse'][] = 'CategoryCloud: Cannot parse parameter: ';