How To Customize WordPress Tag Cloud Without a Plugin

For a WordPress blog, a Tag cloud displays a list of tags. Tags are usually single words, and the importance of each Tag is shown with different font size. The size of each Tag is determined by how many times that particular Tag has been assigned to posts. Tags are links that lead to a list of posts associated with each Tag. The WordPress Tag cloud is a widget that displays all popular tags in a convenient layout. More…

Tag Cloud Benefits

Like any WordPress Widget, and depending on the flexibility of your theme, Tag cloud widget can be used anywhere in your WordPress Website. Your readers can search different topics based on Tags instead of categories. Also Tags help your Website gain higher ranking in Search Engines by using different keywords related to the post. Tags are text links, rich in keywords, that are indexed by search engines. A Tag cloud would help your Website with more search queries. The more you use the same tags, the more they will grow in importance for your visitors and search engines. It is important to keep tags relevant to the post. Around 5 tags per post is good enough.

Default WordPress Tag Cloud

If you are using the standard version of the WordPress Tag cloud, you may dislike how it looks. Many people, including myself, are not happy with just using the default WordPress Tag Cloud widget without being able to modify it. We want to have control. This is where this tutorial helps!

Custom Tag Cloud

My version of the Tag cloud lets you customize it to your liking. Also in my code you have additional controls that are not part of the default WordPress Tag cloud. The custom Tag cloud on the right sidebar of this blog is generated by the code shown below.

Prerequisite: This tutorial assumes that your WordPress theme already supports widgets. To find out, check your theme´s documentation. Also it should be mentioned in your WordPress dashboard. Your theme must support widgets, for this code to work.

What about a Plugin? Yes, there are plugins that customize WordPress Tag Clouds, such as Configurable Tag Cloud and Better Tag Cloud being the most popular. But haven´t you read my previous post about the disadvantages of going crazy adding plugins to your theme?

Advantages of My Custom Tag Cloud Code

These are the main advantages of adding my code:

  1. No need to install an additional plugin for your WordPress Website.
  2. The code is added to your theme´s functions.php file. Your WordPress core files are not modified.
  3. You can change any default parameter to your liking: (smallest, largest, unit, number, format, separator, order, etc). More details.
  4. In addition: My custom Tag cloud code allows you to:
    • Limit the Tags in the cloud based on their weight (i.e. number of posts they are attached to). For example, you can exclude tags that have more than or less than some defined number of posts.
    • Change The Tag color based on its weight. The Tag weight is determined by the number of posts attached to each Tag. For example, Tags with less weight will have a different color than Tags with more weight.

WordPress Custom Tag Cloud Code

This is my version of the custom Tag cloud code. Open the functions.php file located in your theme´s folder and add (copy and paste) the following three functions. This code is tested to work for the current WordPress version. Sorry for the long code!
Note: If the vertical scroll bar is shown, you need to scroll all the way down to see the horizontal bar.

To set your own parameters, search the code for: ***MODIFY TO WHAT YOU LIKE***

<?php
/***** Custom Tag Cloud Code without the need of a Plugin. 
       Tested up to WordPress version 3.1.2 *****/

/** Function that generates Tag colors based on their weight (number of posts per Tag)
If nothing gets passed in to the function for $min_color and $max_color, it skips the function
and uses the defined link color in the CSS.  If only one color is passed, it is used for both.
Function is based on Version 5.2 of the Configurable Tag Cloud plugin **/

function color_weight($weight, $min_color, $max_color) {
	if ($min_color == "" && $max_color == "")
		return;

	if ($min_color == "") {
		$color = $max_color;
		return $color;
	}
	if ($max_color == "") {
		$color = $min_color;
		return $color;
	}
	if ($weight) {
		$weight = $weight/100;

		//hack to handle CSS shorthand color definitions (i.e., #000 instead of #000000)
		//strlen — Get string length (http://php.net/manual/en/function.strlen.php)
		if (strlen($min_color) == 4) {
			//substr — Return part of a string (http://php.net/manual/en/function.substr.php)
			$r = substr($min_color, 1, 1);
			$g = substr($min_color, 2, 1);
			$b = substr($min_color, 3, 1);

			$min_color = "#$r$r$g$g$b$b";
		}
		if (strlen($max_color) == 4) {
			$r = substr($max_color, 1, 1);
			$g = substr($max_color, 2, 1);
			$b = substr($max_color, 3, 1);

			$max_color = "#$r$r$g$g$b$b";
		}
		//hexdec — Hexadecimal to decimal (http://php.net/manual/en/function.hexdec.php)
		$minr = hexdec(substr($min_color, 1, 2));
		$ming = hexdec(substr($min_color, 3, 2));
		$minb = hexdec(substr($min_color, 5, 2));

		$maxr = hexdec(substr($max_color, 1, 2));
		$maxg = hexdec(substr($max_color, 3, 2));
		$maxb = hexdec(substr($max_color, 5, 2));

		//intval — Get the integer value (http://php.net/manual/en/function.intval.php)
		$r = dechex(intval((($maxr - $minr) * $weight) + $minr));
		$g = dechex(intval((($maxg - $ming) * $weight) + $ming));
		$b = dechex(intval((($maxb - $minb) * $weight) + $minb));

		if (strlen($r) == 1) $r = "0".$r;
		if (strlen($g) == 1) $g = "0".$g;
		if (strlen($b) == 1) $b = "0".$b;

		$color = "#$r$g$b";
		$color = substr($color,0,7);
		
		return $color;
	}
}

