Back to Top

Magento 2 Development 26: Blog Listing

Updated 12 March 2024

In this blog, we will show the published and approved blogs on the front end. This will be our first public page since all of the pages before it required some kind of authentication either customer or admin. That means guest users also will be able to access this page.

The URL for the blog listing page will be http://hostname/blog. For now, you will have to directly browse the page. But in the next blog, we will add menus for this page.

So let’s create the controller file, Controller/Index/Index.php

Code for Controller/Index/Index.php file

<?php
namespace Webkul\BlogManager\Controller\Index;

use Magento\Framework\App\Action\Context;
use Magento\Framework\View\Result\PageFactory;

class Index extends \Magento\Framework\App\Action\Action
{
    /**
     * @var Magento\Framework\View\Result\PageFactory
     */
    protected $resultPageFactory;

    /**
     * Dependency Initilization
     *
     * @param Context $context
     * @param PageFactory $resultPageFactory
     */
    public function __construct(
        Context $context,
	    PageFactory $resultPageFactory
    ) {
	    $this->resultPageFactory = $resultPageFactory;
        parent::__construct($context);
    }

    /**
     * Provides content
     *
     * @return \Magento\Framework\View\Result\Page
     */
    public function execute()
    {
        $resultPage = $this->resultPageFactory->create();
        $resultPage->getConfig()->getTitle()->set(__('Blogs'));
        $layout = $resultPage->getLayout();
        return $resultPage;
    }
}

One thing to note here is that we have extended \Magento\Framework\App\Action\Action and not the customer abstract account. That’s because this page will be accessible to guest users also.

Searching for an experienced
Magento 2 Company ?
Find out More

Now the next step is to create the layout file view/frontend/layout/blogmanager_index_index.xml

Code for view/frontend/layout/blogmanager_index_index.xml file

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <head>
		<css src="Webkul_BlogManager::css/style.css"/>
	</head>
    <body>
        <referenceContainer name="content">
            <block class="Webkul\BlogManager\Block\Published\BlogList" name="blogmanager.blog.published.list" template="Webkul_BlogManager::published/list.phtml" />
        </referenceContainer>
    </body>
</page>

Note here we have used layout=”1column” instead of the 2column layout pattern. Also, we have not used the update handle code here because that was required to load the base structure of customer account pages. And we have added the CSS node which will load the style file.

Let’s create the template file now view/frontend/templates/published/list.phtml

Code for view/frontend/templates/published/list.phtml file

<?php 
$blogs = $block->getCollection();
?>
<div class="blog-collection-wrapper">
    <div class="blog-published">
        <?php
        foreach ($blogs as $blog) { ?>
            <div class="blog-item">
                <div class="blog-item-title">
                    <a href="<?= $escaper->escapeUrl($block->getUrl('blog/index/view', ['id'=>$escaper->escapeHtml($blog->getId())]))?>"><?= $escaper->escapeHtml($blog->getTitle()); ?></a>
                </div>
                <div class="blog-item-details">
                    <div><?= __("Created At:").' '.$escaper->escapeHtml($block->getFormattedDate($escaper->escapeHtml($blog->getCreatedAt()))); ?></div>
                    <div><?= __("Author:").' '.$block->getAuthor($blog->getUserId()); ?></div>
                </div>
                <div class="blog-item-content">
                    <?= strlen($escaper->escapeHtml($blog->getContent()))<100 ? $escaper->escapeHtml($blog->getContent()) : substr($escaper->escapeHtml($blog->getContent()),0,100).'...'; ?>
                    <div class="blog-item-view">
                        <a href="<?= $escaper->escapeUrl($block->getUrl('blog/index/view', ['id'=>$escaper->escapeHtml($blog->getId())]))?>"><?= __('view'); ?></a>
                    </div>
                </div>
            </div>
        <?php
        } ?>
        <?= $block->getPagerHtml(); ?>
    </div>
</div>

We have loaded all the blogs with the getCollection method, which we will create in the block. Then we looped over each blog to show data about them.

We have added links to view the blog page which we will create in the next blogs. Also, we have used getFormattedDate and getAuthor which we will create in block. We have displayed the first 100 characters of blog content.

Also, we have called getPagerHtml to get the pagination when we have lots of blogs.

Now let’s see the block class Block/Published/BlogList.php

Code for Block/Published/BlogList.php file

<?php
namespace Webkul\BlogManager\Block\Published;

class BlogList extends \Magento\Framework\View\Element\Template
{
    /**
     * @var \Webkul\BlogManager\Model\ResourceModel\Blog\CollectionFactory
     */
    protected $blogCollection;

    /**
     * @var \Webkul\BlogManager\Model\ResourceModel\Blog\Collection
     */
    protected $blogList;

    /**
     * @var \Webkul\BlogManager\Helper\Data
     */
    protected $helper;

    /**
     * @var \Magento\Customer\Model\CustomerFactory
     */
    protected $customerFactory;

    /**
     * Dependency Initilization
     *
     * @param \Magento\Framework\View\Element\Template\Context $context
     * @param \Webkul\BlogManager\Model\ResourceModel\Blog\CollectionFactory $blogCollection
     * @param \Webkul\BlogManager\Helper\Data $helper
     * @param \Magento\Customer\Model\CustomerFactory $customerFactory
     * @param array $data
     */
    public function __construct(
        \Magento\Framework\View\Element\Template\Context $context,
        \Webkul\BlogManager\Model\ResourceModel\Blog\CollectionFactory $blogCollection,
        \Webkul\BlogManager\Helper\Data $helper,
        \Magento\Customer\Model\CustomerFactory $customerFactory,
        array $data = []
    ) {
        $this->helper = $helper;
        $this->blogCollection = $blogCollection;
        $this->customerFactory = $customerFactory;
        parent::__construct($context, $data);
    }

