How to make a tag cloud in PHP, MySQL and CSS

Tag CloudToday I wanted to make a tag cloud, but all my searching proved fruitless - so I decided to stop being lazy and just work it out myself!

For my example, first you'll need a database that stores the keywords / search terms.

The way mine works is every time a search is run, I check to see if the term has been searched before. If it has, I update the counter field + 1. If the term has not been searched for before, I insert it with a counter of 1.

Alternatively you may store every search individually and use the GROUP BY clause to determine how many times the search has been run.

My query looks like this:

PHP:
// don't forget to connect to DB first!

$terms = array(); // create empty array
$maximum = 0; // $maximum is the highest counter for a search term

$query = mysql_query("SELECT term, counter FROM search ORDER BY counter DESC LIMIT 30");

while ($row = mysql_fetch_array($query))
{
    $term = $row['term'];
    $counter = $row['counter'];
   
    // update $maximum if this term is more popular than the previous terms
    if ($counter> $maximum) $maximum = $counter;
   
    $terms[] = array('term' => $term, 'counter' => $counter);

}

// shuffle terms unless you want to retain the order of highest to lowest
shuffle($terms);

Next we'll setup a bit of css. Feel free to adjust these as you see fit.

CSS:
#tagcloud {
    width: 300px;
    background:#FFFFCC;
    color:#0066FF;
    padding: 10px;
    border: 1px solid #FFE7B6;
    text-align:center;
}

#tagcloud a:link, #tagcloud a:visited {
    text-decoration:none;
}

#tagcloud a:hover, #tagcloud a:active {
    text-decoration: underline;
    color: #000;
}

#tagcloud span {
    padding: 4px;
}

.smallest {
    font-size: x-small;
}

.small {
    font-size: small;
}

.medium {
    font-size:medium;
}

.large {
    font-size:large;
}

.largest {
    font-size:larger;
}

Finally we just want to loop through the array and display it with the appropriate css class.

PHP:
// start the output to the page
echo "<h3>Popular Searches</h3>
<div id=\"tagcloud\">
<div>\n"
;

foreach ($terms as $k) // start looping through the tags
{
    // determine the popularity of this term as a percentage
    $percent = floor(($k['counter'] / $maximum) * 100);
   
    // determine the class for this term based on the percentage
    if ($percent <20)
    {
        $class = 'smallest';
    } elseif ($percent>= 20 and $percent <40) {
        $class = 'small';
    } elseif ($percent>= 40 and $percent <60) {
        $class = 'medium';
    } elseif ($percent>= 60 and $percent <80) {
        $class = 'large';
    } else {
        $class = 'largest';
    }
   
    // output this term
    echo "<span class=\"$class\"><a href=\"search.php?search=" . urlencode($k['term']) . "\">" . $k['term'] . "</a></span>\n ";
}

// close the output
echo "</div>
</div>\n"
;

And thats it! Hope this saves someone some time. Add your comments below!

Posted on 22 August '07 by Steve, under PHP.

RSS feed | Trackback URI

38 Comments »

Comment by maz
2007-08-29 22:05:33

gave very good starting concept

 
Comment by Alien
2007-09-18 18:46:06

Awesome, thank you very much, the tag cloud script is really cool.

 
Comment by George
2007-10-14 08:14:29

Great job! This was really helpful! Keep on!

 
Comment by Jason
2007-10-17 23:05:49

Great script - a couple of suggestions though:

* Most tag clouds are sorted alphabetically, you can do this by changing the shuffle() to a sort().
* This should probably be outputted as an ordered list ( with 's for the terms), then CSS used to make it look like a tagcloud.

 
Comment by Steve
2007-10-17 23:16:08

Jason, I agree with your suggestions, however I wonder, how could you make an ordered list replicate a tag cloud? I'm sure its possible however i'm no wizz when it comes to css.

 
Comment by Sandeep Thakur
2007-10-19 02:13:56

Gr8 work, keep it up :)

 
Comment by Pieter
2007-11-20 04:10:11

Dear

I m just jusing the code on my site and it works very fine, thx for it!

Got a problem, i want to put a 3th option in my arry, for example category. How can i put a third option in the array and how do i have to take out of the array?

So here i have to put the third option :
while ($row = mysql_fetch_array($query))
{
$term = $row['term'];
$counter = $row['counter'];
$terms[] = array($term => $counter);
}

And hiere i have to take out :
foreach ($terms as $k => $v)
{
foreach($v as $k2 => $v2)
{
$percent = floor(($v2 / $maximum) * 100);

if ($percent = 20 and $percent = 40 and $percent = 60 and $percent $k2 ";
}
}

So i can put him into the url (a href as a parameter)

Great thanks for the help / feedback.
Pieter

PS : sorry for my english but it s a little be difficult ;-)

 
Comment by martin
2007-12-05 09:04:48

Good thought, had the exact same thought myself :)

 
Comment by MacDaddyEnforcer
2007-12-20 01:40:02

Hey thanks for the code. I used this idea to make something similar in Java.

 
Comment by Ashesh
2007-12-27 16:01:37

Very nice tutorial. thanks

 
Comment by Jul'
2008-01-20 08:20:25

Hye men !

Thx very much. It id very useful. I've just changed it with a link in the database in order to keep traffic on my site.

See you soon

Jul'

 
Comment by chris
2008-02-07 16:25:38

this tag cloud seems to simple and is constrained by specific sizes that are defined in your css. why not develop a better algorithm that calculates a font percentage between ranges of 75%-250%.

 
Comment by Steve
2008-02-07 20:40:13

chris thats a fair point i'm sure it would look better with more font size variation. Any suggestions for such an algorithm? Obviously it would revolve around refactoring the current percentage that is calculated in the loop. and embedding the style in the tag

 
Comment by zero
2008-02-24 02:30:17

Nice tut, I always wandered how this stuff worked. Not as hard as I thought it would be.

 
Comment by Richard
2008-03-19 11:08:06

Was just researching tagging to incorporate in a new web site I am building. I never thought of utilising search statistics to affect the ranking of tags. Very nice, I will use it to supplement how I intend to do this myself.

 
Comment by Kim Burgess
2008-03-31 10:37:45

@ Steve [re: css formatting ordered list]
just set the display type of the li's to 'inline' and they'll act like span's

@ Chirs [re: font percentage calculation]
its quite simple - you use the percentage to calculate where it should be placed within your font percentage boundaries then add the lower bound:

// tag font size ranges (in percent)
$minSize = 75;
$maxSize = 250;

$tagSize = (floor($v2 / $maximum) * ($maxSize - $minSize)) + $minSize

 
Comment by nawi
2008-04-16 13:55:43

good script, i have try

 
Comment by Fanzin
2008-04-22 07:01:16

Thanks a lot!

 
Comment by Magnus
2008-04-28 01:21:36

Thank you for this very helpful tutorial.

 
Comment by Bassel Safadi
2008-04-29 23:49:31

Thanks a lot Steve,
this is what I call the nice looking functional code,
I'll use it in my upcoming free cms (Aikicms),
if you allow me

Comment by Steve
2008-05-15 17:23:54

No problems Bassel.

 
 
Comment by Maike
2008-05-17 10:53:01

thank you, this has been very useful

 
Comment by Alex Osborn
2008-05-19 02:18:09

Great post, nice concise outline, well formatted code - good work.

Had just been asked by a client to include a cloud in their site, came across this method and had one up in less than an hour, including css formatting and rewriting some of the code for percentage based resizes and to pass along a third parameter (url).

There was a comment before asking how to add the url in, so i'll just paste the change I made:


while($row = mysql_fetch_array($articleRow))
{
$title = $articleRow["Title"];
$score = $articleRow["Score"];
$id = $articleRow["ArticleID"];
$titles[] = array( Title => $title, Score => $score, Id => $id );
}

This way you can remove the second foreach loop, and can call the desired attribute through $v["Title"], or however you name your variables.

Comment by Steve
2008-05-23 17:35:57

Thanks for your feedback Alex, I have used it to revise and improve my code.

 
 
Comment by Deepak Subscribed to comments via email
2008-06-13 09:34:29

That was a great post. Thank you, Steve.
I am a newbie to web development. I have a small doubt.
Can we somehow control the tag cloud. I mean, if I have a university search page, and someone wants to deface it, he/she could enter an obscene search term a 1000 times and it will always remain the largest tag in the cloud.

Comment by Steve
2008-06-13 10:47:15

Hi Deepak,

Yes you definitely can filter out "bad words". An implementation i've used before is to just create an array of distasteful words, then as you are processing the search, check if (in_array($search_term, $bad_words)) show an error to the user and do not add the term to the search table.

 
 
Comment by linuxownzu
2008-06-21 02:13:00

great article. an improvement I made was to use a database call to set the maximum field rather than hard coding it

$query = "SELECT max(counter) as maxcounter from searches order by date desc, counter desc;";
$result = $db1->Query($query);
$arr_result = $db1->FetchArray($result);
return $arr_result[0]['maxcounter'];

Thanks

 
Comment by mirela
2008-07-12 02:27:58

Great tutorial for a beginner. Thank you very much Mr. Steve

 
Comment by Kasper Subscribed to comments via email
2008-07-17 18:45:17

Nice stuff you put together. However, I can't stop wondering if the term "tag" is appropriate, since none of your elements in the cloud are tags. They are search words, and thus the term "search cloud" is more appropriate. Anyways, I'm only being pedantic because I would have loved to had seen an implementation of actual tags.

 
Comment by Patato
2008-08-04 19:29:01

If you execute the query:

SELECT term, counter FROM search ORDER BY counter DESC LIMIT 30

you can be sure that maximum counter is in the first row of your result, so just read it ;)

 
Comment by Khuram
2008-09-03 23:17:49

Inspite of shuffle, I use this SQL

select * from
(select term, count(term) as cnt
from tbl_search_terms
group by term
order by cnt desc
limit 25
) subqTerms
order by term asc

 
Comment by Dominik Subscribed to comments via email
2008-09-05 19:17:20

Nice Post... I'm thinking of implementing such a tag cloud for various artists on my lyrics page. It would be interesting, if someone knew how to tell google or some other search engine bot the relevance of some certain tag. I know it's possible using sitemaps and the priority tag... does google parse the css?

regards
dominik

Comment by Steve
2008-09-07 23:03:38

nah I don't think they parse css, only interest is in HTML like h1, h2 etc.

 
 
2008-10-07 17:43:35

I have to add a tags searcher on one of my sites. I do not know ( now) how to make the sql. It is a nice article about usual cloud tags.

 
Name (required)
E-mail (required - never shown publicly)
URI
Subscribe to comments via email
Your Comment (smaller size | larger size)
You may use <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> in your comment.

Trackback responses to this post