<?php
/*
Plugin Name: Category Tagging
Plugin URI: http://sw-guide.de/wordpress/category-tagging-plugin/
Description: Tagging with categories. Display a tag cloud and related posts.
Version: 1.2
Author: Michael Woehrer
Author URI: http://sw-guide.de
*/

/*	----------------------------------------------------------------------------
 	    ____________________________________________________
       |                                                    |
       |                 Category Tagging                   |
       |                 Michael Woehrer                   |
       |____________________________________________________|

	 Copyright 2006  Michael Woehrer  (michael dot woehrer at gmail dot com)

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    --------------------------------------------------------------------------*/


function cattag_tagcloud(
	$min_scale = 6,
	$max_scale = 24,
	$min_include = 0,
	$sort_by = 'NAME_ASC',
	$exclude = '',
	$element = '<li><a rel="tag" href="%link%" title="%description% (%count%)" style="font-size:%size%pt">%title%</a></li>'
	)
{
	$sort_by = strtoupper($sort_by);

	// *************************************************
	// Get categories and put into array
	// *************************************************
	
	// If sorting is by name, descending...
	$sort_list_cats = 'asc';
	if ($sort_by == 'NAME_DESC') $sort_list_cats = 'desc';

	$cats = list_cats(true, 'all', 'name', $sort_list_cats, '', false, false, true, true, true, true, true, false, true, '', '', $exclude, false);
	$catsArray = explode("\n", $cats);

	// *************************************************
	// Create clean array out of the cat array	
	// *************************************************
	$resultArray = array();
	$count = 0;
	foreach ($catsArray as $cat_loop) {
		if (! empty($cat_loop)) {
			// Get link
			eregi("a href=\"(.+)\" ", $cat_loop, $regs);
			$resultArray[$count]['link'] = $regs[1];

			// Get title
			eregi("title=\"(.+)\"", $cat_loop, $regs);
			$resultArray[$count]['title'] = $regs[1];

			// Get name and number of cat entries
			$cat_loop = trim(strip_tags($cat_loop));
			eregi("(.*) \(([0-9]+)\)$", $cat_loop, $regs);
			$resultArray[$count]['name'] = $regs[1];
			$resultArray[$count]['count'] = $regs[2];

			if ($regs[2] >= $min_include) {
				// Set the min and max number of cat entries
				if ( ( ! isset($count_min) ) or ($regs[2] < $count_min) ) { $count_min = $regs[2]; }
				if ( ( ! isset($count_max) ) or ($regs[2] > $count_max) ) { $count_max = $regs[2]; }				
			} else {
				// Remove array element if the number of posts in this category is smaller than the min value
				// We do this now since the number of posts was not available at the beginning of this foreach loop...
				unset($resultArray[$count]);
			}
			$count++;
		}
	}

	// *************************************************
	// Sort...
	// *************************************************
	switch ($sort_by) {
		case 'WEIGHT_ASC':
			$resultArray = cattag_aux_sortmddata($resultArray,'count','ASC','num');
			break;
		case 'WEIGHT_DESC':
			$resultArray = cattag_aux_sortmddata($resultArray,'count','DESC','num');
			break;
		case 'RANDOM':
			shuffle($resultArray);
			break;
	}

	// *************************************************
	// Scale font
	// *************************************************
	$spread_current = $count_max - $count_min; 
	$spread_default = $max_scale - $min_scale;
	if ($spread_current <= 0) { $spread_current = 1; };
	if ($spread_default <= 0) { $spread_default = 1; }
	$scale_factor = $spread_default / $spread_current;


	// *************************************************
	// Create result
	// *************************************************
	$result = '';
	foreach ($resultArray as $result_loop) {
		// font scaling		
		$final_font = (int) (($result_loop['count'] - $count_min) * $scale_factor + $min_scale);

		// Generate output element
		$element_loop = str_replace('%link%', $result_loop['link'], $element);
		$element_loop = str_replace('%title%', $result_loop['name'], $element_loop);
		$element_loop = str_replace('%description%', $result_loop['title'], $element_loop);
		$element_loop = str_replace('%count%', $result_loop['count'], $element_loop);
		$element_loop = str_replace('%size%', $final_font, $element_loop);
		$result .= $element_loop . "\n";
	}

	$result = "\n" . '<!-- Tag Cloud, generated by \'Category Tagging Plugin\' - http://sw-guide.de/ -->' . "\n" . $result; // Please do not remove this line.
	return $result;
}


