“View product” button on the product edit page in Magento admin

Hello dear friends. While working with Magento, many of you may have noticed that, when you manage products in the admin you need to see how the product looks on the frontend. Of course, you can open a new page, then open frontend search or write direct url address to this product page, as Magento does not have the button or direct link from the admin page to the frontend product page, but it is not very simple way. Let’s create module with this feature. And best of all will be adding a button to the product edit page in the admin near ‘save’, ‘back’, etc… At first, we should find in what file the code, that responses for rendering these buttons, is located. It is the file app/code/core/Mage/Adminhtml/Block/Catalog/Product/Edit.php – hooray, we have found it! Afterwards, we need to rewrite this block functionality and below you can see how to implement this with config.xml file.

<?xml version="1.0"?>
<config>
    <modules>
        <Atwix_PVF>
            <version>0.0.1</version>
        </Atwix_PVF>
    </modules>
    <frontend>
    </frontend>
    <global>
        <blocks>
            <atwix_pvf>
                <class>Atwix_PVF_Block</class>
            </atwix_pvf>
            <adminhtml>
                <rewrite>
                    <catalog_product_edit>Atwix_PVF_Block_Adminhtml_Catalog_Product_Edit</catalog_product_edit>
                </rewrite>
            </adminhtml>
        </blocks>
    </global>
</config>

At the following step is necessary to create the file app/code/local/Atwix/PVF/Block/Adminhtml/Catalog/Product/Edit.php that will contain next code:

class Atwix_PVF_Block_Adminhtml_Catalog_Product_Edit extends Mage_Adminhtml_Block_Catalog_Product_Edit
{
    /**
     * @var Mage_Catalog_Model_Product Product instance
     */
    private $_product;

    /**
     * Preparing global layout
     * 
     * @return Atwix_PVF_Block_Adminhtml_Catalog_Product_Edit|Mage_Core_Block_Abstract
     */
    protected function _prepareLayout()
    {
        parent::_prepareLayout();
        $this->_product = $this->getProduct();
        $this->setChild('view_on_front',
            $this->getLayout()->createBlock('adminhtml/widget_button')
                ->setData(array(
                'label'     => Mage::helper('catalog')->__('View Product Page'),
                'onclick'   => 'window.open(\''.Mage::getModel('core/url')->getUrl() . $this->_product->getUrlPath() .'\')',
                'disabled'  => !$this->_isVisible(),
                'title' => (!$this->_isVisible())?
                    Mage::helper('catalog')->__('Product is not visible on frontend'):
                    Mage::helper('catalog')->__('View Product Page')
            ))
        );

        return $this;
    }

    /**
     * Returns duplicate & view on front buttons html
     * 
     * @return string
     */
    public function getDuplicateButtonHtml()
    {
        return $this->getChildHtml('duplicate_button') . $this->getChildHtml('view_on_front');
    }

    /**
     * Checking product visibility
     * 
     * @return bool
     */
    private function _isVisible()
    {
        return $this->_product->isVisibleInCatalog() && $this->_product->isVisibleInSiteVisibility();
    }

}

Onwards, let’s get across the class logic described above. We guess, you have already found out that private variable $_product is needed for us to load product instance into it.
The functional, that responses for rendering buttons, is located in _prepareLayout function, so it must be overridden, but don’t omit to call parent: _prepareLayout, because a lot of functionality will be lost. Following on – after parent calling we add the child element with id ‘view_on_front’ and instance of the button widget object. But what is this? Oh.. no! Magento can’t render children with the custom id. Maybe function that renders other button can help us. That is it.
We choose getDuplicateButtonHtml function, this one returns html of duplicated button, so we add our button html to this function return param. As the result, we get useful button that allows us to open the product page just clicking it.
Thank you for attention, stay tuned.

UPDATE: We’ve found another good way to add such button on product page in admin. As my fellow wrote in his article Advices and Best Practices for Magento developers we should avoid any rewrites in the modules, as rewrites cause conflicts between modules.
But what should we use instead of block rewrite? – It’s observer. In our case it’s called `adminhtml_block_html_before `, and see below how our config.xml will be changed:

<?xml version="1.0"?>
<config>
    <modules>
        <Atwix_PVF>
            <version>0.0.1</version>
        </Atwix_PVF>
    </modules>
    <global>
        <blocks>
            <atwix_pvf>
                <class>Atwix_PVF_Block</class>
            </atwix_pvf>
        </blocks>
        <models>
            <atwix_pvf>
                <class>Atwix_PVF_Model</class>
            </atwix_pvf>
        </models>
    </global>
    <adminhtml>
        <events>
            <adminhtml_block_html_before>
                <observers>
                    <atwix_pvf>
                        <type>model</type>
                        <class>Atwix_PVF_Model_Observer</class>
                        <method>addPVFButton</method>
                    </atwix_pvf>
                </observers>
            </adminhtml_block_html_before>
        </events>
    </adminhtml>
</config>

However, there’s one issue – this observer is called many times for every blocks in the admin. So we need to add checking by block type. Block type should be equal ‘adminhtml/catalog_product_edit’. Let’s look into observer code to see how this issue has been resolved:

class Atwix_PVF_Model_Observer
{
    public function addPVFButton($observer)
    {
        $_block = $observer->getBlock();
        $_type = $_block->getType();
        if ($_type == 'adminhtml/catalog_product_edit') {
            $_deleteButton = $_block->getChild('delete_button');
            $_block->setChild('product_view_button',
                $_block->getLayout()->createBlock('atwix_pvf/adminhtml_widget_button')
            );
            $_deleteButton->setBeforeHtml($_block->getChild('product_view_button')->toHtml());
        }
    }
}

In previous code snippet we got HTML of delete button and tied our button’s HTML to it.

And finally, we’ve created a block for this button:

class Atwix_PVF_Block_Adminhtml_Widget_Button extends Mage_Adminhtml_Block_Widget_Button
{
    /**
     * @var Mage_Catalog_Model_Product Product instance
     */
    private $_product;

    /**
     * Block construct, setting data for button, getting current product
     */
    protected function _construct()
    {
        $this->_product = Mage::registry('current_product');
        parent::_construct();
        $this->setData(array(
            'label'     => Mage::helper('catalog')->__('View Product Page'),
            'onclick'   => 'window.open(\''.Mage::getModel('core/url')->getUrl() . $this->_product->getUrlPath() .'\')',
            'disabled'  => !$this->_isVisible(),
            'title' => (!$this->_isVisible())?
                Mage::helper('catalog')->__('Product is not visible on frontend'):
                Mage::helper('catalog')->__('View Product Page')
        ));
    }

    /**
     * Checking product visibility
     *
     * @return bool
     */
    private function _isVisible()
    {
        return $this->_product->isVisibleInCatalog() && $this->_product->isVisibleInSiteVisibility();
    }
}

Latest version of the module was uploaded to our GitHub account
We hope this article’s update will be useful.