Most of the time, as Magento 2 developers, we have to dip our hands into both the backend and the front end. In this blog, I will present to you how to make a Menu in the customer’s My Account menu on the front end. I will use my example code in one of our modules: GiftRegistry.
Table of Contents
InstallSchema
We will create a database for the table, our table’s data will be from this database.
Make a file named magenest_registry_event in Setup/InstallSchema.php
$table = $installer->getConnection()->newTable($installer->getTable('magenest_registry_event')) ->addColumn( 'event_id', Table::TYPE_INTEGER, null, ['identity' => true, 'unsigned' => true, 'nullable' => false, 'primary' => true], 'Event ID' ) ->addColumn( 'customer_id', Table::TYPE_INTEGER, null, ['unsigned' => true, 'nullable' => false, 'default' => '0'], 'Owner Id' ) ->addColumn( 'event_type', Table::TYPE_TEXT, null, ['nullable' => false], 'Event type' ) ->addColumn( 'event_location', Table::TYPE_TEXT, null, ['nullable' => false], 'Event location' ) ->addColumn( 'event_time', Table::TYPE_TIMESTAMP, null, ['nullable' => false], 'Event time' ) ->addColumn( 'created_time', Table::TYPE_TIMESTAMP, null, ['nullable' => false, 'default' => Table::TIMESTAMP_INIT], 'Time created' ) ->addColumn( 'update_time', Table::TYPE_TIMESTAMP, null, ['nullable' => false, 'default' => Table::TIMESTAMP_INIT_UPDATE], 'Time update' ) ->addForeignKey( $installer->getFkName('magenest_registry_event', 'customer_id', 'customer_entity', 'entity_id'), 'customer_id', $installer->getTable('customer_entity'), 'entity_id', Table::ACTION_CASCADE ) ->setComment('Table Event'); $installer->getConnection()->createTable($table);
Model
Next up, create our table’s model: Model/Event.php
<?php /* * Created by Magenest * User: Nguyen Duc Canh * Date: 1/12/2015 * Time: 10:26 */ namespace Magenest\GiftRegistry\Model; use Magenest\GiftRegistry\Model\ResourceModel\Event as ResourceEvent; use Magenest\GiftRegistry\Model\ResourceModel\Event\Collection as Collection; class Event extends \Magento\Framework\Model\AbstractModel{ protected $_eventPrefix = 'event'; public function __construct( \Magento\Framework\Model\Context $context, \Magento\Framework\Registry $registry, ResourceEvent $resource, Collection $resourceCollection, array $data = [] ){ parent::__construct($context, $registry, $resource, $resourceCollection, $data); } public function getDataCollection(){ $collection = $this->getCollection()->addFieldToSelect('*'); return $collection; } }
Model/ResourceModel/Event.php
<?php /* * Created by Magenest * User: Nguyen Duc Canh * Date: 1/12/2015 * Time: 10:26 */ namespace Magenest\GiftRegistry\Model\ResourceModel; class Event extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb{ protected function _construct() { // TODO: Implement _construct() method. $this->_init('magenest_registry_event', 'event_id'); } }
Model/ResourceModel/Event/Collection.php
<?php /* * Created by Magenest * User: Nguyen Duc Canh * Date: 1/12/2015 * Time: 10:26 */ namespace Magenest\GiftRegistry\Model\ResourceModel\Event; class Collection extends \Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection{ protected function _construct() { $this->_init('Magenest\GiftRegistry\Model\Event', 'Magenest\GiftRegistry\Model\ResourceModel\Event'); } }
View/Frontend
This is where frontend components are handled frontend/layout/customer_account.xml.
<?xml version="1.0"?> <page xmlns:xsi="//www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd"> <body> <referenceBlock name="customer_account_navigation"> <block class="Magento\Framework\View\Element\Html\Link\Current" name="customer-account-navigation-gift-registry-link"> <arguments> <argument name="label" xsi:type="string">My Gift Registry</argument> <argument name="path" xsi:type="string">giftregistry/customer/registry</argument> </arguments> </block> </referenceBlock> </body>
This is the file that adds a Tab named My Gift Registry in the My Account menu of a customer. The data will be passed onto giftregistry/customer/registry controller for handling. Make sure the path is correct.
After that, we need to create one more layout file which will create a block and its template frontend/layout/giftregistry_customer_registry.xml
<page xmlns:xsi="//www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd"> <update handle="customer_account"/> <body> <referenceContainer name="content"> <block class="Magenest\GiftRegistry\Block\Customer\Registry\ListGift" name="giftregistry.list" template="Magenest_GiftRegistry::customer/giftregistry/list.phtml" /> </referenceContainer> </body> </page>
Add frontend/templates/customer/gifregistry/list.phtml
<?php $_events = $block->getEvents(); ?> <?php if(count($_events)): ?> <div class="table-wrapper downloadable-products"> <table id="my-downloadable-products-table" class="data table table-downloadable-products"> <caption class="table-caption"><?php echo __('List Event') ?></caption> <thead> <tr> <th scope="col" class="col title"><?php echo __('Event #') ?></th> <th scope="col" class="col title"><?php echo __('Event Type') ?></th> <th scope="col" class="col title"><?php echo __('Customer Id') ?></th> <th scope="col" class="col title"><?php echo __('Event Location') ?></th> <th scope="col" class="col title"><?php echo __('Ship') ?></th> <th scope="col" class="col title"><?php echo __('Company') ?></th> <th scope="col" class="col date"><?php echo __('Event Time') ?></th> <th scope="col" class="col actions"><?php echo __('Actions') ?></th> </tr> </thead> <tbody> <?php foreach($_events as $_event): ?> <tr> <td data-th="<?php echo $block->escapeHtml(__('Event')) ?>" class="col title"> <?php echo $_event['event_id'] ?> </td> <td data-th="<?php echo $block->escapeHtml(__('Event Type')) ?>" class="col title"> <?php echo $_event['event_type'] ?> </td> <td data-th="<?php echo $block->escapeHtml(__('Customer Id')) ?>" class="col title"> <?php echo $_event['customer_id'] ?> </td> <td data-th="<?php echo $block->escapeHtml(__('Event Location')) ?>" class="col title"> <?php echo $_event['event_location'] ?> </td> <td data-th="<?php echo $block->escapeHtml(__('Ship')) ?>" class="col title"> <?php echo $_event['ship_firstname'] ?> </td> <td data-th="<?php echo $block->escapeHtml(__('Company')) ?>" class="col title"> <?php echo $_event['ship_company'] ?> </td> <td data-th="<?php echo $block->escapeHtml(__('Event Time')) ?>" class="col title"> <?php echo $_event['event_time'] ?> </td> <td data-th="<?php echo $block->escapeHtml(__('Actions')) ?>" class="col actions"> <a href="<?php echo $block->getViewUrl($_event) ?>" class="action view"> <span><?php echo __('View') ?></span> </a> <a href="<?php echo $block->getEditUrl($_event) ?>" class="action edit"> <span><?php echo __('Edit') ?></span> </a> </td> </tr> <?php endforeach; ?> </tbody> </table> </div> <?php if ($block->getChildHtml('pager')): ?> <div class="toolbar downloadable-products-toolbar bottom"> <?php echo $block->getChildHtml('pager'); ?> </div> <?php endif; ?> <?php else: ?> <div class="message info empty"><span><?php echo __('You have not event !.'); ?></span></div> <?php endif; ?> <div class="actions-toolbar"> <div class="primary"> <a href="<?php echo $block->escapeUrl($block->getBackUrl()) ?>" class="action back"> <span><?php echo __('Back') ?></span> </a> <a href="<?php echo $block->escapeUrl($block->getNewRegistryUrl()) ?>" class="action new"> <span><span><?php echo __('New Registry') ?></span> </span> </a> <a href="<?php echo $block->escapeUrl($block->getUpdateUrl()) ?>" class="action update"> <span><span><?php echo __('Update Registry') ?></span> </span> </a> </div> </div>
This is the template file that adds the table components and displays them. You can customize it to suit your need.
Controller
Better late than never, let’s create our controller file in Controller/Customer/Registry
<?php /** * Created by PhpStorm. * User: canh * Date: 01/12/2015 * Time: 13:25 */ namespace Magenest\GiftRegistry\Controller\Customer; class Registry extends \Magento\Framework\App\Action\Action { /** @var \Magento\Framework\View\Result\Page */ protected $resultPageFactory; /** * @param \Magento\Framework\App\Action\Context $context */ public function __construct(\Magento\Framework\App\Action\Context $context, \Magento\Framework\View\Result\PageFactory $resultPageFactory) { $this->resultPageFactory = $resultPageFactory; parent::__construct($context); } /** * Blog Index, shows a list of recent blog posts. * * @return \Magento\Framework\View\Result\PageFactory */ public function execute() { $resultPage = $this->resultPageFactory->create(); $resultPage->getConfig()->getTitle()->prepend(__('List Gift Registry')); return $resultPage; }
This will put List Gift Registry as the title of the page.
Block
This is one crucial part, make a file named Block/Customer/Registry/ListGift.php
<?php /** * Created by PhpStorm. * User: canh * Date: 01/12/2015 * Time: 14:10 */ namespace Magenest\GiftRegistry\Block\Customer\Registry; use Magenest\GiftRegistry\Model\ResourceModel\Event\Collection as EventedCollection; class ListGift extends \Magento\Framework\View\Element\Template { protected $currentCustomer; protected $_eventFactory; public function __construct( \Magento\Framework\View\Element\Template\Context $context, \Magento\Customer\Helper\Session\CurrentCustomer $currentCustomer, \Magenest\GiftRegistry\Model\ResourceModel\Event\CollectionFactory $eventFactory, array $data = [] ) { parent::__construct($context, $data); $this->currentCustomer = $currentCustomer; $this->_eventFactory = $eventFactory; $this->getEvents(); } public function getEvents(){ $currentCustomerId = $this->currentCustomer->getCustomerId(); $eventId = $this->getRequest()->getParams(); if(empty($eventId['event_fn']) && empty($eventId['event_ln'])){ $eventCollection = $this->_eventFactory->create()->addFieldToFilter('customer_id', $currentCustomerId); $data = $eventCollection->getData(); return $data; } else { $eventCollection = $this->_eventFactory->create() ->addFieldToFilter('ship_firstname',$eventId['event_fn']) ->addFieldToFilter('ship_lastname',$eventId['event_ln']); $data =$eventCollection->getData(); return $data; } } public function _prepareLayout() { return parent::_prepareLayout(); } public function getViewUrl($event) { return $this->getUrl('giftregistry/customer/viewregistry/', ['event_id' => $event['event_id']]); } public function getBackUrl(){ return $this->getUrl('customer/account/index'); } public function getNewRegistryUrl(){ return $this->getUrl('giftregistry/customer/newregistry'); } public function getUpdateUrl(){ return $this->getUrl('giftregistry/customer/registry'); } public function getEditUrl($event){ return $this->getUrl('giftregistry/customer/editregistry',['event_id' => $event['event_id']]); } }
This is the place where data will be received from the database and handled, then passed onto the template file to display.
The Final Result
This picture denotes our expected outcome.
If you have followed all the steps, but don’t see the expected outcome, here are some things you can check:
- Module installation: Make sure the GiftRegistry module is installed correctly and enabled.
- Clear cache: Clear the Magento cache to ensure changes take effect.
- Module registration: Check if the module is registered properly in Magento’s configuration.
- Module dependencies: Ensure that all required modules are present and properly configured.
- Configuration settings: Verify that the module’s configuration is correctly set, especially regarding the menu item in the customer’s My Account menu.
- Custom theme compatibility: Check if the module changes are compatible with your custom theme and if necessary layout updates or template files are correctly overridden.
- Logging and debugging: Enable logging and debugging to capture any errors or warnings related to the GiftRegistry module.
- Theme fallback: If using a custom theme with a parent theme, confirm that the necessary changes cascade down correctly without interference from the parent theme.
Hope you find this blog helpful. If you need any help, don’t hesitate to contact Magenest. Our team of experts is here to help you with any questions.