There is no built in function to hide categories that do not have products/stock. You can disable each category manually.
However, large websites this is never ideal. You would need to modify the Magento core slightly.
You will need to rewrite the Mage_Catalog_Block_Navigation block. There is 2 functions that control your categories.
1st function _renderCategoryMenuItemHtml() you will want to replace the loop
foreach ($children as $child) {
if ($child->getIsActive()) {
$activeChildren[] = $child;
}
}
with this:
foreach ($children as $child) {
if ($child->getIsActive() && $this->_hasProducts($child->entity_id)) {
$activeChildren[] = $child;
}
}
and then for the 2nd function renderCategoriesMenuHtml() replace the code
foreach ($this->getStoreCategories() as $child) {
if ($child->getIsActive()) {
$activeCategories[] = $child;
}
}
with this:
foreach ($this->getStoreCategories() as $child) {
if ($child->getIsActive() && $this->_hasProducts($child->entity_id)) {
$activeCategories[] = $child;
}
}
In the end create the function to check if a category has products. Products out of stock, are considered inactive.
protected function _hasProducts($category_id) {
$products = Mage::getModel('catalog/category')->load($category_id)
->getProductCollection()
->addAttributeToSelect('entity_id')
->addAttributeToFilter('status', 1)
->addAttributeToFilter('visibility', 4);
return ( $products->count() > 0 ) ? true : false;
}
This method checks each category individually by using the catalog/category model. If you have many categories, you might want to rewrite the code a bit so you do not run into performance issues since this will run each time a category is generated.