'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 = ""; $listc = ""; } 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}"}
{name} ({total_e}/{total_c})
{/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}"}
• {name}
({total_e}/{total_c})
{/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=" - "}
{ps_name}
({entries}/{comments})
{/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--