We needed subcategories for a site we are currently working on at achieve internet.
I found that it was pretty simple to add this functionality to joomla, as most of the work has already been done.
I made three small changes to com_content and four changes to the admin com_content
Since categories already have a parent_id field in the database, I went ahead and created two new categories, setting their parent id's to that of another category in the database.
This made the structure section 1 > existing category > new subcategory > new sub-subcategory.
When I went to check out what the front did, I found that it almost worked. The problem was that when you went to the section and any category, all of the categories in that section were listed.
This was a simple fix. I only had to add one line of code to two different functions. One change was in showCategory and one was in showSection of com_content
In /components/content.php in showSection() line 279 I added
Code:
. " AND a.parent_id = 0 "
so that when you view categories in a section, only top level categories display.
The block of code that I changed looks like:
Code:
// Main Query
$query = "SELECT a.*, COUNT( b.id ) AS numitems"
. "\n FROM #__categories AS a"
. "\n LEFT JOIN #__content AS b ON b.catid = a.id"
. $xwhere2
. "\n WHERE a.section = '$section->id'"
. "\n AND a.parent_id = 0 " //This is my new line
. $xwhere
. $access
. "\n GROUP BY a.id"
. $empty
. $empty_sec
. "\n ORDER BY $orderby"
Next, I fixed it so that when you view a category, the only sub categories that display are subcategories of that category.
In /components/content.php showCategory() around line 400, I changed the SQL query to only get child categories rather then list all categories in that section.
I added
Code:
. "\n AND c.parent_id = $id "
to the following block of code:
Code:
// get the list of other categories
$query = "SELECT c.*, COUNT( b.id ) AS numitems"
. "\n FROM #__categories AS c"
. "\n LEFT JOIN #__content AS b ON b.catid = c.id "
. $xwhere2
. ( $noauth ? "\n AND b.access <= $gid" : '' )
. "\n WHERE c.section = '$category->section'"
. $xwhere
. ( $noauth ? "\n AND c.access <= $gid" : '' )
. "\n AND c.parent_id = $id " //This is my new line
. "\n GROUP BY c.id"
. $empty
. "\n ORDER BY c.ordering"
;
After I did this, I noticed one problem. If a category only had one subcategory, it would not display. This too, was a simple fix.
Starting at line 93 of /components/content.html.php in the method showContentList() I changed `count( $other_categories ) > 1)` to count( $other_categories ) > 0)
Here is the block of code:
Code:
<?php
// Displays listing of Categories
if ( ( ( count( $other_categories ) > 0 /*<- This was a 1*/ ) || ( count( $other_categories ) < 2 && count( $items ) < 1 ) ) ) {
if ( ( $params->get( 'type' ) == 'category' ) && $params->get( 'other_cat' ) ) {
HTML_content::showCategories( $params, $items, $gid, $other_categories, $catid, $id, $Itemid );
}
if ( ( $params->get( 'type' ) == 'section' ) && $params->get( 'other_cat_section' ) ) {
HTML_content::showCategories( $params, $items, $gid, $other_categories, $catid, $id, $Itemid );
}
}
?>
Now it worked just as I wanted it to... but for one detail. On the back end, I needed a way to select the the proper subcategory form a tree list so that I could tell what level I was putting the content in.
I used the treeSelectList() method in mosHTML to do this.
I modified administrator/components/com_content/admin.content.php
on lines 521 and 538 I replaced:
Code:
$lists['catid'] = mosHTML::selectList( $categories, 'catid', 'class="inputbox" size="1"', 'id', 'name' );
with
Code:
$lists['catid']=mosHTML::treeSelectList( $categories, 1, array(), 'catid', 'class="inputbox" size="1"', 'value', 'text', intval( $row->catid ) ) ;
The treeSelectList method needs the parent id of each list item, so I modified the preceding SQL statements to get the parent id. I just added ", parent_id as parent " to:
Code:
$query = "SELECT id, name, parent_id as parent "
. "\n FROM #__categories"
. "\n WHERE section = '$section->id'"
. "\n ORDER BY ordering"
;
$database->setQuery( $query );
AND line 522:
Code:
$query = "SELECT id, name, parent_id as parent "
. "\n FROM #__categories"
. $where
. "\n ORDER BY ordering"
In the newest joomla version, it was only in one place; line 498.
Code:
$query = "SELECT id, name, section, parent_id as parent "
. "\n FROM #__categories"
. "\n WHERE section IN ( '$section_list' )"
. "\n ORDER BY ordering"
;
That was all it took. Really, it was a pretty simple fix to what could be seen as a pretty big draw back to joomla. I have posted the modified files at
http://www.achieveinternet.com/blog/?p=7#more-7 . I am working with version 1.0.7 and the version I posted is from 1.0.8. so you may have to make a few more small changes. Feel free to download and use them, or integrate my changes into future releases or joomla.