lots of code take some code, share some code!

Tag Cloud



Tag Cloud Script (Version 2) is now Available, with more customizable features

Introduction


In this tutorial i am going to show you how to create a basic word / tag cloud using php and utilizing php classes for easy inclusion. I am going to create a class based cloud, this is because it will be more convenient for you to adapt it on your own website(s), if you don't know much about class based programming then click here to take a look at the class tutorial.

Tutorial

First we need to create the class and for this example i am going to call the class 223wordCloud224 this is just my personal naming preference, feel free to call your cloud whatever you like, we are also going to assign the first class variable which will be the container of all the items in the array, we will call it 223wordsArray224.

<?
class wordcloud
{
var $wordsArray = array();
}
?>

Next, we need to assign the first function, because of the difference between PHP 4 and PHP 5 Constructors, i have created a method (function) called 223wordCloud224 and 223__construct224, when wordCloud is called it simultaneously call the PHP 5 constructor, so it's compatible with both versions like so.

<?
function __construct($words = false)
{
if ($words !== false && is_array($words))
{
foreach ($words as $key => $value)
{
$this->addWord($value);
}
}
}

function wordCloud($words = false)
{
$this->__construct($words);
}
?>

The main constructor basically can be used to load the words when the class object is created.

Now, we need to create a function to add words into the array as and when we need them.

<?
function addWord($word, $value = 1)
{
$word = strtolower($word);
if (array_key_exists($word, $this->wordsArray))
$this->wordsArray[$word] += $value;
else
$this->wordsArray[$word] = $value;

return $this->wordsArray[$word];
}
?>

The method above will basically check the array of words and if the word exists it will increase the repetition value, this can also be adjusted by manual input.

Next, we need to be able to get the size of the array, now because we have an array with values, we can use the values of all the items in the array added together like so.

<?
function getCloudSize()
{
return array_sum($this->wordsArray);
}
?>

Next, we need to create a function to calculate the class / range that each specific word should be assigned to, this will be done by using the percentage that will be returned from the final function.

<?
function getClassFromPercent($percent)
{
if ($percent >= 99)
$class = 1;
else if ($percent >= 70)
$class = 2;
else if ($percent >= 60)
$class = 3;
else if ($percent >= 50)
$class = 4;
else if ($percent >= 40)
$class = 5;
else if ($percent >= 30)
$class = 6;
else if ($percent >= 20)
$class = 7;
else if ($percent >= 10)
$class = 8;
else if ($percent >= 5)
$class = 9;
else
$class = 0;

return $class;
}
?>

Next we create a function that will shuffle all the values in the cloud, this is so that we can have a different output each time, this could be adapted so that it only shuffles the cloud if choose to.

<?
function shuffleCloud()
{
$keys = array_keys($this->wordsArray);

shuffle($keys);

if (count($keys) && is_array($keys))
{
$tmpArray = $this->wordsArray;
$this->wordsArray = array();
foreach ($keys as $key => $value)
$this->wordsArray[$value] = $tmpArray[$value];
}
}
?>

Now, we need to create a function to display the words, i have decided to make this function have two possible outputs, this is because if you would like more control over the output or if you would like to use less standard class names then you can do so, the two possible output types are an php array and html spans.

function showCloud($returnType = "html")
{
$this->shuffleCloud();
$this->fullCloudSize = $this->getCloudSize();
$this->max = max($this->wordsArray);

if (is_array($this->wordsArray))
{
$return = ($returnType == "html" ? "" : ($returnType == "array" ? array() : ""));
foreach ($this->wordsArray as $word => $popularity)
{
$sizeRange = $this->getClassFromPercent(($popularity / $this->max) * 100);
if ($returnType == "array")
{
$return[$word]['word'] = $word;
$return[$word]['sizeRange'] = $sizeRange;
if ($currentColour)
$return[$word]['randomColour'] = $currentColour;
}
else if ($returnType == "html")
{
$return .= "<span class='word size{$sizeRange}'> {$word} </span>";
}
}

return $return;
}
}

Ok, so now we have the class, we need to use this to create our cloud, this could be done like so.

<?

// You could add items to the class by passing them through the constructor

$randomWords = array("webmasterworld", "Computer", "Skateboarding", "PC", "music", "music", "music", "music", "PHP", "C", "XHTML", "programming", "forums", "Chill out", "email", "forums", "Computer", "GTA", "Freetimers", "css", "mysql", "sql", "css", "mysql", "sql", "forums", "internet", "class", "object", "method", "music", "music", "music", "music", "gui", "encryption");

$cloud = new wordCloud($randomWords);

