Основное приложение каким-либо образом получает список доступных модулей.
Каждый модуль имеет вполне определенный общий интерфейс (в программном смысле).
Интерфейс может, например, определять обязательные методы execute() и render().
Основное приложение пробегается циклом по модулям, и дергает их методы.
Например сначала execute (возможно передавая туда определенные настройки). Здесь модуль выполняет свою работу с данными.
А потом, на этапе отрисовки страницы дергает render. Тут либо из render получает готовую разметку и сам рисует, либо указывает где именно отрендерить.
Как-то так в общем случае.