    /**
     * Get Blog Collection
     *
     * @return Webkul\BlogManager\Model\ResourceModel\Blog\Collection
     */
    public function getCollection()
    {
        if (!$this->blogList) {
            $collection = $this->blogCollection->create();
            $collection->addFieldToFilter('status', 1);
            $collection->setOrder('created_at', 'DESC');
            $this->blogList = $collection;
        }
        return $this->blogList;
    }

    /**
     * Prepare Layout
     *
     * @return this
     */
    protected function _prepareLayout()
    {
        parent::_prepareLayout();
        if ($this->getCollection()) {
            $pager = $this->getLayout()->createBlock(
                \Magento\Theme\Block\Html\Pager::class,
                'blogmanager.publishedblog.pager'
            )
            ->setCollection(
                $this->getCollection()
            );
            $this->setChild('pager', $pager);
            $this->getCollection()->load();
        }
        return $this;
    }

    /**
     * Get Pager Html
     *
     * @return void
     */
    public function getPagerHtml()
    {
        return $this->getChildHtml('pager');
    }

    /**
     * Get Author Name
     *
     * @param int $userId
     * @return string
     */
    public function getAuthor($userId)
    {
        if ($userId) {
            $customer = $this->customerFactory->create()->load($userId);
            if ($customer && $customer->getId()) {
                return $customer->getName();
            }
        }
        return __('Admin');
    }

    /**
     * Get Formatted Date
     *
     * @param string $date
     * @return date
     */
    public function getFormattedDate($date)
    {
        return $this->helper->getFormattedDate($date);
    }
}

There are multiple things to notice here. First, we loaded the blogs based on status and sorted them by created date in the getCollection method. After loading it we have set the collection in $this->blogList field variable. if (!$this->blogList) this ensures that we load the collection only once for a page load. Because if you see we have called the getCollection multiple times in _prepareLayout and also in the template file. So it will ensure that we load the collection only once and save the data for future function calls.

We need the _prepareLayout function so that the pagination works. Because we have not created code for the pager but used Magento’s pagination.

In getPagerHtml, we have called for a child html called pager. This will be responsible for showing the pager based on the collection that we provide in prepare layout function.

The getAuthor is used to get the author’s name based on the id. We have loaded the customer model and got the name. If the id is 0 or if the customer with that id does not exist then it will return ‘Admin’.

For formatting dates, I have created a function getFormattedDate which again calls a function of the same from the helper. We will create this function in Helper.

Now let’s edit the helper class Helper/Data.php

Updated code for Helper/Data.php file

<?php
namespace Webkul\BlogManager\Helper;

use Magento\Customer\Model\Session;

class Data extends \Magento\Framework\App\Helper\AbstractHelper
{
    /**
     * @var Magento\Customer\Model\Session
     */
    protected $customerSession;

    /**
     * @var \Magento\Framework\Stdlib\DateTime\TimezoneInterface
     */
    protected $date;
    
    /**
     * Dependency Initilization
     *
     * @param Session $customerSession
     * @param \Magento\Framework\Stdlib\DateTime\TimezoneInterface $date
     * @param \Magento\Framework\App\Helper\Context $context
     */
    public function __construct(
        Session $customerSession,
        \Magento\Framework\Stdlib\DateTime\TimezoneInterface $date,
        \Magento\Framework\App\Helper\Context $context
    ) {
        $this->customerSession = $customerSession;
        $this->date = $date;
        parent::__construct($context);
    }

    /**
     * Get Customer Id
     *
     * @return int
     */
    public function getCustomerId()
    {
        $customerId = $this->customerSession->getCustomerId();
        return $customerId;
    }

    /**
     * Get Formatted Date
     *
     * @param string $date
     * @return date
     */
    public function getFormattedDate($date='')
    {
        return $this->date->date($date)->format('d/m/y h:i A');
    }
}

Here we have just added the function to format date.

We also need to do some styling so that the page looks good. So let’s edit the view/frontend/web/css/style.css

.blog-form .blog-form-field-container {
    margin: 15px auto;
}
.blog-form .blog-form-action-container {
    text-align: center;
}
.blog-form .blog-form-action-container .blog-form-action {
    min-width: 150px;
    padding: 10px;
    font-size: 16px;
    background: #2b4c8a;
    color: white;
}
.blog-collection-wrapper {
    max-width: 1000px;
    margin: 0 auto;
}
.blog-published .blog-item-title {
    font-size: 20px;
    margin-bottom: 5px;
}
.blog-published .blog-item-title a:hover {
    text-decoration: none;
}
.blog-published .blog-item-details div {
    display: inline-block;
    margin-right: 25px;
    margin-bottom: 10px;
    color: gray;
}
.blog-published .blog-item-content .blog-item-view {
    margin-top: 5px;
    text-decoration: underline;
}
.blog-published {
    margin-top: -20px
}
.blog-published .blog-item {
    border-bottom: 1px solid #cccccc;
    padding-bottom: 20px;
    padding-top: 30px;
}

Now when you browse the URL. You should see all the blogs as shown below,

2021-08-03_18-11

Also, you can see the pagination at the bottom,

2021-08-03_18-12-1


Next Blog -> Magento 2 Development 27: Front-end Menus

Previous Blog -> Magento 2 Development 25: Helper

. . .

Leave a Comment

Your email address will not be published. Required fields are marked*


Be the first to comment.

Back to Top

Message Sent!

If you have more details or questions, you can reply to the received confirmation email.

Back to Home