Hemen hemen her sitede etiket bulutu ile karşılaşıyorsunuzdur. Ben de bu yazımda basit bir etiket bulutu yapımını anlatmaya çalışacağım.

Etiketler sitemizde yayınladığımız yazılarda yazılarımızı ifade ederler ve genelde bir kelimeden oluşurlar. Örneğin ben bu yazı için "etiket", "etiket bulutu", "tag", "tag cloud" şeklinde etiketler ekledim.

Etiket bulutu oluşturmak için elimizde etiketler ve bu etiketlerin kaç defa kullanıldığı bilgileri olmalıdır. Etiketlerin kaç defa kullandığı bilgisini etiketlerimizin yazı font büyüklüğünün belirlenmesinde kullanacağız. Peki bu verileri tutan veri tabanı tablolarımız nasıl olmalı ?

Etiket bulutu oluşturmak için 3 adet tablomuz bulunmaktadır. Bu tablolar "etiketler", "yazilar", "yazi_etiket_iliskileri" şeklindedir. Yazılarımızı "yazilar" tablosunda, etiketlerimizi "etiketler" tablosunda, etiketlerin hangi yazıya ait olduğunu ise "yazi_etiket_iliskileri" tablosunda tutacağız. Tablolarımız son görünümü aşağıdaki gibi olacak.

"yazilar" Tablosu

  • yazi_id
  • baslik
  • yazi

"etiketler" Tablosu

  • etiket_id
  • etiket
  • yazi_adedi

"yazi_etiket_iliskileri" Tablosu

  • yazi_id
  • etiket_id

Tablolarımız bu şekilde olacak. Sql kodlarını veriyorum.

CREATE TABLE `yazilar` (
    `yazi_id`  int(11) UNSIGNED NOT NULL AUTO_INCREMENT ,
    `baslik`  text CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL ,
    `yazi`  text CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL ,
    PRIMARY KEY (`yazi_id`)
);

CREATE TABLE `etiketler` (
    `etiket_id`  int(11) UNSIGNED NOT NULL AUTO_INCREMENT ,
    `etiket`  varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL ,
    `yazi_adedi`  int(11) UNSIGNED NOT NULL ,
    PRIMARY KEY (`etiket_id`)
);

CREATE TABLE `yazi_etiket_iliskileri` (
    `etiket_id`  int(11) UNSIGNED NOT NULL ,
    `yazi_id`  int(11) UNSIGNED NOT NULL 
)
;

Sql kodumuzu yazmadan önce "etiketler" tablosundaki yazi_adedi adlı sütunu neden kullandığımız açıklamak istiyorum. Ben yazıyı eklerken kullandığım etiketin yazı adedini güncelleyerek etiketler tablosunda tutmayı tercih ediyorum böylece sql sorgumuz sistemi fazla yormadan hızlı bir şekilde gerçekleşecektir. Aksi taktirde etiketlerinin kullanım adedini almak için sorguda join kullanmamız gerekecekki bu da sorguyu yavaşlatacaktır. Fakat siz dersenizki ben yazı eklerken etiket adedeni güncellemekle uğraşamam yazi_adedi sütununu kaldırabilirsiniz. İsterseniz "yazi_adedi" sütunu kullandığımızda ve kullanmadığımızdaki sorgularımızı yazalım.

"yazi_adedi" sütunu olduğunda sql sorgusu

SELECT etiket_id,etiket, yazi_adedi FROM etiketler
ORDER BY yazi_adedi DESC
LIMIT 10

"yazi_adedi" sütunu olmadığında sql sorgusu

SELECT e.etiket_id,e.etiket, COUNT(*) AS yazi_adedi FROM etiketler AS e
INNER JOIN yazi_etiket_iliskileri AS yei ON k.etiket_id=yei.etiket_id
GROUP BY yei.etiket_id
ORDER BY yazi_adedi DESC
LIMIT 10

"yazi_adedi" sütunu kullanıp kullanmamak artık size kalmış olaydır.

