How to display Attribute Group Name on Product page? - magento

I created Attribute Sets with more Grouped attributes inside. In admin, the custom attributes are displayed in groups (tabs) like I created them. But, on the product page, all the attributes are listed together, without displaying the Attribute Group Name before listing the Attributes in that Group.
How can I display also the Attribute Group names, not only the attributes? If you could show me on the default template, I will do it accordingly in my custom template.
Thank you!

Ok, I found an answer and I hope it will be useful to others in search for the same thing.
First, I'm using Magento 1.5.0.
Second, I found the answer in German here, with an extension already created, but the installation failed.
So, I added /app/code/local/Mage/Catalog/Block/Product/View/Attributesgroups.php with the following code:
<?php
class Mage_Catalog_Block_Product_View_Attributesgroups extends Mage_Core_Block_Template
{
protected $_product = null;
function getProduct()
{
if (!$this->_product) {
$this->_product = Mage::registry('product');
}
return $this->_product;
}
public function getAdditionalData(array $excludeAttr = array())
{
$data = array();
$product = $this->getProduct();
$attributes = $product->getAttributes();
foreach ($attributes as $attribute) {
if ($attribute->getIsVisibleOnFront() && !in_array($attribute->getAttributeCode(), $excludeAttr)) {
$value = $attribute->getFrontend()->getValue($product);
// TODO this is temporary skipping eco taxes
if (is_string($value)) {
if (strlen($value) && $product->hasData($attribute->getAttributeCode())) {
if ($attribute->getFrontendInput() == 'price') {
$value = Mage::app()->getStore()->convertPrice($value,true);
} elseif (!$attribute->getIsHtmlAllowedOnFront()) {
$value = $this->htmlEscape($value);
}
$group = 0;
if( $tmp = $attribute->getData('attribute_group_id') ) {
$group = $tmp;
}
$data[$group]['items'][ $attribute->getAttributeCode()] = array(
'label' => $attribute->getFrontend()->getLabel(),
'value' => $value,
'code' => $attribute->getAttributeCode()
);
$data[$group]['attrid'] = $attribute->getId();
}
}
}
}
// Noch Titel lesen
foreach( $data AS $groupId => &$group ) {
$groupModel = Mage::getModel('eav/entity_attribute_group')->load( $groupId );
$group['title'] = $groupModel->getAttributeGroupName();
}
return $data;
}
}
Then, I created the /app/design/frontend/default/YOUR_TEMPLATE/template/catalog/product/view/attributesgroups.phtml file with the following content:
<?php
$_helper = $this->helper('catalog/output');
$_product = $this->getProduct()
?>
<?php if($_additionalgroup = $this->getAdditionalData()): ?>
<div class="box-collateral box-additional">
<h2><?php echo $this->__('Additional Information') ?></h2>
<?php $i=0; foreach ($_additionalgroup as $_additional): $i++; ?>
<h3><?php echo $this->__( $_additional['title'] )?></h3>
<table class="data-table" id="product-attribute-specs-table-<?php echo $i?>">
<col width="25%" />
<col />
<tbody>
<?php foreach ($_additional['items'] as $_data): ?>
<tr>
<th class="label"><?php echo $this->htmlEscape($this->__($_data['label'])) ?></th>
<td class="data"><?php echo $_helper->productAttribute($_product, $_data['value'], $_data['code']) ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<script type="text/javascript">decorateTable('product-attribute-specs-table-<?php echo $i?>')</script>
<?php endforeach; ?>
</div>
<?php endif;?>
Last step was to modify /app/design/frontend/default/YOUR_TEMPLATE/layout/catalog.xml in line 223, and replaced
<block type="catalog/product_view_attributes" name="product.attributes" as="additional" template="catalog/product/view/attributes.phtml">
with
<block type="catalog/product_view_attributesgroups" name="product.attributes" as="additional" template="catalog/product/view/attributesgroups.phtml">
I repeat, this answer does NOT belong to me, I just translated what I found. Many thanks to the beautiful people who ended my three days of search with a clean and simple answer: WebGuys.DE
Also, thanks to #rpSetzer who cared to help!

Iterate through all the attributes and create an array of groups. In each group you put the attributes that belong to it. Then it's simple to display them the way you wanted.
Here is an implementation that is very close to what you need.

