Как один и вариантов.
Использовать роутинг. Например fastRoute, перенаправить все роуты на middleware в котором проверить сущестовование роута первого порядка (категории) если найдена то обработчик передается в контроллер категорий, если не найден то ищем роут второго порядка(товары) и в случае успеха делегируем дальнейшее выполнение в нужный контроллер.
Или велосипед самому накропать. там сильно сложного нет ничего. Просто прослойку принимающую сначала все роуты отличные от ЧПУ например. проверку делаем аналогичную.