/*** Function that Generates an HTML string that makes the Tag Cloud ****/
//See Reference: http://codex.wordpress.org/Template_Tags/wp_generate_tag_cloud
//This function is similar as 'wp_generate_tag_cloud()' located in: 'wp-includes/category-template.php'
//Major difference: This function COLORS the Tags in the cloud based on their 
//weight (number of posts attached to the Tag) as shown in the short code. 
 
function bac_generate_tag_cloud( $tags, $args = '' ) {
	global $wp_rewrite;
	$defaults = array( //***KEEP THE DEFAULTS DON'T TOUCH.***
		'smallest' => 8, 'largest' => 22, 'unit' => 'pt', 'number' => 0,
		'format' => 'flat', 'separator' => "\n", 'orderby' => 'name', 'order' => 'ASC',
		'topic_count_text_callback' => 'default_topic_count_text',
		'topic_count_scale_callback' => 'default_topic_count_scale', 'filter' => 1,
	);
	//!isset — Determine if a variable is NOT set or is NULL (http://php.net/manual/en/function.isset.php)
	if ( !isset( $args['topic_count_text_callback'] ) && isset( $args['single_text'] ) && isset( $args['multiple_text'] ) ) {
		//var_export — returns a parsable string representation of a variable (http://php.net/manual/en/function.var-export.php)
		$body = 'return sprintf (
			_n(' . var_export($args['single_text'], true) . ', ' . var_export($args['multiple_text'], true) . ', $count),
			number_format_i18n( $count ));';
		//create_function — Create an anonymousfunction (http://php.net/manual/en/function.create-function.php)
		$args['topic_count_text_callback'] = create_function('$count', $body);
	}
	$args = wp_parse_args( $args, $defaults );
	//extract — Import variables into the current symbol table from an array (http://php.net/manual/en/function.extract.php)
	extract( $args );

	if ( empty( $tags ) )
		return;

	$tags_sorted = apply_filters( 'tag_cloud_sort', $tags, $args );
	if ( $tags_sorted != $tags  ) { // the tags have been sorted by a plugin
		$tags = $tags_sorted;
		unset($tags_sorted);
	} else {
		if ( 'RAND' == $order ) {
			shuffle($tags);
		} else {
			// SQL cannot save you; this is a second (potentially different) sort on a subset of data.
			if ( 'name' == $orderby )
				uasort( $tags, create_function('$a, $b', 'return strnatcasecmp($a->name, $b->name);') );
			else
				uasort( $tags, create_function('$a, $b', 'return ($a->count > $b->count);') );

			if ( 'DESC' == $order )
				$tags = array_reverse( $tags, true );
		}
	}
	if ( $number > 0 )
		$tags = array_slice($tags, 0, $number);

	$counts = array();
	$real_counts = array(); // For the alt Tag
	foreach ( (array) $tags as $key => $tag ) {
		$real_counts[ $key ] = $tag->count;
		$counts[ $key ] = $topic_count_scale_callback($tag->count);
	}
	$min_count = min( $counts );
	$spread = max( $counts ) - $min_count;
	if ( $spread <= 0 )
		$spread = 1;
	$font_spread = $largest - $smallest;
	if ( $font_spread < 0 )
		$font_spread = 1;
	$font_step = $font_spread / $spread;

	$a = array();

	foreach ( $tags as $key => $tag ) {
		$count = $counts[ $key ];
		$real_count = $real_counts[ $key ];
		$tag_link = '#' != $tag->link ? esc_url( $tag->link ) : '#';
		$tag_id = isset($tags[ $key ]->id) ? $tags[ $key ]->id : $key;
		$tag_name = $tags[ $key ]->name;
		
		/* Short code that changes the Tag color based on its weight (how many posts are attached to each Tag.) */
		//Define Variable: Beginning color for Tag. format" "#xxx" or "#xxxxxx" where x = [0-9,a-f]
		//If both variables are not defined it uses the Tag color as defined in the CSS document.
		$min_color = "#5679B9"; //***MODIFY TO WHAT YOU LIKE***
		 
		//Define Variable: Ending color for Tag. format" "#xxx or "#xxxxxx"
		$max_color = "#AF1410"; //***MODIFY TO WHAT YOU LIKE***
		
		if ($largest == $smallest)
			$tag_weight = $largest;
		else
			$tag_weight = ($smallest+(($count-$min_count)*$font_step));
			
		$diff = $largest-$smallest;
		
		if ($diff <= 0)
			$diff = 1;
		//round — Rounds a float (http://php.net/manual/en/function.round.php)	
		$color_weight = round(99*($tag_weight-$smallest)/($diff)+1);
		
		//this is the color_weight() functions defined above. 
		$tag_color = color_weight($color_weight, $min_color, $max_color);
				
		//Modified to include Tag Link color.
		//call_user_func — Call a user function given by the first parameter (http://php.net/manual/en/function.call-user-func.php) 
		$a[] = "<a href='$tag_link' class='tag-link-$tag_id' title='" . esc_attr( call_user_func( $topic_count_text_callback, $real_count ) ) . "' style='font-size: " . 
			( $smallest + ( ( $count - $min_count ) * $font_step ) )
			. "$unit;  color: $tag_color; background-color: inherit;'>$tag_name</a>"; //background-color is added for validation purposes.
		/*** End of short code ***/		
	}	
	switch ( $format ) :
	case 'array' :
		$return =& $a;
		break;
	case 'list' :
		$return = "<ul class='wp-tag-cloud'>\n\t<li>";
		//join — Alias of implode() (http://php.net/manual/en/function.join.php)
		$return .= join( "</li>\n\t<li>", $a );
		$return .= "</li>\n</ul>\n";
		break;
	default :
		$return = join( $separator, $a );
		break;
	endswitch;
		
		//Function to create a new filter hook (http://codex.wordpress.org/Function_Reference/apply_filters)
		return apply_filters( 'bac_generate_tag_cloud', $return, $tags, $args );
}