Thanks for translation : additionnal information for those who may need :
For 1st step, if the folder /app/code/local/Mage/Catalog/Block/Product/View/ doesn't exist, create it ! with correct persmissions and place the file Attributesgroups.php there
If you have different store views (for different languages), and you want to use correct translation for each attribute label, here is want you need to do :
In the file Attributesgroups.php
Replace 'label' => $attribute->getFrontend()->getLabel(), with'label' => $attribute->getStoreLabel(),

Related

How to make sure that foreach loop data shows in correct set position views

I have a controller that shows modules for my each position
Array
(
[0] => Array
(
[layout_module_id] => 1
[layout_id] => 1
[module_id] => 1
[position] => column_left
[sort_order] => 1
)
[1] => Array
(
[layout_module_id] => 2
[layout_id] => 1
[module_id] => 2
[position] => column_left
[sort_order] => 2
)
)
Above currently I have only two modules set and the are in the position of column left.
Because the position views are out side of the foreach loop they are picking up that module even though not set for that position? As shown in image.
Question: How can I make sure that the module will only display in its set position view.
public function index() {
$layout_id = $this->getlayoutID($this->router->class);
$modules = $this->getlayoutsmodule($layout_id);
echo '<pre>';
print_r($modules);
echo "</pre>";
$data['modules'] = array();
foreach ($modules as $module) {
$this->load->library('module/question_help');
$data['modules'][] = $this->load->view('module/question_help', $this->question_help->set(), TRUE);
}
// Position Views
$data['column_left'] = $this->load->view('column_left', $data, TRUE);
$data['column_right'] = $this->load->view('column_right', $data, TRUE);
$data['content_top'] = $this->load->view('content_top', $data, TRUE);
$data['content_bottom'] = $this->load->view('content_bottom', $data, TRUE);
// Main view
$this->load->view('welcome_message', $data);
}
public function getlayoutsmodule($layout_id) {
$this->db->select('*');
$this->db->from('layouts_module');
$this->db->where('layout_id', $layout_id);
$query = $this->db->get();
if ($query->num_rows() > 0) {
return $query->result_array();
}
}
Each of the position views have the same foreach loop
<?php if ($modules) { ?>
<?php foreach ($modules as $module) { ?>
<?php echo $module;?>
<?php } ?>
<?php }?>
main view
<div class="container">
<div class="row">
<?php echo $column_left; ?>
<?php if ($column_left && $column_right) { ?>
<?php $class = 'col-sm-6'; ?>
<?php } elseif ($column_left || $column_right) { ?>
<?php $class = 'col-sm-9'; ?>
<?php } else { ?>
<?php $class = 'col-sm-12'; ?>
<?php } ?>
<div id="content" class="<?php echo $class; ?>">
<?php echo $content_top; ?>
<h1>Welcome to CodeIgniter!</h1>
<div id="body">
<p>The page you are looking at is being generated dynamically by CodeIgniter.</p>
<p>If you would like to edit this page you'll find it located at:</p>
<code>application/views/welcome_message.php</code>
<p>The corresponding controller for this page is found at:</p>
<code>application/controllers/Welcome.php</code>
<p>If you are exploring CodeIgniter for the very first time, you should start by reading the User Guide.</p>
</div>
<p class="footer">Page rendered in <strong>{elapsed_time}</strong> seconds. <?php echo (ENVIRONMENT === 'development') ? 'CodeIgniter Version <strong>' . CI_VERSION . '</strong>' : '' ?></p>
<?php echo $content_bottom; ?>
</div>
<?php echo $column_right; ?></div>
</div>
I would do it like this (not sure if the library needs to be loaded in each iteration but leaving it there):
$tmpdata = array();
foreach ($modules as $module) {
$this->load->library('module/question_help');
$tmpdata[$module['position']]['modules'][] = $this->load->view('module/question_help', $this->question_help->set(), TRUE);
}
$data = array();
foreach ($tmpdata as $pos => $mods) {
$data[$pos] = $this->load->view($pos, $tmpdata[$pos], TRUE);
}
$this->load->view('welcome_message', $data);
Passing $tmpdata[$pos] to each position's view makes the array called $modules available, so in the views, just use
if ($modules) {
foreach ($modules as $module) {
echo $module;
}
}
as before.
This keeps it dynamic and you don't have to modify this code if you change or add positions. I'm using two data arrays just to avoid passing unnecessary data.

Change the order of totals

