'Catagory Lister 2',
'pi_version' => '1.02 - 10/26/2005',
'pi_author' => 'Jeff Barsky',
'pi_author_url' => 'http://www.miasmaofmusings.com',
'pi_description' => 'Make a more configurable catagory listing.',
'pi_usage' => cat_lister::usage()
);
class Cat_lister { // Open Class
var $return_data = '';
function Cat_lister() { // Open Cat_lister Function
// -- Section 1 -- Variables and Validation
// Set Globals and Variables
global $TMPL, $DB, $LOC;
$return = '';
$oops = '';
$category = array();
$tree = array();
$sort_order = '';
// Bring in Parameters and Tag Template
$custom_order = (!$TMPL -> fetch_param('custom_order') ) ? "DEF" : $TMPL -> fetch_param('custom_order') ;
$sort_order = (!$TMPL -> fetch_param('sort_order') ) ? "DEF" : $TMPL -> fetch_param('sort_order') ;
$sort_field = (!$TMPL -> fetch_param('sort_field') ) ? "DEF" : $TMPL -> fetch_param('sort_field') ;
$display_style = (!$TMPL -> fetch_param('display_style')) ? "NLevel" : $TMPL -> fetch_param('display_style') ;
$style_def_L = (!$TMPL -> fetch_param('style_def_L') ) ? "" : " ".$TMPL -> fetch_param('style_def_L');
$style_def_I = (!$TMPL -> fetch_param('style_def_I') ) ? "" : " ".$TMPL -> fetch_param('style_def_I');
$p_seperator = (!$TMPL -> fetch_param('p_seperator') ) ? " - " : $TMPL -> fetch_param('p_seperator') ;
$hide_empties = (!$TMPL -> fetch_param('hide_empties') ) ? "0" : $TMPL -> fetch_param('hide_empties') ;
$warnings = (!$TMPL -> fetch_param('warnings') ) ? "0" : $TMPL -> fetch_param('warnings') ;
$max_depth = (!$TMPL -> fetch_param('max_depth') ) ? "0" : $TMPL -> fetch_param('max_depth') ;
$max_list = (!$TMPL -> fetch_param('max_list') ) ? "0" : $TMPL -> fetch_param('max_list') ;
$date_format = (!$TMPL -> fetch_param('date_format') ) ? "m/d/Y" : $TMPL -> fetch_param('date_format') ;
$tagdata = $TMPL -> tagdata;
// Help out "uninformed" users / Explode Custom Order
$custom_order = ereg_replace('[:space:]', '', $TMPL -> fetch_param('custom_order'));
$custom_order = ereg_replace('[:punct:]', '|', $custom_order);
$custom_order = explode('|', $custom_order);
// -- Section 2 -- Queries and Extracted Data
// Start weblog_id block
if (!$TMPL -> fetch_param('weblog')){
$oops .= "WARNING: No Weblog name provided, using default of 'weblog1'.
\n";
$weblog = "weblog1";
} else {
$weblog = $TMPL -> fetch_param('weblog');
}
$query = $DB->query("SELECT weblog_id, cat_group FROM exp_weblogs WHERE blog_name = '".$DB->escape_str($weblog)."'");
if ($query ->num_rows == 0) {
// First Bail Out Point
$oops .= "FATAL ERROR: Weblog not found, please check to be sure the weblog name you supplied is valid.
\n";
return $oops;
}
$weblog = $query -> result[0]['weblog_id'];
$catgroup = $query -> result[0]['cat_group'];
// End weblog_id block
// Now we need to get data: Get Catagory Data and start collect
$sql = "SELECT cat_id, group_id, parent_id, cat_name, cat_order, cat_description, cat_image
FROM exp_categories
WHERE group_id = ".$catgroup."
ORDER BY parent_id, cat_order";
// Run first query
$query = $DB->query($sql);
// Collect initial data
foreach ($query->result as $row) {
$category[$row['cat_id']] = array(
'cid' => $row['cat_id'],
'parent' => $row['parent_id'],
'order' => $row['cat_order'],
'grp' => $row['group_id'],
'name' => $row['cat_name'],
'cat_desc' => (($row['cat_description']) ? $row['cat_description'] : "0" ),
'cat_image' => (($row['cat_image']) ? $row['cat_image'] : "0" ),
'total_e' => "0",
'total_c' => "0",
'l_e_date' => "0",
'l_c_date' => "0",
'entries' => "0",
'comments' => "0",
'nest_lvl' => "0",
'nest_list' => "0",
'ps_name' => "0"
);
}
// Now we need to get even MORE data
$sql = "SELECT exp_category_posts.entry_id, cat_id, weblog_id, entry_date, comment_total, recent_comment_date
FROM exp_category_posts, exp_weblog_titles
WHERE exp_category_posts.entry_id = exp_weblog_titles.entry_id
AND exp_weblog_titles.weblog_id = ".$weblog ;
// Run second query
$query = $DB->query($sql);
// Put this data into the "Category" collection
foreach($query -> result as $row){
$category[$row['cat_id']]['entries']++;
$category[$row['cat_id']]['total_e']++;
$category[$row['cat_id']]['comments'] += $row['comment_total'];
$category[$row['cat_id']]['total_c'] += $row['comment_total'];
$category[$row['cat_id']]['l_e_date'] =
($category[$row['cat_id']]['l_e_date'] >= $row['entry_date']) ?
$category[$row['cat_id']]['l_e_date'] : $row['entry_date'];
$category[$row['cat_id']]['l_c_date'] =
($category[$row['cat_id']]['l_c_date'] >= $row['recent_comment_date']) ?
$category[$row['cat_id']]['l_c_date'] : $row['recent_comment_date'];
}
// Time to manipulate object.
foreach ($category as $c){
$parent = $c['parent'];
$category[$c['cid']]['nest_lvl']++;
$category[$c['cid']]['nest_list'] = $category[$c['cid']]['cid'];
$category[$c['cid']]['ps_name'] = $category[$c['cid']]['name'];
$tree[$c['parent']][] = $c['cid'];
while ($parent != 0){
$category[$parent]['entries'] -= $category[$c['cid']]['total_e'];
$category[$parent]['comments'] -= $category[$c['cid']]['total_c'];
$category[$c['cid']]['nest_lvl']++;
$category[$c['cid']]['nest_list'] = $parent.",".$category[$c['cid']]['nest_list'];
$category[$c['cid']]['ps_name'] = $category[$parent]['name'].$p_seperator.$category[$c['cid']]['ps_name'];
$parent = $category[$parent]['parent'];
}
}
// -- Section 3 -- Sorting / Removing Empties / Limit Depth
if ($sort_order == "DEF") {
// Sort Hierarchically
$this -> jbHsort($parent = array(0), $tree, count($category), $outOrder = array());
// The $outOrder array is returned by reference
foreach($outOrder as $key => $val){ $cat[] = $category[$val]; }
if ($hide_empties){
$ntemp = array();
foreach ($cat as $row){
if ($row['entries'] != 0 or
$row['total_e'] != 0) {
$ntemp[] = $row;
}
}
$category = $ntemp;
unset($ntemp);
} else {
$category = $cat;
}
} elseif($sort_order == "CUSTOM"){
// Sort Custom Order
foreach($custom_order as $val){
$cat[] = $category[$val];
}
if ($hide_empties){
$ntemp = array();
foreach ($cat as $row){
if ($row['entries'] != 0) {
$ntemp[] = $row;
}
}
$category = $ntemp;
unset($ntemp);
} else {
$category = $cat;
}
} else {
// Sort Ascending/Descending on field
foreach($category as $row){ $temp[] = $row; }
$cat = $this -> jbMDAsort($temp, $sort_field, $sort_order);
if ($hide_empties){
$ntemp = array();
foreach ($cat as $row){
if ($row['entries'] != 0) {
$ntemp[] = $row;
}
}
$category = $ntemp;
unset($ntemp);
} else {
$category = $cat;
}
}
unset($cat, $ntemp);
// Limit Length
if ($max_list){
$category = array_slice($category, 0, $max_list);
}
// Limit Depth
if ($max_depth){
foreach ($category as $row){
if ($row['nest_lvl'] <= $max_depth){
$cat[] = $row;
}
}
$category = $cat;
}
// -- Section 4 -- Data Formatting and Output
// HTML List Styles
$listo = ""; $listc = "";
if ($display_style == "NListO"){ $listo = "
"; $listc = "
"; }
if ($display_style == "NListU"){ $listo = ""; }
if ($listo){ $return .= $listo; }
$prevNest = 1;
// Prepare data for output
foreach ($category as $row) {
$row['l_e_date'] = ($row['l_e_date'] != 0) ? date($date_format, $row['l_e_date']) : "N/A" ;
$row['l_c_date'] = ($row['l_c_date'] != 0) ? date($date_format, $row['l_c_date']) : "N/A" ;
$tagdata = $TMPL->tagdata;
// Nested listing information added
if ($listo){
if ($prevNest != $row['nest_lvl']){
if ($prevNest < $row['nest_lvl']){
$return .= $listo;
$prevNest++;
} else {
$back = $prevNest - $row['nest_lvl'];
for ($x = 0; $x < $back; $x++){ $return .= $listc; }
$prevNest = $row['nest_lvl'];
}
}
}
if ($listo) { $tagdata = "".$tagdata."\n"; }
// Interpolate data
foreach ($TMPL->var_single as $key => $val) {
$tagdata =& $TMPL->swap_var_single ($key, $row[$key], $tagdata);
}
// Add output to string
$return .= $tagdata;
}
// Close Nested Lising
if ($listc){ for ($x = 0; $x < $row['nest_lvl']; $x++){ $return .= $listc; } }
// Output all the data for output
$this -> return_data = $return;
} // Close Cat_lister Function
// Function - jbHsort
function jbHsort($parent, $tree, $stop, &$outOrder){
if (count($outOrder) != $stop){
if ((array_key_exists($parent[0], $tree)) && (count($tree[$parent[0]]) != '0')){
$outOrder[] = $child = array_shift($tree[$parent[0]]);
array_unshift($parent, $child);
$this -> jbHsort($parent, $tree, $stop, $outOrder);
} else {
array_shift($parent);
$this -> jbHsort($parent, $tree, $stop, $outOrder);
}
}
}
// Function - jbMDAsort
function jbMDAsort($usa, $f, $dir){
// If this seems redundant, it's not, it's faster.
$sa = $usa;
if ($dir == "ASC"){
for ($i = 0; $i < sizeof($sa) - 1; $i++) {
for ($j = 0; $j < sizeof($sa) - 1 - $i; $j++){
if (strtolower($sa[$j][$f]) > strtolower($sa[$j+1][$f])) {
$tmp = $sa[$j];
$sa[$j] = $sa[$j+1];
$sa[$j+1] = $tmp;
}
}
}
} else {
for ($i = 0; $i < sizeof($sa) - 1; $i++) {
for ($j = 0; $j < sizeof($sa) - 1 - $i; $j++){
if (strtolower($sa[$j][$f]) < strtolower($sa[$j+1][$f])) {
$tmp = $sa[$j];
$sa[$j] = $sa[$j+1];
$sa[$j+1] = $tmp;
}
}
}
}
return $sa;
}
// Function - Usage
function usage() { // Open Usage
ob_start();
?>
For a complete description of this plugin with complete feature lists and descriptions,
complete list of parameters and descriptions, better looking samples, additional available
functions, future enhancements, please download the associated Word Doc from:
http://www.miasmaofmusings.com/index.php/weblog/dl_cl/
------------------------------------
WHAT THIS DOES:
------------------------------------
Cat_lister replaces the basic functionality of the built-in Expression
Engine tag:
{exp:weblog:categories weblog="{master_weblog_name}"}
and offers several new features not possible with the built in tag.
Cat_lister allows for a very flexible way of displaying your categories in
the style you want to use. Categories can be displayed alphabetically,
ranked, by date, nested, and pseudo nested (see below). Categories can be
sorted ascending, descending, hierarchical, or by custom order. Category
lists can be limited in length (good for rankings), limited to depth
(see below), or without (intelligently evaluated, see below) “empty”
categories included.
Also included, and in fact the original reason for the plugin in the first
place, are entry and comment statistics. Statistic include entries per
category, comments per category, total entries per categories (include
subcategories), and total comments per categories (including subcategories).
In addition, several formatting options were not available with the original
tag. You can now specify as HTML Ordered or Unordered list, plain list (no
formatting added), or with included “Nesting Levels” (see below).
With these options you should be able to create the category list that you
want with little or no programming. It is hoped that this plugin will
reduce your time and head scratching on working out the custom queries
and sorts.
------------------------------------
New Features:
------------------------------------
Pseudo Nested List
Hierarchical Depth Limiting
Intelligently Hidden (sub)Categories
List Length Limiting
Nesting Levels
Entry and Comment Statistics
------------------------------------
Features:
------------------------------------
Custom Ordering
Custom Sorting
Display Styles
------------------------------------
BASIC USAGE:
------------------------------------
Basic usage for the Cat_lister plugin is rather straightforward. The following
example would create a simple list of categories with the number of entries and
comments within each category:
{exp:cat_lister weblog="{master_weblog_name}"}
{name}
({entries}/{comments})
{/exp:cat_lister}
Resulting in a list this may look something like this:
Entertainment (45/443)
News (12/203)
Personal (8/45)
Politics (19/392)
Simple and to the point, this example assumes that you do not have any subcategories,
but one simple change could take that into account and show off the power of the
"Pseudo-Nested" ability:
{exp:cat_lister weblog="{master_weblog_name}"}
{ps_name}
({entries}/{comments})
{/exp:cat_lister}
Now if you have subcategories, you may have a list like this:
Entertainment (45/443)
Entertainment - Movies (20/443)
Entertainment - Television (6/443)
Entertainment - Television - Comedy (2/443)
Entertainment - Television - Drama (4/443)
Entertainment - Theater (3/443)
News (12/203)
Personal (8/45)
Personal - Dating (3/45)
Personal - Career (2/45)
Politics (19/392)
The advantage of the "Pseudo Nested" list is that you will not have to provide
a huge amount of CSS definitions to have it display well. It is a fast and easy
why to display your hierarchical list and not think about it.
To turn the above tag into an HTML ordered list you may want to use the
following example:
{exp:cat_lister weblog="{master_weblog_name}" display_style="NListO"}
{name}
({entries}/{comments})
{/exp:cat_lister}
And the resulting list would look like this:
1. Entertainment (45/443)
a. Movies (20/443)
b. Television (6/443)
i. Comedy (2/443)
ii. Drama (4/443)
c. Theater (3/443)
2. News (12/203)
3. Personal (8/45)
a. Dating (3/45)
b. Career (2/45)
4. Politics (19/392)
At this point you will want to add some CSS definitions to allow you to format
the list the way you want it. This is just the simplest of samples.
Advanced usage is listed below.
------------------------------------
CHEAT SHEET:
------------------------------------
Available Fields for tag creation:
{name} = Category Name
{ps_name} = Category Pseudo Name
{cat_desc} = Category Description
{cat_image} = Category Image File Name
{entries} = Total Entries Per Category
{comments} = Total Comments Per Category
{total_e} = Total Entries, Including Subcategories
{total_c} = Total Comments, Including Subcategories
{l_e_date} = Last Entry Date
{l_c_date} = Last Comment Date
{nest_lvl} = Current Nesting Level
These are available, but should not be needed except when debugging:
{nest_list} = Current Nesting List (Show a list of the CIDs to root
{cid} = Category ID Number
{parent} = Parent ID Number
{order} = Hierarchical Ordering Number
{grp} = Category Group Number
Available Parameters:
weblog = "{master_weblog_name}" (REQUIRED)
custom_sort = "1|3|6|4" (Optional)
sort_field = "[field]" (Optional, see list above)
sort_order = "ASC" (Optional, DEF, CUSTOM, DESC are available but not needed)
display_style = "NListO" or "NListU" (Optional)
style_def_L = "class='listStyle'" (Optional)
style_def_I = "class='itemStyle'" (Optional)
p_seperator = " - " (Default is as shown)
max_depth = "5" (Default is 0 which shows all)
max_list = "10" (Default is 0 which shows all)
date_format = "m/d/Y" (Default is as shown)
hide_empty = "yes" (Default is as shown)
------------------------------------
ADVANCED USAGE:
------------------------------------
(These samples look MUCH better when run as the alignment will be correct. This is
examples to give you ideas.)
The CSS for Nested Level output:
(Change to suit your application of course)
This will allow for a nested list up to three levels deep. Beyond that, you will have
to add to the style definitions. Here are three samples that I think you will find useful:
Example One:
This example is a simple version of “Nesting Levels” and creates the sample below it. In
theory it should look very similar to the above examples but without the “List” tags in
the underlying code. From a modern coding standpoint this is fairly advance in that it
uses all CSS to create the effect. There are no tables and of course no lists to get in
the way of the display.
{exp:cat_lister weblog="{master_weblog_name}"}
{/exp:cat_lister}
Entertainment (45/443)
Movies (20/201)
Television (6/52)
Comedy (2/18)
Drama (4/28)
Theater (3/80)
News (12/203)
Personal (8/45)
Dating (3/12)
Career (2/19)
Politics (19/392)
Want to add a bullet in front of each, change the “{name}” to “• {name}” and there
you go. Easy, instant bulleted, hierarchical list.
Example Two:
OK, so you do not like the crowded nature of the list. The numbers are too close to the
categories and you want to see them maybe all the way to the left. Why not try this:
{exp:cat_lister weblog="{master_weblog_name}"}
{/exp:cat_lister}
- Entertainment (45/443)
- Movies (20/201)
- Television (6/52)
- Comedy (2/18)
- Drama (4/28)
- Theater (3/80)
- News (12/203)
- Personal (8/45)
- Dating (3/12)
- Career (2/19)
- Politics (19/392)
When the above is displayed in a page this will look nice and professional
and so simple to do.
Example Three:
How about using the nesting level with the “Pseudo Name” convention? You can get
an interesting effect with that. In this case you will not be using the “Nesting
Level” as a way of indenting, but a way of shading to denote the depth of the
selection adding a visual clue as to the location of the category.
The CSS for this example:
{exp:cat_lister weblog="{master_weblog_name}" p_separator=" - "}
{/exp:cat_lister}
Entertainment (45/443)
Entertainment - Movies (20/201)
Entertainment - Television (6/52)
Entertainment - Television - Comedy (2/18)
Entertainment - Television - Drama (4/28)
Entertainment - Theater (3/80)
News (12/203)
Personal (8/45)
Personal - Dating (3/12)
Personal - Career (2/19)
Politics (19/392)
By combining the parameter, styles and available information (nesting level) you
can create just about any output you can think of. Already I am thinking about
rollover possibilities and background images and the like making this plugin
very versatile indeed.
------------------------------------
NOTES ABOUT THIS PLUGIN:
------------------------------------
This is a rather feature rich plugin and it will only get more so as I develop it (see the
future features list above) and I am one man. I have debugged this to the best of my resources,
but since EE is so mutable there may be things I have not thought of or have not tested for.
I will say this, I have not tested for uncategorized entries. If you do not categorize entries,
I do not know what will happen. I suggest that you have some default category for all entries,
even if you make a default category of "Unfiled" or some such. This makes a lot of sense and
is proper data management.
The plugin itself comes very tersely commented, just enough to follow along what is generally
happening. I happen to be one of those people who over comment everything for my own edification
(and a very poor memory). That being the case I strip the comments and testing code from the
release software. If you would like a copy of the code with all my comments (and there are a lot)
then please let me know and I will send you a copy.
For a complete description of this plugin with complete feature lists and descriptions,
complete list of parameters and descriptions, better looking samples, additional available
functions, future enhancements, please download the associated Word Doc from:
http://www.miasmaofmusings.com/index.php/weblog/dl_cl/
------------------------------------
ADDITIONAL FUNCTIONS:
------------------------------------
There are two additional functions with this class. For more information about them, please
download the Word Doc for this plugin at:
http://www.miasmaofmusings.com/index.php/weblog/dl_cl/
The two functions are
Cat_lister::jbMDAsort which will take a multidimentional array and sort it on a provided
field and in a particular direction.
Cat_lister::jbHsort which will take a hierarchical tree array and output a hierarchical
order to be applied to an array. (This function is usable with special prep, so definately
see the doc on this one.)
------------------------------------
Revision History:
------------------------------------
1.02 - (10/26/2005) Bug Fixes and Documentation Fixes (there was a version issue I was not
aware of and became clear quickly.
1.01 - (10/13/2005) Added a security feature, thanks Paul Burdick for the catch.
1.0 - (10/10/2005) Completed all major coding, removed various bugs, cleaned
up the code and the inline comments.
------------------------------------
COPYRIGHT INFORMATION:
------------------------------------
(c) 2005, Jeff Barsky and Miasma of Musings. You may use and distribute this plugin as you
wish, but please leave original creator information in the file. If you have questions
or suggestions, please email me at:
admin@miasmaofmusings.com
or
jbarsky@visual-impact.com
If you base another plugin on this software, please feel free to drop all information
if you change it more than 50% or so. Otherwise, I would appreciate it if this
information were to stay with the plugin.
Author: Jeff Barsky
Originating Site: http://www.miasmaofmusings.com
Version 1.02 : 10/26/2005
--END--