/*** Function that Displays the Tag Cloud ****/
//See Reference: http://codex.wordpress.org/Template_Tags/wp_tag_cloud 
//This function is similar as 'wp_tag_cloud()' located in: 'wp-includes/category-template.php'
//Major difference: This function excludes Tags in the cloud based on their weight as shown in the short code. 
function bac_tag_cloud($args) {

$defaults = array( // ***MODIFY TO WHAT YOU LIKE***

	'smallest' => 12,   //The smallest Tag (lowest count) is shown at size 12
	'largest' => 30,    //The largest Tag (highest count) is shown at size 30 
	'unit' => 'px',     //Unit of measure for the smallest and largest values. Can be any CSS value (pt, px, em, %). 
	'number' => 50,     //set how many tags to show (default is 45 tags in the Tag cloud list).
	'format' => 'flat', // Format of the cloud display (flat, list, array) 
	'separator' => "\n", //The text/space between tags. 
	'orderby' => 'name', //argument will accept 'name' or 'count' and defaults to 'name'.
	'order' => 'ASC',   //sort order, defaults to 'ASC' and can be 'DESC'
	'exclude' => '',   //Exclude a specific Tag by its Tag ID separated by commas.
	'include' =>'',   //Include a specific Tag by Tag ID separated by commas. Use 'exclude' or 'include', but not both.
	'link' => 'view',  //Set link to allow edit of a particular Tag.
	'taxonomy' => 'post_tag', //Taxonomy or array of taxonomies to use in generating the cloud. 
	'echo' => true //DO NOT TOUCH THIS.
); //***End Of MODIFY SECTION***

//wp_parse_args() is a generic utility for merging together an array of arguments and an array of default values. 
/*http://codex.wordpress.org/Function_Reference/wp_parse_args*/
$args = wp_parse_args( $args, $defaults );
//Retrieve the terms in taxonomy or list of taxonomies. 
/*http://codex.wordpress.org/Function_Reference/get_terms  ;    http://php.net/manual/en/function.array-merge.php*/
// Always query top tags
$tags = get_terms( $args['taxonomy'], array_merge( $args, array( 'orderby' => 'count', 'order' => 'DESC' ) ) ); 

//If there are no tags
if ( empty( $tags ))
	return; //ends execution of the current function

/***** Short Code that gives the user the option not to display Tags in the Cloud 
based on the Tag's weight (number of posts attached to the Tag.)  *****/

//Minimum number of posts per tags. ***MODIFY TO WHAT YOU LIKE***
$min_num = 1;  // Tags with less than this number of posts will not be displayed.

//maximum number of posts per tags. ***MODIFY TO WHAT YOU LIKE***
$max_num = 65; //Tags with more than this number of posts will not be displayed.

foreach($tags as $key => $tag)
	{	//If the post count of Tag is outside the range
		if($tag->count < $min_num || $tag->count > $max_num)
		{
			/*unset()-destroy a single element of an array - http://php.net/manual/en/function.unset.php*/ 
			unset($tags[$key]);
		}
	}
/*** End of short code ***/

foreach ( $tags as $key => $tag ) {
		if ( 'edit' == $args['link'] )
		
			//Displays a link to edit the current Tag, if the user is logged in and allowed to edit the Tag.
			/*http://codex.wordpress.org/Function_Reference/edit_tag_link*/
			$link = get_edit_tag_link( $tag -> term_id, $args['taxonomy'] );
		else
			//Returns permalink for a taxonomy term archive. 
			/*http://codex.wordpress.org/Function_Reference/get_term_link*/
			$link = get_term_link( intval($tag -> term_id), $args['taxonomy'] );
		
		//Check whether variable is a WordPress Error. 
		/*http://codex.wordpress.org/Function_Reference/is_wp_error*/
		if ( is_wp_error( $link ) )
			return false;

	$tags[ $key ] -> link = $link;
	$tags[ $key ] -> id = $tag -> term_id;
}
//Generates a Tag cloud (heatmap) from provided data. Located at: 
$return = bac_generate_tag_cloud( $tags, $args ); // Here is where those top tags get sorted according to $args

//Function to create a new filter hook.
/*http://codex.wordpress.org/Function_Reference/apply_filters*/
$return = apply_filters( 'bac_tag_cloud', $return, $args );

if ( 'array' == $args['format'] || empty($args['echo']) )
	return $return;

echo $return;
}
//Hooks a function to a specific filter action.
/*http://codex.wordpress.org/Function_Reference/add_filter*/
add_filter('wp_tag_cloud', 'bac_tag_cloud');
?>