I'm having some troubles figuring out how to change the order of the totals in the transactional email templates (In Magento).
Basicly I want the 'Tax' row to be at the very bottom - below 'Grand total incl. tax'.
I know that this is the code, that prints the rows. But I can't seem to figure out how to change the order of the rows.
<?php foreach ($this->getTotals() as $_code => $_total): ?>
<?php if ($_total->getBlockName()): ?>
<?php echo $this->getChildHtml($_total->getBlockName(), false); ?>
<?php else:?>
<tr class="<?php echo $_code?>">
<td <?php echo $this->getLabelProperties()?>>
<?php if ($_total->getStrong()):?>
<?php echo $this->escapeHtml($_total->getLabel());?>
<?php else:?>
<?php echo $this->escapeHtml($_total->getLabel());?>
<?php endif?>
</td>
<td <?php echo $this->getValueProperties()?>>
<?php if ($_total->getStrong()):?>
<?php echo $this->formatValue($_total) ?>
<?php else:?>
<?php echo $this->formatValue($_total) ?>
<?php endif?>
</td>
</tr>
<?php endif?>
Could anyone be of help with this problem?
Thanks and have a wonderful day!
Method 1: Modifying the theme template file.
Copy app/design/frontend/base/sales/order/totals.phtml to your theme file and open it.
Add the following to the top of it.
if($tax = $this->getTotal('tax'))
{
$this->removeTotal('tax');
$this->addTotal($tax, 'grand_total');
}
This code will remove the tax from the totals list, then re-add it below the Grand Total. You should move the totals.phtml file into your custom theme folder so upgrades won't override it.
Method 2: Overriding the core block file.
You can do the same patch by overriding the core Totals block by doing the following:
Copy app/code/core/Mage/Sales/Block/Order/Totals.php to app/code/local/Mage/Sales/Block/Order/Totals.php
Open app/code/local/Mage/Sales/Block/Order/Totals.php and change the getTotals() function to the following:
public function getTotals($area=null)
{
//Move tax below grand_total
if($tax = $this->getTotal('tax'))
{
$this->removeTotal('tax');
$this->addTotal($tax, 'grand_total');
}
$totals = array();
if ($area === null) {
$totals = $this->_totals;
} else {
$area = (string)$area;
foreach ($this->_totals as $total) {
$totalArea = (string) $total->getArea();
if ($totalArea == $area) {
$totals[] = $total;
}
}
}
return $totals;
}

Start using time for product (License type)