function cattag_related_posts(
	$limit = 5,
	$display_posts = true,
	$display_pages = false,
	$before = '<li>',
	$after = '</li>',
	$notfound = false,
	$order = 'DATE_DESC',
	$exclude_ids = ''
) {

	global $wpdb,$post;	// WordPress globals

	// *************************************************
	// Prepare selection of posts and pages
	// *************************************************
	if ( ($display_posts === true) AND ($display_pages === true) ) {
		// Display both posts and pages
		$poststatus = "IN('publish', 'static')";
	} elseif ( ($display_posts === true) AND ($display_pages === false) ) {
		// Display posts only
		$poststatus = "= 'publish'";
	} elseif ( ($display_posts === false) AND ($display_pages === true) ) {
		// Display pages only
		$poststatus = "= 'static'";
	} else {
		// Nothing can be displayed
		return $notfound;
	}

	// *************************************************
	// Prepare exlusion of categories
	// *************************************************	
	$exclude_ids = preg_replace('/[^0-9,]/','',$exclude_ids);	// remove everything except 0-9 and comma
	$exclude_ids_sql = '';
	if ($exclude_ids != '') {
		$exclude_ids_sql = 'AND post2cat.category_id NOT IN(' . $exclude_ids . ')';
	}

	// *************************************************
	// Put the category IDs into a comma-separated string
	// *************************************************
	$catsList = '';
	$count = 0;
	foreach((get_the_category()) as $loop_cat) { 
		// Add category id to list
		if ($count == 0) {
			$catsList = $loop_cat->cat_ID;
		} else {
			$catsList = $catsList . ',' . $loop_cat->cat_ID;
		}
		$count++;
	}

	// *************************************************
	// Prepare order
	// *************************************************
	switch (strtoupper($order)) {
		case 'RANDOM':
			$order_by = 'RAND()';
			break;
		default:	// 'DATE_DESC'
			$order_by = 'posts.post_date DESC';
	}

	// *************************************************
 	// SQL query. DISTINCT is here for getting a unique result without duplicates
 	// *************************************************
	$queryresult = $wpdb->get_results("SELECT DISTINCT posts.ID, posts.post_title
							FROM $wpdb->posts posts, $wpdb->post2cat post2cat
							WHERE posts.ID <> $post->ID
							AND posts.post_status $poststatus
							AND posts.ID = post2cat.post_id
							AND post2cat.category_id IN($catsList)
							$exclude_ids_sql
							ORDER BY $order_by 
							LIMIT $limit
							");

	// *************************************************
	// Return the related posts
	// *************************************************
	$result = '';
	if (is_array($queryresult)) {
		foreach($queryresult as $tag_loop) {
			$result .= $before . '<a href="' . get_permalink($tag_loop->ID) . '" title="' . $tag_loop->post_title . '" id="post-' . $tag_loop->ID . '">' . $tag_loop->post_title . '</a>' . $after . "\n";
		}
		$result = "\n" . '<!-- Related Posts, generated by \'Category Tagging Plugin\' - http://www.sw-guide.de/ -->' . "\n" . $result; // Please do not remove this line.
		return $result;
	} else {
		return $notfound;
	}

}

//##############################################################################
// Additional functions
//##############################################################################
function cattag_aux_sortmddata($array, $by, $order, $type){
	// Sort a one level deep multidimensional array
	// Source: http://de2.php.net/manual/de/function.array-multisort.php#61334
	//		$array: the array you want to sort
	//		$by: the associative array name that is one level deep
	//				example: name
	//		$order: ASC or DESC
	//		$type: num or str

	$sortby = "sort$by"; //This sets up what you are sorting by
	
	$firstval = current($array); //Pulls over the first array
	
	$vals = array_keys($firstval); //Grabs the associate Arrays
	
	foreach ($vals as $init){
		$keyname = "sort$init";
		$$keyname = array();
	}
	//This was strange because I had problems adding
	//Multiple arrays into a variable variable
	//I got it to work by initializing the variable variables as arrays
	//Before I went any further
	
	foreach ($array as $key => $row) {
		foreach ($vals as $names) {
			$keyname = "sort$names";
			$test = array();
			$test[$key] = $row[$names];
			$$keyname = array_merge($$keyname,$test);
		}
	}
	
	//This will create dynamic mini arrays so that I can perform
	//the array multisort with no problem
	//Notice the temp array... I had to do that because I
	//cannot assign additional array elements to a
	//varaiable variable           
	
	if ($order == "DESC") {   
		if ($type == "num") {
			array_multisort($$sortby,SORT_DESC, SORT_NUMERIC,$array);
		} else {
			array_multisort($$sortby,SORT_DESC, SORT_STRING,$array);
		}
	} else {
		if ($type == "num") {
			array_multisort($$sortby,SORT_ASC, SORT_NUMERIC,$array);
		} else {
			array_multisort($$sortby,SORT_ASC, SORT_STRING,$array);
		}
	}
	
	//This just goed through and asks the additional arguments
	//What they are doing and are doing variations of
	//the multisort
	return $array;
}

?>