Styling the Custom Tag Cloud

Finally we need to style the custom Tag cloud code with CSS. The following CSS code is what I used for this blog. The code should be part of your theme´s CSS file (usually called style.css). You probably already have a CSS code in place for the cloud and this step might not be necessary.

/* Styling Custom Tag Cloud Widget by BOUTROS ABICHEDID */

#sidebar ul li.widget_tag_cloud{
    padding:0 0 30px 0; 
}
#sidebar ul li.widget_tag_cloud a{
    background-color:inherit;
    text-decoration:none;   
    padding:0 0 0 15px;
    line-height:22px;
    color:#DF8D0D;
}
#sidebar ul li.widget_tag_cloud a:hover{
    text-decoration: none;
    color:#695321 !important; 
    background-color: inherit;
}

Conclusion

You now can customize your Tag cloud without the need of a plugin and without modifying your WordPress core files. In addition, you have more control of what tags to show and what color to display based on their weight. If you have any questions or anything else to say, make sure to leave a comment. Thank you for reading!

References

  1. Function Reference « WordPress Codex
  2. wp_tag_cloud() Function
  3. Taxonomies
  4. WordPress Widgets
  5. Is Tag Cloud useful, does it give SEO boost, …
  6. Tag Clouds and SEO

If you enjoyed this post, please consider: linking back to it, subscribing by email to future posts, or subscribing to the RSS feed to have new articles delivered to your feed reader. Thanks!

About the Author |
Boutros is a professional Drupal & WordPress developer, Web developer, Web designer, Software Engineer and Blogger. He strives for pixel perfect design, clean robust code, and user-friendly interface. If you have a project in mind and like his work, feel free to contact him. Connect with Boutros on Twitter, and LinkedIn.
Visit Boutros AbiChedid Website.

42 Responses to “How To Customize WordPress Tag Cloud Without a Plugin”

  1. Michael says:

    Hello Boutros,
    I really appreciated the post you wrote on tag cloud, thank you!
    I’m a journalist and photographer, but I do not do codes or plug-ins or else … my blog is hosted on WP servers … is there anything I can do to have more tags in the cloud.
    Best and have a great day :)
    Michael

    • Hi Michael,

      The answer is Yes, if your WordPress Website is self hosted.
      But if it is hosted at wordpress.com then I don’t know.
      Can you be more specific, to what Website are you planning to add the tags?
      I can help with a donation to this blog and the amount will be determined depending on the complexity of your task.
      Thanks.

      Boutros.

  2. Luko Del Ponte says:

    Hello,

    I’m using custom taxonomies. When I put tag cloud widget in widget area it displays “standard” posts tags only. And if I put two widgets (for different taxonomies) in widget areas it displays the same thing (“standard” tags, not custom taxonomies).
    Is there a way to modify code for displaying custom taxonomies? I’m using it to exclude some “administrative” custom taxonomies.
    P.S. Without this code in functions.php, tag cloud widgets are able to display various taxonomies (including custom).

    BW

    Luko

  3. Asaka says:

    Hi! Thanks for your code!

    Just a question, if you can help me :)

    I wanna change my tag cloud color; i tried by changing the stylesheet code I added, but no results. I wanna a black tag cloud, but I see red, blue tags!

    Thanks for your attention

  4. bruno says:

    Hi Boutros,

    I think that the code should be changed as follow:

    function bac_tag_cloud($args) {

    $defaults = array( // ***MODIFY TO WHAT YOU LIKE***

    …. bla bla …

    ); //***End Of MODIFY SECTION***

    $args = wp_parse_args( $args, $defaults );

    I tried to use your colored cloud tag with a specific category and I can’t filter tags by category. When I change $args by $defaults, it’s ok.

    • Thanks Bruno for your feedback. Are you talking about line 216 of the code?
      What do you modify it to?

      I already used this code on 6 different themes and it works fine. It might be a theme related issue.
      Thanks.
      Boutros.

  5. Thx man, i’ve been looking for this kind of tags code, and i came across this article.
    I’ve been reluctant to install a plugin about this, and thankfully found your article in the right time.

    • bruno says:

      No, the line 216 is correct.

      But I think the line 195 should be : function bac_tag_cloud($args) {

      instead of : function bac_tag_cloud($defaults) {

      And line 197 should be : $defaults = array( // ***MODIFY TO WHAT YOU LIKE***

      instead of : $args = array( // ***MODIFY TO WHAT YOU LIKE***

      Otherwise if you call bac_tag_cloud($defaults) with $defaults = array(‘include’ => ’1,2,3,’), then due to wp_parse_args( $args, $defaults ); the include list is erased.

      $args = wp_parse_args( array(‘include’ => ”) , array(‘include’ => ’1,2,3′) );
      in this case $args['include'] remains an empty list.

      • You are absolutely Correct Bruno. Thank you very much. Interesting No one pointed this out before and it worked on many themes. But I guess this issue rose for your specific need.
        The ‘bac_tag_cloud()’ function is similar to the ‘wp_tag_cloud()’ located in: ‘wp-includes/category-template.php’

        Amazing on how many themes this code has been installed without any problems. I will correct the code accordingly.
        Thank you Bruno.

        Boutros.

  6. alain says:

    Merci pour le code, ça marche à merveille.
    Bonne continuation

  7. Magnus says:

    Hi !
    I tried to copy and paste your code into my functions file, then the the website just got white, I removed the code and the site was fine again.
    I have probably put the code in the wrong place in the functions file. Where should I put it???

    • Hi Magnus,

      What WordPress theme are you using (link)? Also what WordPress Version?
      Also as a general warning:
      When you add several PHP code blocks in your theme´s funtions.php file, make sure that you do NOT leave any white space (spaces, newline) before the opening PHP tag (<?php) or after the closing PHP tag (?>). The correct way is as follows:

      <?php 
      //Some Code here beetween the opening PHP tag (above) 
      //and the closing PHP tag (below)...
      ?>
      <?php 
      //Some other Code here ...
      ?>
      

      In the above code, if you leave any white space or a newline between lines 4 and 5, you will get the following error: “Warning: Cannot modify header information – headers already sent by…”

      It could be the above, or a plugin interfering with my code. But I will know better if you let me know the theme you are using and I’ll take a look.
      Boutros.