In checkout cart mornitor, i added a datepicker for earch product in cart to allow cusommer selecting start using date (within 1 month from now).
I want to save this datepicker to onepage when click place-order. It will save to order.
I already create attribute in eav_attribute.
In config.xml i use this code:
<events>
<controller_action_predispatch_checkout_cart_index >
<observers>
<licensetime_observer>
<class>licensetime/observer</class>
<method>saveLicensetime</method>
</licensetime_observer>
</observers>
</controller_action_predispatch_checkout_cart_index>
</events>
And observer i was try to var_dump but start_date is null
public function saveLicensetime($observer)
{
$event = $observer->getEvent();
$product = $event->getProduct();
$quote = Mage::getSingleton('checkout/type_onepage')->getQuote();
$licenseStartDate = $quote->getLicense_start_date();
if (!$licenseStartDate) {
$licenseStartDate = date ("Y-m-d H:i:s", floor(time()/86400)*86400);
}
//var_dump($quote); die("aaaaaaaaaaa");
}
In cart/item/defaul.phtml datepicker code:
<label for="license_start_date"><?php echo $this->__('Start Date') ?> :</label>
<input name="cart[<?php echo $_item->getId() ?>][license_start_date]" readonly="true" id="license_start_date<?php echo $_item->getProductId(); ?>" value="<?php echo $this->getLicenseStartTime($_item->getId()) ?>" class="date-picker" />
<label for="license_end_date"><?php echo $this->__('End Date') ?> :</label>
<input readonly="true" name="cart[<?php echo $_item->getId() ?>][license_end_date]" id="license_end_date<?php echo $_item->getProductId(); ?>" value="<?php echo $this->getLicenseEndTime($_item->getId()) ?>"></input>
I'm trying this article but no luck!
Magento change Custom Option value before adding it to cart
Sorry, my E not well!
After few days ago, i'm hard-working and know that:
- Override app/code/core/Mage/Checkout/Model/Cart.php and edit function like that:
public function updateItems($data)
{
Mage::dispatchEvent('checkout_cart_update_items_before', array('cart'=>$this, 'info'=>$data));
foreach ($data as $itemId => $itemInfo) {
$item = $this->getQuote()->getItemById($itemId);
if (!$item) {
continue;
}
if (!empty($itemInfo['remove']) || (isset($itemInfo['qty']) && $itemInfo['qty']=='0')) {
$this->removeItem($itemId);
continue;
}
$qty = isset($itemInfo['qty']) ? (float) $itemInfo['qty'] : false;
if ($qty > 0) {
$item->setQty($qty);
}
/* Start: Custom code added for license start date */
if(!empty($itemInfo['license_start_date'])) {
$write = Mage::getSingleton('core/resource')->getConnection('core_write');
# make the frame_queue active
$query = "UPDATE `sales_flat_quote_item` SET license_start_date = '".$itemInfo['license_start_date']."' where item_id = $itemId";
$write->query($query);
$item->setLicense_start_date($itemInfo['license_start_date']);
}
/* End: Custom code added for licensee start date */
}
Mage::dispatchEvent('checkout_cart_update_items_after', array('cart'=>$this, 'info'=>$data));
return $this;
}
and copy app/code/core/Mage/Adminhtml/Block/Sales/Order/Items/Abstract.php to local (app/code/local/Mage/Adminhtml/Block/Sales/Order/Items/Abstract.php) and add this function:
public function getLicense_start_date($item) {
$itemId = $item->getId();
$write = Mage::getSingleton('core/resource')->getConnection('core_write');
$query = "SELECT q.* FROM `sales_flat_order_item` o
LEFT JOIN `sales_flat_quote_item` q on o.quote_item_id = q.item_id
WHERE o.item_id = $itemId";
# For older versions of Magento
/* $query = "SELECT q.* FROM `sales_order_entity_int` o
LEFT JOIN `sales_flat_quote_item` q on o.value = q.entity_id
WHERE o.entity_id = $itemId AND o.attribute_id = 343"; */
$res = $write->query($query);
while ($row = $res->fetch() ) {
if(key_exists('itemcomment',$row)) {
echo nl2br($row['itemcomment']);
}
}
}
To add the license time column to the items edit the .phtml file below:
app/design/adminhtml/default/default/template/sales/order/view/items.phtml (you can add you theme in adminhtml to edit)
Adding header for items to make it look like below:
<tr class="headings">
<th><?php echo $this->helper('sales')->__('Product') ?></th>
<th><?php echo $this->helper('sales')->__('Licens Time') ?></th>
<th><?php echo $this->helper('sales')->__('Item Status') ?></th>
And adding Column with comments. app/design/adminhtml/default/default/template/sales/order/view/items/renderer/default.phtml
Add a column for item comments juts before status columns to make it look a like below.
<td><?php echo $this->getLicense_start_date($_item) ?></td> <!-- New column added for item comments -->
<td class="a-center"><?php echo $_item->getStatus() ?></td>
Note that: In your theme, for the file: template/checkout/cart.phtml
Add the new heading along with other heading for cart items and in the file: template/checkout/cart/item/default.phtml use datepicker to selected date with code like below:
<td class="a-center">
<input type="text" name="cart[<?php echo $_item->getId() ?>][license_start_date]" rows="3" cols="20"><?php echo $_item->getLicense_start_date() ?></input>
</td>

Displaying Specific Magento Categories From Category ID

As of yet, I haven't managed to find anything online that already caters for what I'm trying to achieve. I simply want to call in specific categories to a list but I want to be able to define which categories by ID, so for example, I would like to be able to call them in like something such as the below:-
{{block type="catalog/navigation" name="catalog.category" template="developer/extension/script.phtml" ids="3,6,17,143,57"}}
I'm already displaying a list of sub categories in various places based on the parent category ID but in instances where there are hundreds of sub categories, it isn't always practical to display all of them, so I'm wondering if the existing script can possibly be tweaked to only include specific categories as per above?
<?php
//gets all sub categories of parent category 'cat-id-4'
$cats = Mage::getModel('catalog/category')->load(4)->getChildren();
$catIds = explode(',',$cats);
$categories = array();
foreach($catIds as $catId) {
$category = Mage::getModel('catalog/category')->load($catId);
$categories[$category->getName()] = array(
'url' => $category->getUrl(),
'img' => $category->getImageUrl()
);
}
ksort($categories, SORT_STRING);
?>
<ul>
<?php if($category->getIsActive()): ?>
<?php foreach($categories as $name => $data): ?>
<li>
<?php echo $name; ?>
</li>
<?php endforeach; ?>
<?php endif; ?>
</ul>
If anyone could advise how I could possibly achieve this please, that would be fantastic - Thanks in advance.
This should work with your given CMS block code:
<?php
$catIds = explode(',', $this->getIds()); //<-- ONLY CHANGE MADE
$categories = array();
foreach($catIds as $catId) {
$category = Mage::getModel('catalog/category')->load($catId);
$categories[$category->getName()] = array(
'url' => $category->getUrl(),
'img' => $category->getImageUrl()
);
}
ksort($categories, SORT_STRING);
?>
<ul>
<?php if($category->getIsActive()): ?>
<?php foreach($categories as $name => $data): ?>
<li>
<?php echo $name; ?>
</li>
<?php endforeach; ?>
<?php endif; ?>
</ul>