// Or you could assign them manually
$cloud->addWord("harvey", 5);
$cloud->addWord("music", 12);
echo $cloud->showCloud();
?>

Don't forget to create your styles to display the different size fonts, this is a little something i have come up with.

<style>
<!--
.word {
font-family: Tahoma;
padding: 4px 4px 4px 4px;
letter-spacing: 3px;
}
span.size1 {
color: #000;
font-size: 2.4em;
}
span.size2 {
color: #333;
font-size:2.2em;
}
span.size3 {
color: #666;
font-size: 2.0em;
}
span.size4 {
color: #999;
font-size: 1.0em;
}
span.size5 {
color: #aaa;
font-size: 1.6em;
}
span.size6 {
color: #bbb;
font-size: 1.4em;
}
span.size7 {
color: #ccc;
font-size: 1.2em;
}
span.size8 {
color: #ddd;
font-size: .8em;
}
//-->
</style>

To finish off i will finish with the code in full.

Full PHP Tag Cloud Class

<?
/*
@wordCloud
Author: Derek Harvey
Website: www.lotsofcode.com

@Description
PHP Tag Cloud Class, a nice and simple way to create a php tag cloud, a database and non-database solution.
*/

class wordCloud
{
var $wordsArray = array();

/*
* PHP 5 Constructor
*
* @param array $words
* @return void
*/

function __construct($words = false)
{
if ($words !== false && is_array($words))
{
foreach ($words as $key => $value)
{
$this->addWord($value);
}
}
}

/*
* PHP 4 Constructor
*
* @param array $words
* @return void
*/

function wordCloud($words = false)
{
$this->__construct($words);
}

/*
* Assign word to array
*
* @param string $word
* @return string
*/

function addWord($word, $value = 1)
{
$word = strtolower($word);
if (array_key_exists($word, $this->wordsArray))
$this->wordsArray[$word] += $value;
else
$this->wordsArray[$word] = $value;

return $this->wordsArray[$word];
}

/*
* Shuffle associated names in array
*/

function shuffleCloud()
{
$keys = array_keys($this->wordsArray);

shuffle($keys);

if (count($keys) && is_array($keys))
{
$tmpArray = $this->wordsArray;
$this->wordsArray = array();
foreach ($keys as $key => $value)
$this->wordsArray[$value] = $tmpArray[$value];
}
}

/*
* Calculate size of words array
*/

function getCloudSize()
{
return array_sum($this->wordsArray);
}

/*
* Get the class range using a percentage
*
* @returns int $class
*/

function getClassFromPercent($percent)
{
if ($percent >= 99)
$class = 1;
else if ($percent >= 70)
$class = 2;
else if ($percent >= 60)
$class = 3;
else if ($percent >= 50)
$class = 4;
else if ($percent >= 40)
$class = 5;
else if ($percent >= 30)
$class = 6;
else if ($percent >= 20)
$class = 7;
else if ($percent >= 10)
$class = 8;
else if ($percent >= 5)
$class = 9;
else
$class = 0;

return $class;
}

/*
* Create the HTML code for each word and apply font size.
*
* @returns string $spans
*/

function showCloud($returnType = "html")
{
$this->shuffleCloud();
$this->max = max($this->wordsArray);

if (is_array($this->wordsArray))
{
$return = ($returnType == "html" ? "" : ($returnType == "array" ? array() : ""));
foreach ($this->wordsArray as $word => $popularity)
{
$sizeRange = $this->getClassFromPercent(($popularity / $this->max) * 100);
if ($returnType == "array")
{
$return[$word]['word'] = $word;
$return[$word]['sizeRange'] = $sizeRange;
if ($currentColour)
$return[$word]['randomColour'] = $currentColour;
}
else if ($returnType == "html")
{
$return .= "<span class='word size{$sizeRange}'> {$word} </span>";
}
}
return $return;
}
}
}
?>

<style>
<!--
.word {
font-family: Tahoma;
padding: 4px 4px 4px 4px;
letter-spacing: 3px;
}
span.size1 {
color: #000;
font-size: 2.4em;
}
span.size2 {
color: #333;
font-size:2.2em;
}
span.size3 {
color: #666;
font-size: 2.0em;
}
span.size4 {
color: #999;
font-size: 1.0em;
}
span.size5 {
color: #aaa;
font-size: 1.6em;
}
span.size6 {
color: #bbb;
font-size: 1.4em;
}
span.size7 {
color: #ccc;
font-size: 1.2em;
}
span.size8 {
color: #ddd;
font-size: .8em;
}
span.size0 {
color: #ccc;
font-size: .6em;
}
//-->
</style>

