Hello guys,
This is a great requirement to have a print link on the product detail( product view) page in magento commerce. I am writing this content for version 1.4.0.1.
The content is not short or easy, I am only writing the steps to accomplish this task and hope the viewers of this site could get a solution.
The content has been divided into four steps and is explained step by step.
Step1. How to start?
The print is a command much like viewing a product detail and each command is controlled through “controllers” which is available into “module/…/action”.
Here for product view,
module = catalog
… = product
action = viewAction
So in case of Print command these should be
module = catalog
… = product
and action = print
In “/app/code/core/Mage/Catalog/controllers/ProductController.php” create a new funtion “printAction()”. To create this function simply copy the function “viewAction()” and rename it and modify the line
“Mage:dispatchEvent(‘catalog_controller_product_view’,…)” to “Mage:dispatchEvent(‘catalog_controller_product_print’,…)”
/**
* Print product action function
in “app\code\core\Mage\Catalog\controllers\ProductController.php
*/
public function printAction()
{
if ($product = $this->_initProduct()) {
Mage::dispatchEvent(‘catalog_controller_product_print’, array(‘product’=>$product));if ($this->getRequest()->getParam(‘options’)) {
$notice = $product->getTypeInstance(true)->getSpecifyOptionMessage();
Mage::getSingleton(‘catalog/session’)->addNotice($notice);
}Mage::getSingleton(‘catalog/session’)->setLastViewedProductId($product->getId());
Mage::getModel(‘catalog/design’)->applyDesign($product, Mage_Catalog_Model_Design::APPLY_FOR_PRODUCT);
$this->_initProductLayout($product);
$this->_initLayoutMessages(‘catalog/session’);
$this->_initLayoutMessages(‘tag/session’);
$this->_initLayoutMessages(‘checkout/session’);
$this->renderLayout();
}
else {
if (isset($_GET['store']) && !$this->getResponse()->isRedirect()) {
$this->_redirect(”);
} elseif (!$this->getResponse()->isRedirect()) {
$this->_forward(‘noRoute’);
}
}
}
Step2. Creating link for print
Actually the real link (URL) for product view page is “/index.php/catalog/product/view/id/$id/category/$category”.
And the content on print page of product is much like the content on product view page and we can get easily these contents from allready available for product view page so we will keep the print link as “/index.php/catalog/product/print/id/$id”.
No need to add category and its id.
Put this code anywhere you want better in product view template file which is “/view.phtml”.
<a href=”<?php echo $this->getBaseurl();?>catalog/product/print/id/<?php echo $this->getProduct()->getId();?> target=”_blank”>Print Product Detail</a>
Step3. Create a block file for print
Create a block file(.php) file. Copy View.php and rename it to Print.php and change the class name to “Mage_catalog_Block_Product_Print” and do nothing.
/**
* Product Print block
*
* @category Mage
* @package Mage_Catalog
* @module Catalog
*/
class Mage_Catalog_Block_Product_Print extends Mage_Catalog_Block_Product_Abstract
{
/**
* Add meta information from product to head block
*
* @return Mage_Catalog_Block_Product_Print
*/
protected function _prepareLayout()
{
$this->getLayout()->createBlock(‘catalog/breadcrumbs’);
$headBlock = $this->getLayout()->getBlock(‘head’);
if ($headBlock) {
$product = $this->getProduct();
$title = $product->getMetaTitle();
if ($title) {
$headBlock->setTitle($title);
}
$keyword = $product->getMetaKeyword();
$currentCategory = Mage::registry(‘current_category’);
if ($keyword) {
$headBlock->setKeywords($keyword);
} elseif($currentCategory) {
$headBlock->setKeywords($product->getName());
}
$description = $product->getMetaDescription();
if ($description) {
$headBlock->setDescription( ($description) );
} else {
$headBlock->setDescription($product->getDescription());
}
if ($this->helper(‘catalog/product’)->canUseCanonicalTag()) {
$params = array(‘_ignore_category’=>true);
$headBlock->addLinkRel(‘canonical’, $product->getUrlModel()->getUrl($product, $params));
}
}return parent::_prepareLayout();
}/**
* Retrieve current product model
*
* @return Mage_Catalog_Model_Product
*/
public function getProduct()
{
if (!Mage::registry(‘product’) && $this->getProductId()) {
$product = Mage::getModel(‘catalog/product’)->load($this->getProductId());
Mage::register(‘product’, $product);
}
return Mage::registry(‘product’);
}/**
* Check if product can be emailed to friend
*
* @return bool
*/
public function canEmailToFriend()
{
$sendToFriendModel = Mage::registry(‘send_to_friend_model’);
return $sendToFriendModel && $sendToFriendModel->canEmailToFriend();
}/**
in “app\code\core\Mage\Catalog\Block\Product\Print.php”
* Retrieve url for direct adding product to cart
*
* @param Mage_Catalog_Model_Product $product
* @param array $additional
* @return string
*/
public function getAddToCartUrl($product, $additional = array())
{
if ($this->getRequest()->getParam(‘wishlist_next’)){
$additional['wishlist_next'] = 1;
}return $this->helper(‘checkout/cart’)->getAddUrl($product, $additional);
}/**
* Get JSON encripted configuration array which can be used for JS dynamic
* price calculation depending on product options
*
* @return string
*/
public function getJsonConfig()
{
$config = array();
if (!$this->hasOptions()) {
return Mage::helper(‘core’)->jsonEncode($config);
}$_request = Mage::getSingleton(‘tax/calculation’)->getRateRequest(false, false, false);
$_request->setProductClassId($this->getProduct()->getTaxClassId());
$defaultTax = Mage::getSingleton(‘tax/calculation’)->getRate($_request);$_request = Mage::getSingleton(‘tax/calculation’)->getRateRequest();
$_request->setProductClassId($this->getProduct()->getTaxClassId());
$currentTax = Mage::getSingleton(‘tax/calculation’)->getRate($_request);$_regularPrice = $this->getProduct()->getPrice();
$_finalPrice = $this->getProduct()->getFinalPrice();
$_priceInclTax = Mage::helper(‘tax’)->getPrice($this->getProduct(), $_finalPrice, true);
$_priceExclTax = Mage::helper(‘tax’)->getPrice($this->getProduct(), $_finalPrice);$config = array(
‘productId’ => $this->getProduct()->getId(),
‘priceFormat’ => Mage::app()->getLocale()->getJsPriceFormat(),
‘includeTax’ => Mage::helper(‘tax’)->priceIncludesTax() ? ‘true’ : ‘false’,
‘showIncludeTax’ => Mage::helper(‘tax’)->displayPriceIncludingTax(),
‘showBothPrices’ => Mage::helper(‘tax’)->displayBothPrices(),
‘productPrice’ => Mage::helper(‘core’)->currency($_finalPrice, false, false),
‘productOldPrice’ => Mage::helper(‘core’)->currency($_regularPrice, false, false),
‘skipCalculate’ => ($_priceExclTax != $_priceInclTax ? 0 : 1),
‘defaultTax’ => $defaultTax,
‘currentTax’ => $currentTax,
‘idSuffix’ => ‘_clone’,
‘oldPlusDisposition’ => 0,
‘plusDisposition’ => 0,
‘oldMinusDisposition’ => 0,
‘minusDisposition’ => 0,
);$responseObject = new Varien_Object();
Mage::dispatchEvent(‘catalog_product_view_config’, array(‘response_object’=>$responseObject));
if (is_array($responseObject->getAdditionalOptions())) {
foreach ($responseObject->getAdditionalOptions() as $option=>$value) {
$config[$option] = $value;
}
}return Mage::helper(‘core’)->jsonEncode($config);
}/**
* Return true if product has options
*
* @return bool
*/
public function hasOptions()
{
if ($this->getProduct()->getTypeInstance(true)->hasOptions($this->getProduct())) {
return true;
}
return false;
}/**
* Check if product has required options
*
* @return bool
*/
public function hasRequiredOptions()
{
return $this->getProduct()->getTypeInstance(true)->hasRequiredOptions($this->getProduct());
}}
Step4. Front Design
a) Layout (layout/catalog.xml)
Copy the layout of product view and paste it under and then change the head tag “catalog_product_view” to “catalog_product_print”. Set template to “page/print_product.phtml”. And in reference, where ‘name=”content”‘ set block type to “catalog/product_print” and set template to “catalog/product/print.phtml”
To create print_product.phtml copy print.phtml from review block and paste it into “template/page/” folder.
<!–
Product Print in catalog.xml
–><catalog_product_print translate=”label”>
<label>Catalog Product View (Any)</label>
<!– Mage_Catalog –>
<reference name=”root”>
<action method=”setTemplate”><template>page/print.phtml</template></action>
</reference>
<reference name=”head”>
<action method=”addJs”><script>varien/product.js</script></action><action method=”addItem”><type>js_css</type><name>calendar/calendar-win2k-1.css</name><params/><!–<if/><condition>can_load_calendar_js</condition>–></action>
<action method=”addItem”><type>js</type><name>calendar/calendar.js</name><!–<params/><if/><condition>can_load_calendar_js</condition>–></action>
<action method=”addItem”><type>js</type><name>calendar/calendar-setup.js</name><!–<params/><if/><condition>can_load_calendar_js</condition>–></action>
</reference>
<reference name=”content”>
<block type=”catalog/product_print” name=”product.info” template=”catalog/product/print.phtml”>
<!–
<action method=”addReviewSummaryTemplate”><type>default</type><template>review/helper/summary.phtml</template></action>
<action method=”addReviewSummaryTemplate”><type>short</type><template>review/helper/summary_short.phtml</template></action>
<action method=”addReviewSummaryTemplate”><type>…</type><template>…</template></action>
–>
<block type=”catalog/product_view_media” name=”product.info.media” as=”media” template=”catalog/product/view/media.phtml”/>
<block type=”core/text_list” name=”alert.urls” as=”alert_urls” translate=”label”>
<label>Alert Urls</label>
</block><action method=”setTierPriceTemplate”><template>catalog/product/view/tierprices.phtml</template></action>
<block type=”catalog/product_list_upsell” name=”product.info.upsell” as=”upsell_products” template=”catalog/product/list/upsell.phtml”>
<action method=”setColumnCount”><columns>4</columns></action>
<action method=”setItemLimit”><type>upsell</type><limit>4</limit></action>
</block><block type=”catalog/product_view_additional” name=”product.info.additional” as=”product_additional_data” />
<block type=”catalog/product_view_description” name=”product.description” as=”description” template=”catalog/product/view/description.phtml”/>
<block type=”catalog/product_view_attributes” name=”product.attributes” as=”additional” template=”catalog/product/view/attributes.phtml”/>
<block type=”catalog/product_view” name=”product.info.addto” as=”addto” template=”catalog/product/view/addto.phtml”/>
<block type=”catalog/product_view” name=”product.info.addtocart” as=”addtocart” template=”catalog/product/view/addtocart.phtml”/><block type=”catalog/product_view” name=”product.info.options.wrapper” as=”product_options_wrapper” template=”catalog/product/view/options/wrapper.phtml” translate=”label”>
<label>Info Column Options Wrapper</label>
<block type=”core/template” name=”options_js” template=”catalog/product/view/options/js.phtml”/>
<block type=”catalog/product_view_options” name=”product.info.options” as=”product_options” template=”catalog/product/view/options.phtml”>
<action method=”addOptionRenderer”><type>text</type><block>catalog/product_view_options_type_text</block><template>catalog/product/view/options/type/text.phtml</template></action>
<action method=”addOptionRenderer”><type>file</type><block>catalog/product_view_options_type_file</block><template>catalog/product/view/options/type/file.phtml</template></action>
<action method=”addOptionRenderer”><type>select</type><block>catalog/product_view_options_type_select</block><template>catalog/product/view/options/type/select.phtml</template></action>
<action method=”addOptionRenderer”><type>date</type><block>catalog/product_view_options_type_date</block><template>catalog/product/view/options/type/date.phtml</template></action>
</block>
<block type=”core/html_calendar” name=”html_calendar” as=”html_calendar” template=”page/js/calendar.phtml”/>
</block>
<block type=”catalog/product_view” name=”product.info.options.wrapper.bottom” as=”product_options_wrapper_bottom” template=”catalog/product/view/options/wrapper/bottom.phtml” translate=”label”>
<label>Bottom Block Options Wrapper</label>
<action method=”insert”><block>product.tierprices</block></action>
<block type=”catalog/product_view” name=”product.clone_prices” as=”prices” template=”catalog/product/view/price_clone.phtml”/>
<action method=”append”><block>product.info.addtocart</block></action>
</block><block type=”core/template_facade” name=”product.info.container1″ as=”container1″>
<action method=”setDataByKey”><key>alias_in_layout</key><value>container1</value></action>
<action method=”setDataByKeyFromRegistry”><key>options_container</key><key_in_registry>product</key_in_registry></action>
<action method=”append”><block>product.info.options.wrapper</block></action>
<action method=”append”><block>product.info.options.wrapper.bottom</block></action>
</block>
<block type=”core/template_facade” name=”product.info.container2″ as=”container2″>
<action method=”setDataByKey”><key>alias_in_layout</key><value>container2</value></action>
<action method=”setDataByKeyFromRegistry”><key>options_container</key><key_in_registry>product</key_in_registry></action>
<action method=”append”><block>product.info.options.wrapper</block></action>
<action method=”append”><block>product.info.options.wrapper.bottom</block></action>
</block>
<action method=”unsetCallChild”><child>container1</child><call>ifEquals</call><if>0</if><key>alias_in_layout</key><key>options_container</key></action>
<action method=”unsetCallChild”><child>container2</child><call>ifEquals</call><if>0</if><key>alias_in_layout</key><key>options_container</key></action>
</block>
</reference>
<reference name=”right”>
<block type=”catalog/product_list_related” name=”catalog.product.related” before=”-” template=”catalog/product/list/related.phtml”/>
</reference>
</catalog_product_print>/* product_print.phtml*/
<?php
/**
* Template for Mage_Page_Block_Html
*/
?>
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Strict//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd”>
<html xmlns=”http://www.w3.org/1999/xhtml” xml:lang=”<?php echo $this->getLang() ?>” lang=”<?php echo $this->getLang() ?>”>
<head>
<?php echo $this->getChildHtml(‘head’) ?>
</head>
<body>
<div>
<div>
<img src=”<?php echo $this->getPrintLogoUrl() ? $this->getPrintLogoUrl() : $this->getSkinUrl(‘images/logo_print.gif’) ?>” alt=”" />
<?php if ($this->getPrintLogoText()):?>
<address><?php echo nl2br($this->htmlEscape($this->getPrintLogoText())) ?></address>
<?php endif;?>
</div>
<?php echo $this->getChildHtml(‘content’) ?>
<div>
<button type=”button” title=”<?php echo $this->__(‘Close Window’) ?>” onclick=”window.close();”><span><span><?php echo $this->__(‘Close Window’) ?></span></span></button>
</div>
<?php echo $this->getAbsoluteFooter() ?>
</div>
</body>
</html>
b) Desing
Copy “view.phtml” from “/app/desing/frontend/base/default/template/catalog/product/” and paste into the same folder and rename it “print.phtml”.
/**
* Product print template
*
* @see Mage_Catalog_Block_Product_Print
* @see Mage_Review_Block_Product_Print
*/
?>
<?php
$_helper = $this->helper(‘catalog/output’);
$_product = $this->getProduct();
?>
<script type=”text/javascript”>
var optionsPrice = new Product.OptionsPrice(<?php echo $this->getJsonConfig() ?>);
</script>
<div id=”messages_product_view”><?php echo $this->getMessagesBlock()->getGroupedHtml() ?></div>
<div>
<div>
<form action=”<?php echo $this->getAddToCartUrl($_product) ?>” method=”post” id=”product_addtocart_form”<?php if($_product->getOptions()): ?> enctype=”multipart/form-data”<?php endif; ?>>
<div>
<input type=”hidden” name=”product” value=”<?php echo $_product->getId() ?>” />
<input type=”hidden” name=”related_product” id=”related-products-field” value=”" />
</div><div>
<div>
<h1><?php echo $_helper->productAttribute($_product, $_product->getName(), ‘name’) ?></h1>
</div><?php if ($this->canEmailToFriend()): ?>
<p><a href=”<?php echo $this->helper(‘catalog/product’)->getEmailToFriendUrl($_product) ?>”><?php echo $this->__(‘Email to a Friend’) ?></a></p>
<?php endif; ?><?php echo $this->getReviewsSummaryHtml($_product, false, true)?>
<?php echo $this->getChildHtml(‘alert_urls’) ?>
<?php echo $this->getChildHtml(‘product_type_data’) ?>
<?php echo $this->getTierPriceHtml() ?><?php if (!$this->hasOptions()):?>
<div>
<?php if($_product->isSaleable()): ?>
<?php echo $this->getChildHtml(‘addtocart’) ?>
<?php if( $this->helper(‘wishlist’)->isAllow() || $_compareUrl=$this->helper(‘catalog/product_compare’)->getAddUrl($_product)): ?>
<span><?php echo $this->__(‘OR’) ?></span>
<?php endif; ?>
<?php endif; ?>
<?php echo $this->getChildHtml(‘addto’) ?>
</div>
<?php else:?>
<?php echo $this->getChildHtml(‘addto’) ?>
<?php endif; ?><?php if ($_product->getShortDescription()):?>
<div>
<h2><?php echo $this->__(‘Quick Overview’) ?></h2>
<div><?php echo $_helper->productAttribute($_product, nl2br($_product->getShortDescription()), ‘short_description’) ?></div>
</div>
<?php endif;?><?php echo $this->getChildHtml(‘other’);?>
<?php if ($_product->isSaleable() && $this->hasOptions()):?>
<?php echo $this->getChildChildHtml(‘container1′, ”, true, true) ?>
<?php endif;?></div>
<div>
<?php echo $this->getChildHtml(‘media’) ?>
</div><div></div>
<?php if ($_product->isSaleable() && $this->hasOptions()):?>
<?php echo $this->getChildChildHtml(‘container2′, ”, true, true) ?>
<?php endif;?>
</form>
<script type=”text/javascript”>
//<![CDATA[
var productAddToCartForm = new VarienForm('product_addtocart_form');
productAddToCartForm.submit = function(){
if (this.validator.validate()) {
this.form.submit();
}
}.bind(productAddToCartForm);
//]]>
</script>
</div><div>
<?php echo $this->getChildHtml(‘description’) ?>
<?php echo $this->getChildHtml(‘additional’) ?>
<?php echo $this->getChildHtml(‘upsell_products’) ?>
<?php echo $this->getChildHtml(‘product_additional_data’) ?>
<?php echo $this->getProductId();?>
</div>
</div>
Make sure you have made backup of your magento project.
Very fine, really it helped me. But it would be better if these codes are not included in magento files.
Poor tutorial.
If you are planning to create a step-by-step for beginners, please be more descriptive.
All directions followed, but it did not work.
I can not troubleshoot because there is such a lack of information.
Please update before anybody else wastes their time.
Hi Craig,
I am very sorry that my tutorial did not help you. But I would like to mention, that time I was also a beginner for Magento.
But I have received a number of comments of appreciation.
And hope at this time you have got any better solution.
Regards,
Hey Great Post Thanx Really HelpFull….!!
Hey,
You may customise your templates for print link too as per your need and requirement.
I’ve followed your instructions from top to bottom a few times, but when I visit the print URL I’ve got a 404.
Any clue on what may be happening?
http://rehab.freelander.cat/catalog/product/print/id/11761
Well, I did everithing in the local, not in the core.
If I move the files to the core it does work, but I don’t feel confortable adding files to the core.
Looks like that if the files are just in the local folder it does not work.
hi,
thanks for the code, but i cannot seem to get it to work. Could you please post a zip/rar file with the code so I can work out where i went wrong!
thanks
Thanks for the code, it works fine and now onward to change the actual xml file to print the way I wanted to…
to Brendan: When I was copying the last step “print.phtml” I’ve noticed that some of the code came over wrong. In line 88:
getChildChildHtml(‘container1′, ”, true, true) ?>
The right single quote next to container1 came over not as single quote (need to replace) and the two single quote became a doubt quote.
Same for line 99:
getChildChildHtml(‘container2′, ”, true, true) ?>
See if this would help. Also I’ve noticed that two of the files in Step 2 and 3 can be confusing to locate as there are many files of the same name in the Magento installation. Also Step 4a the block of code contains two blocks, the first one ends at and the next line belongs to the product_print.phtml in a different folder. Just want to make sure you have those down as well.
Hi again,
Just spotted another thing of note: Step 2 in the block of code:
<a href=”getBaseurl();?>catalog/product/print/id/getProduct()->getId();?>” target=”_blank”>Print Product Detail
The end double quote is missing before ‘target=”_blank”‘, this will help make sure the print link opens a new window.
Thanks
Good idea, but poorly written. It works, but requires a good share of time.
Nothing for beginners.
Thank you so mutch for this! This functionality is exactly what I needed for a project, works great (after a little work….
I added:
<a href="#" onclick="popWin('helper(‘catalog/image’)->init($_product, ‘image’) ?>’, ‘gallery’, ‘width=520,height=520,left=50,top=50,location=no,status=yes,scrollbars=yes,resizable=yes’); return false;”>
<img id="image" src="helper(‘catalog/image’)->init($_product, ‘image’)->resize(250,250); ?>” alt=”htmlEscape($_product->getName()) ?>” title=”htmlEscape($_product->getName()) ?>” />
to the print.phtml to get the product image on there.
Pingback: 2010 in review | Web Development
Hi. What about print all the images of the product?
Thanks in advance.
Very nice tutorial, worked for me too. thanks!
I am trying to do this on 1.5 and have follwed the steps and it does not work, please can someone help
can anyone point me to a similar tutorial for 1.5 if there is any?
Hello all,
Many thanks and congratulations for an excellent tutorial – it seems to have helped many people. This is a note for those of you who can’t quite make it work, or perhaps just want to explore other options for a printable PDF per product page. Take a look at Catalog-on-Demand, Flyer Edition. Our product page is http://www.catalog-on-demand.com/plans/catalog-on-demand_for_magento.php. Use the contact form if you have questions or comments. Also – there is a discount coupon code on our Magento Connect page.