All Addtional Attributes for Grouped Products in Magento

Similar to the question asked at:
Magento - Show Custom Attributes in Grouped Product table
I'd like to display attributes of simple products in the grouped product page.
However, I need it to work such that you do not explicitly specify which attributes get displayed. Instead, it displays all the attributes that would get displayed on the simple product view of that product.
I've tried variations of:
(from /template/catalog/product/view/type/grouped.phtml)
<?php foreach ($_associatedProducts as $_item): ?>
<tr>
<td><?php echo $this->htmlEscape($_item->getName()) ?></td>
<!-- important problem part -->
<?php foreach ($_item->getAttributes() as $arr): ?>
<td><?php echo $arr->getData() ?></td>
<?php endforeach; ?>
<!-- end of problem part -->
<td class="a-right">
<?php echo $this->getPriceHtml($_item, true) ?>
</td>
<?php if ($_product->isSaleable()): ?>
<td class="a-center">
<?php if ($_item->isSaleable()) : ?>
View
<?php else: ?>
<p class="availability"><span class="out-of-stock"><?php echo $this->__('Out of stock.') ?></span></p>
<?php endif; ?>
</td>
<?php endif; ?>
</tr>
<?php endforeach; ?>
And other variations, however, I cannot limit the attributes being displayed to just the ones I need (i.e. just the additional attributes displayed on the simple product view; those set as Viewable on Frontend). Any ideas?
The class Mage_Catalog_Block_Product_View_Attributes method getAdditionalData() should point you toward how to limit the variables to only those that are selected as Viewable on Frontend. Its getAdditionalData method is referenced in the product view block.
The steps to solving this would be the following:
1. Create a new Magento module with the intent to override the grouped product block.
2. Create the new grouped product block, stealing liberally from the getAdditionalData() method of Mage_Catalog_Block_Product_View_Attributes.
3. Create a new template based on /template/catalog/product/view/type/grouped.phtml to back your custom block.
4. Override the block in your module's config.xml (see: Overriding catalog/breadcrumbs and catalog/products/view, Magento forums)
This has the consequence that all your grouped products in the catalog will behave this way. If you need to be more selective, then I think a reasonable thing to do would be to add a custom attribute to catalog products (preferably set up in the custom module you just created!) in order to toggle the behavior, and program a check for that toggle into your template.
Add after $_product = $this->getProduct();
/* CODE TO GET ATTRIBUTES */
$gridattributes = array();
$attributes = $_product->getAttributes();
foreach ($attributes as $attribute) {
if ($attribute->getIsVisibleOnFront() && !in_array($attribute->getAttributeCode(), $excludeAttr)) {
$value = $attribute->getFrontend()->getValue($_product);
if (!$_product->hasData($attribute->getAttributeCode())) {
$value = Mage::helper('catalog')->__('N/A');
} elseif ((string)$value == '') {
$value = Mage::helper('catalog')->__('No');
} elseif ($attribute->getFrontendInput() == 'price' && is_string($value)) {
$value = Mage::app()->getStore()->convertPrice($value, true);
}
if (is_string($value) && strlen($value)) {
$gridattributes[$attribute->getAttributeCode()] = array(
'label' => $attribute->getStoreLabel(),
'value' => $value,
'code' => $attribute->getAttributeCode()
);
}
}
}
?>
Add after <th><?php echo $this->__('Product Name') ?></th>:
foreach($gridattributes as $attrib){
echo '<th>'.$this->htmlEscape($attrib[label]).'</th>';
}
Add after <td><?php echo $this->htmlEscape($_item->getName()) ?></td>:
foreach($gridattributes as $attribname=>$attribval){
echo '<td>'.$this->htmlEscape($_item->getData($attribname)).'</td>';
}

Resources