<?
$randomWords = array(
"webmasterworld", "Computer", "Skateboarding", "PC", "music", "music", "music", "music", "PHP", "C", "XHTML", "eminem", "programming", "forums", "webmasterworld",
"Chill out", "email", "forums", "Computer", "GTA", "css", "mysql", "sql", "css", "mysql", "sql",
"forums", "internet", "class", "object", "method", "music", "music", "music", "music", "gui", "encryption"
);

$cloud = new wordCloud($randomWords);
$cloud->addWord("music", 12);
$cloud->addWord("downloads", 8);
$cloud->addWord("internet", 17);
$cloud->addWord("PHP", 22);
$cloud->addWord("CSS", 32);
echo $cloud->showCloud();
?>

And this is how it should look, i have changes some of the colours for the more important words.

How to intergrate with a MySQL database.

Depending on how your information is stored in your database, an individual field or a comma seperated field then you can place the tags into the cloud from a MySQL results like follows.

Let's say we have a table called tags, if we have comma seperated values.

<?php

$cloud = new wordcloud();

$getBooks = mysql_query("SELECT title FROM `tags`");
if ($getBooks)
{
while ($rowBooks = mysql_fetch_assoc($getBooks))
{
$getTags = explode(' ', $rowBooks['title']);
foreach ($getTags as $key => $value)
{
$value = trim($value);
$cloud->addWord($value);
}
}
}

$myCloud = $cloud->showCloud('array');
if (is_array($myCloud))
{
foreach ($myCloud as $key => $value)
{
echo ' <a href="path/to/tags/'.$value['word'].'" style="font-size: 1.'.$value['sizeRange'].'em">'.$value['word'].'</a> &nbsp;';
}

?>

If the tag is an individual field, then:

<?php

$cloud = new wordcloud();

$getBooks = mysql_query("SELECT title FROM `tags`");
if ($getBooks)
{
while ($rowBooks = mysql_fetch_assoc($getBooks))
{
$cloud->addWord($rowBooks['title']);
}
}
}

