How to Make a Magento 2 Menu in My Account menu on M2 frontend?

Eric Quach
Eric Quach

Most of the time, as a Magento 2 developer, we have to dip our hands into both backend and frontend. In this blog, I will present to you how to make a Menu in customer’s My Account menu on the frontend. I will use my example code in one of our modules: GiftRegistry.

This picture denotes our expected outcome:

add menu on magento 2

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 which 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.

Controlller

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.

READ MORE

Don't want to miss out on our latest insights?
Subscribe to our newsletter.

Disclaimer: By clicking submit, you agree to share your information with us to receive news, announcements, and resources when they are available.