Ben yine de "yazi_adedi" sütununu kullanacak olan arkadaşlarımız için yeni yazı elediğimizde veya güncellediğimizde o yazıya eklediğimiz etiketlerin yazi_adedi'ni güncelleyen sorguyu veriyorum.

UPDATE etiketler as e SET yazi_adedi=(
        SELECT COUNT(*)
        FROM yazi_etiket_iliskileri as yei
        INNER JOIN yazilar as y ON yei.yazi_id=y.id
        WHERE yei.etiket_id=e.etiket_id
)
WHERE e.etiket_id IN ('16', '21')

Yazı adedini güncelleyen sorgmuzda where koşulunda vermiş olduğum '16' ve '21' değerleri yazıya eklemiş olduğumuz etiketlerin etiket id'dir yani sizin sorgunuzda değişecek olan kısım.

Etiket bulutu oluşturan php fonksiyonumuz.

<?php

function etiket_bulutu($etiketler = array(), $ile_birlestir=' '){
	$max_adet = 0 ;
	//en çok kullanılan etiketin yazı adedini alıyoruz
	foreach($etiketler as $index => $etiket)
	{
		if ($etiket['yazi_adedi'] > $max_adet)
			$max_adet = $etiket['yazi_adedi'];
	}
	unset ($etiket);

	$etiket_bulutu = array();
	//Bütün etiketlerin font büyüklüğünü belirleyen for döngüsü
	foreach($etiketler as $etiket)
	{
		//etiketin yazı adedini maksimum yazı adedine bölerek yüzdesini buluyoruz
		$yuzde = ($etiket['yazi_adedi']/$max_adet)*100;
		
		// Yüzde aralıklarına göre font büyüklüğü belirleniyor
		if($yuzde >= 98)      $size = 2.0;
		else if($yuzde >= 80) $size = 1.7;
		else if($yuzde >= 70) $size = 1.6;
		else if($yuzde >= 60) $size = 1.5;
		else if($yuzde >= 50) $size = 1.3;
		else if($yuzde >= 40) $size = 1.1;
		else if($yuzde >= 30) $size = 1.0;
		else if($yuzde >= 20) $size = 0.8;
		else if($yuzde >= 10) $size = 0.7;
		else if($yuzde >= 5)  $size = 0.7;
		else                  $size = 0.7;
       
                $etiket_bulutu[$etiket['etiket']] = '<a href="#etiket_linki" style="font-size: '.$size.'em" title="'.$etiket['yazi_adedi'].' adet yazı bulunmaktadır" >'.$etiket['etiket'].'</a> ';
	}

	ksort($etiket_bulutu); //diziyi key değerlerine göre sırala
	return implode($ile_birlestir, $etiket_bulutu);
}

Bu fonksiyonumuz iki adet parametre alıyor. Birincisi etiket bulutu oluştururken kullanılacak olan etiketler, diğer parametremiz ise etiketlerin arasına koyulacak olan karakter.

Örnek Kullanım

$etiketler = array(
	array('etiket'=> 'etiket 1','yazi_adedi'=>5),
	array('etiket'=> 'etiket 2','yazi_adedi'=>3),
	array('etiket'=> 'etiket 3','yazi_adedi'=>1),
	array('etiket'=> 'etiket 4','yazi_adedi'=>6),
	array('etiket'=> 'etiket 5','yazi_adedi'=>10),
	array('etiket'=> 'etiket 6','yazi_adedi'=>3)
);

echo etiket_bulutu($etiketler, ' ');

Ben fonksiyonun örnek kullanımında etiketler dizisini elle oluşturdum ama siz o etiketleri veritabanından çekip benim verdiğim örnekte kullandığım dizi haline getirip fonksiyona parametre olarak göndermelisiniz.

Bu sistemi serkandaglioglu.com'da da kullanmaktayım. Sidebardaki etiket bulutunu burdaki yöntemle oluşturdum.

Elimden geldiğince mantığını anlatmaya çalıştım. Faydalı olması dileğiyle.