$myCloud = $cloud->showCloud('array');
if (is_array($myCloud))
{
foreach ($myCloud as $key => $value)
{
echo ' <a href="tags_url/'.urlencode($value['word']).'" style="font-size: 1.'.($value['range']).'em">'.$value['word'].'</a> ';
}
?>

Video Tutorials

Finished.

Ok, so that's the tutorial over. Please have fun with the code, if you are a little confused then please check out the video tutorials, the quality is a little bad at the moment but i hope to arrange some better videos soon!

All comments and questions are welcome, provided they are related to this page.

28 Responses to “Tag Cloud”

  1. madteckhead says:

    Any suggestions for how to best include a int value (similar to the rating value) for each word so that it can be included in a link. Said another way, my links don't use the name in the tad but a category id, which is unique.

    Any suggestion appreciated.

    Nathan

  2. curb says:

    Is there a way to use the span size1,2,3,4 etc instead of the style="font-size: 1.'.($value['range']).'em" ?

    All the sizeRange is zero when I know there are multiple rows with the same words in a title making the cloud tags cloudless.

    $cloud = new wordcloud();
    $getBooks = mysql_query("SELECT title FROM `bookstore`");
    if ($getBooks)
    {
    while ($rowBooks = mysql_fetch_assoc($getBooks))
    {
    $getTags = explode(' ', $rowBooks['title']);
    foreach ($getTags as $key => $value)
    {
    $value = trim($value);
    $cloud->addWord($value);
    }
    }
    }

    $myCloud = $cloud->showCloud('array');
    if (is_array($myCloud))
    {
    foreach ($myCloud as $key => $value)
    {
    echo ' <a href="tags_url/'.urlencode($value['word']).'" style="font-size: 1.'.($value['range']).'em" rel="nofollow">'.$value['word'].'</a> ';
    }
    }

  3. Karan Goyal says:

    That worked like a charm, thanks a lot :)

  4. RichF says:

    Thanks for this snippet. I leveraged this while building out my own tag cloud generator from a lucene index. Some of the initial clouds I generated are located at [http://richardfriedman.blogspot.com] I will post my code snippets in a blog when I get it cleaned up.

  5. Kevin T. Keith says:

    Is there a way to generate the array dynamically, so that the tags in the cloud would evolve as the content of your site changes? (For instance: a function that scans and rank-orders the total text content of a Web site, ignores words like "the" or "and", and then generates an array of tags consisting of whatever the top 50 or 100 words on the site happen to be that day, so that new words will appear and old ones disappear as not merely the number of repetitions of a word, but the actual words themselves, appear or disappear from the site. That way you wouldn't have to edit the array to reflect changes in content.)

  6. Crashdaddy says:

    Hi fellas, I love the code. It kicks @. In fact it produces such nice results, I'm trying to use it on this [url=http://crashdaddy62.powweb.com/articles/action=all]database-driven article section[/url] I'm building for these nice people. The articles and number of views and ids are stored in a database, and I pull them out for each article in the database. I'm trying to use your code to generate links to each article based on its id, but it's kicking MY @! Like how do you tell it to include the id in the class, and then pass it? Is that even something I need to do?

  7. Jason says:

    Thank you for this wonderful script, appreciation isn't given so often in today's world so I just want to ensure you know i am very thankful!

  8. keyur shah says:

    Awesome. Thanks.

  9. u24 says:

    hey, you're fifth on google "php tag cloud". I might use this ifwhen I redesign puremango.

  10. tanglesey says:

    How could make this dynamic and pull data from a mySQL database? Sorry, not much of the php programmer, but I like your script,and would like to use it on my site.

  11. mohamed says:

    nice explaning thanks but does it work for any script?

  12. Edward Han says:

    Hi

    Is there another way where I can display different colors for different percentage?

    I tried using style but it didn't work. Any idea how I can do it?

  13. Bobby says:

    Hi, this script is great - worked first time and easy to understand - except for one thing (always a but eh? :))

    Anyway, i'm using the non-database version, so i'm controlling the tag words manually, but i cant figure out how to add links to each individual word.

    I've looked at the video tutorial about links, but i cant see whats going on (detail too small). Any help would be greatly appreciated (non-programmer here). Thank you.

  14. mike says:

    good article thanks

  15. Aran Wilkinson says:

    I was wondering how the tags have to be stored to use the MySQL code that you placed in this tutorial...

    Currently I am storing my tags within the same record as the new article that they are apart of, is this is the right way to do it? Or should I be linking them to the news article some way?

  16. Aran Wilkinson says:

    Thought it would be best to give you a example of how I am storing these tags...

    Basically:

    ID: 1
    Title: Blah (Title of the news Article)
    Content: Stuff About Blah (Content for the news article)
    Author
    Date/Time
    Tags: Blah Stuff About

    The tags are in a list with spaces breaking them up...

    How can I use your script in conjuction with my database and tables?

    As well is this a good way to store my tags? I am not totally sure whether it is the best way to store these tags and as well should I be splitting them up really with a , or something?

  17. Azirius says:

    Heh, I've always wondered how this was done, looks fairly simple now, I guess its always easier when looking at completed code instead of doing it yourself :)
    Nice tutorial, I'll probably be back for another look :P

  18. hguhf says:

    I would like to thank you guys for this useful information you've shared .

    Regards

  19. Dene says:

    I find it a little odd how the above comments are posted one after the other within a small time frame :S

  20. Dene says:

    P.S. having no kind of message display when I post a message is kinda confusing it makes me think it didn't post lol

  21. admin says:

    I migrated the comments from the previous website, unfortunately i couldn't retain the original timestamp.

  22. ????? says:

    Thanks

  23. Amir says:

    Dear lotsofcode,

    I just found your Tutorial about -Tag Cloud Script- but my PHP knowledge is not good enough to understand, where and as which file-name I should save all your scripts. My question is, what should I do with all those codes? Could you please let me know step by step, where I should put all those codes, where should I save and as which file-name?
    I can imagine that all your scripts go into the different files, but I do not know that.

    Regards,
    Amir

  24. lotsofcode says:

    If you use the download link on the top right hand side of the page you can download all the files in the preset directories. Files such as the php, css, js and html and included, you should simply extract them into a directory on your server then visit the directory using a web browser.

  25. Apple iPhone says:

    It works very well, thanks a lot !

  26. Dragos says:

    Very nice script. I think i'will use it. Thanks a lot!

  27. panther says:

    hi @ all,

    first, this is the most simple tagcloud-script i found.
    second, my question is: how can i limit the output of words?
    example: i have 40 words but the output should be limited of 20.

    please, can you help me?!!!

    thx and sry for my bad english.

  28. kwan2400 says:

    I'm using this code very well.
    It works very well, thank you!
    But I want to use more fileds in MySQL database.
    Like this : StarWars(2008-01-01) <- title (date_added)
    How can I use this script that I want?

Leave a Reply

 
 
Please enter the word above into the box below, the word is not case sensitive.
 
If you have trouble reading the word above then click here to load a new word.
Security word: