A module page in the front office
A hook adds a block to an existing page. When a module needs a page of its own with its own address — for example, all reviews of a product — you write a front controller. It is a class that receives the request, prepares data and picks a template.
Where the controller lives
Front controllers are kept in the controllers/front folder, page templates in views/templates/front. The files are created by hand:
modules/acmehello/
├── acmehello.php
├── classes/
├── controllers/
│ └── front/
│ └── reviews.php
├── upgrade/
└── views/
└── templates/
├── front/
│ └── reviews.tpl
└── hook/The controller
<?php
// modules/acmehello/controllers/front/reviews.php
class AcmehelloReviewsModuleFrontController extends ModuleFrontController
{
public function initContent(): void
{
parent::initContent();
$this->setTemplate('module:acmehello/views/templates/front/reviews.tpl');
}
}The class name is strictly defined: the module name with a capital letter, the file name with a capital letter and the ModuleFrontController ending. The initContent() method is called when the page is opened, setTemplate() picks the template.
The page template
{* modules/acmehello/views/templates/front/reviews.tpl *}
{extends file='page.tpl'}
{block name='page_title'}
{l s='Reviews' d='Modules.Acmehello.Shop'}
{/block}
{block name='page_content'}
<p>{l s='The list of reviews will be here.' d='Modules.Acmehello.Shop'}</p>
{/block}The template extends the theme's page.tpl and fills two of its blocks: the title and the content. The header, footer and columns are added automatically.
The page address
Open http://shop.test/index.php?fc=module&module=acmehello&controller=reviews. A shop page with the title "Reviews" appears. If friendly URLs are enabled in the shop, the same page is available as http://shop.test/module/acmehello/reviews.
There is no need to reset the module: the controller is found by its file name.
Data in the template
The controller reads the product id from the request and passes the reviews to the template. The module object is available as $this->module:
// modules/acmehello/controllers/front/reviews.php
public function initContent(): void
{
parent::initContent();
$productId = (int) Tools::getValue('id_product');
$product = new Product($productId, false, $this->context->language->id);
if (!Validate::isLoadedObject($product)) {
Tools::redirect($this->context->link->getPageLink('pagenotfound'));
}
$this->context->smarty->assign([
'productName' => $product->name,
'productUrl' => $this->context->link->getProductLink($product),
'reviews' => $this->module->getReviews($productId),
]);
$this->setTemplate('module:acmehello/views/templates/front/reviews.tpl');
}{block name='page_content'}
<p><a href="{$productUrl}">{$productName}</a></p>
{foreach from=$reviews item=review}
<article class="acme-review">
<strong>{$review.author}</strong> — {$review.rating}/5
<p>{$review.content}</p>
</article>
{foreachelse}
<p>{l s='No reviews yet.' d='Modules.Acmehello.Shop'}</p>
{/foreach}
{/block}The address /module/acmehello/reviews?id_product=1 shows the product name with a link and all its reviews. For a missing product the "Not found" page opens.
A link to the page
The address of a module page is not written by hand — getModuleLink() builds it. Add a link to the reviews block on the product page:
// modules/acmehello/acmehello.php, the hookDisplayFooterProduct method
$this->context->smarty->assign([
'reviews' => $this->getReviews($productId),
'reviewsUrl' => $this->context->link->getModuleLink('acmehello', 'reviews', ['id_product' => $productId]),
]);{* modules/acmehello/views/templates/hook/product-reviews.tpl *}
<a href="{$reviewsUrl}">{l s='All reviews' d='Modules.Acmehello.Shop'}</a>The arguments of getModuleLink() are the module name, the controller name and the request parameters. The method takes the language and friendly URLs into account.
Logged-in customers only
// modules/acmehello/controllers/front/reviews.php
public $auth = true;
public $authRedirection = 'my-account';With these properties a guest is redirected to the sign-in page. The reviews page does not need them, but they are useful for customer account pages.
Common mistake
The class is named AcmeHelloReviewsController, or the file Reviews.php. The page returns 404 and the log has no errors. The engine looks for the file controllers/front/reviews.php and the class AcmehelloReviewsModuleFrontController — the names are built from the module name and the value of the controller parameter, and this rule cannot be bent.