So basically you need to keep the category url if you have only one product in that category but shows the product page instead of the category page.
For this, forwarding your category page to product page is what you need to do. The best place to perform forward is the predispatch section. This is how you can do this.
1. Listen to the event controller_action_predispatch_catalog_category_view
For this you need to set this in the config.xml
file of your module.
File : app\code\local\Namespace\Module\etc\config.xml
<config>
<frontend>
<events>
<controller_action_predispatch_catalog_category_view>
<observers>
<forward_category_to_product>
<class>namespace_module/observer</class>
<method>forwardSingleProCategory</method>
</forward_category_to_product>
</observers>
</controller_action_predispatch_catalog_category_view>
</events>
</frontend>
</config>
2. Define Observer
File : app\code\local\Namespace\Module\Model\Observer.php
class Namespace_Module_Model_Observer
{
public function forwardSingleProCategory(Varien_Event_Observer $observer)
{
//get event data
$action = $observer->getControllerAction();
$request = $action->getRequest();
//get category id
$categoryId = (int)$request->getParam('id', false);
//grab category collection
$layer = Mage::getModel('catalog/layer')->setCurrentCategory($categoryId);
$collection = $layer->getProductCollection();
//check whether category count is 1. If YES, then do magic
if ($collection->getSize() == 1) {
//prepare parameters that needs for the action `catalog/product/view`
$product = $collection->getFirstItem();
$actionName = 'view';
$controllerName = 'product';
$moduleName = 'catalog';
$params = array(
'category' => $categoryId,
'id' => (int)$product->getId()
);
/**
* This one is important.
* we need to set pathinfo to the required path .
* otherwise path parameters will overwrite _params while
* in the next matching process in the standard router
*/
$pathInfo = 'catalog/product/view/id' . $product->getId();
$request->setPathInfo($pathInfo);
//triggers Mage_Core_Controller_Varien_Action::_forward()
$e = new Mage_Core_Controller_Varien_Exception();
$e->prepareForward($actionName, $controllerName, $moduleName, $params);
throw $e;
return false;
}
return $this;
}
}
In this code, we will collect the collection of category and check whether collection count is 1. If yes, then we will trigger a forward action. In the code, the following section is actually do this triggering.
$e = new Mage_Core_Controller_Varien_Exception();
$e->prepareForward($actionName, $controllerName, $moduleName, $params);
throw $e;
If you are curious to know how this observer works, then read this thread.
and here is the full module reference. Feel free to use it.