Categories for layered navigation in Magento - magento

I'm looking to enhance the layered navigation in Magento.
Presently, attributes that are used in layered navigation can't be grouped, meaning if you have several attributes that are logically in one group (i.e. attributes "height", "width" & "depth" which are "Dimensions", and "color" and "texture" belong in an "Appearance" section).
I think this would enhance the usability and navigation for users.
Before I go ahead and begin developing a module for this, I was wondering if anyone came across something like this for magento, and if not, do you have any tips how this should be done?
Joseph

I created a module for this. Here are the changes I made:
MyName/Navigation/Catalog/Model/Layer.php:
class MyName_Navigation_Catalog_Model_Layer extends Mage_Catalog_Model_Layer {
public function getFilterableAttributes()
{
$setIds = $this->_getSetIds();
if (!$setIds) {
return array();
}
$collection = Mage::getResourceModel('catalog/product_attribute_collection')
->setItemObjectClass('catalog/resource_eav_attribute');
$collection->addSetInfo(true);
$collection->getSelect()->distinct(true);
$collection
->setAttributeSetFilter($setIds)
->addStoreLabel(Mage::app()->getStore()->getId())
->setOrder('position', 'ASC');
$collection = $this->_prepareAttributeCollection($collection);
$collection->load();
return $collection;
}
}
I'm just rewriting the overridden function from Mage_Catalog_Model_Layer with that addition of the line:
$collection->addSetInfo(true);
This ensures that the group data will be loaded when I need it.
The next two changes just allow you to access the data.
MyName/Navigation/Catalog/Model/Layer/Attribute.php:
class MyName_Navigation_Catalog_Model_Layer_Filter_Attribute extends Mage_Catalog_Model_Layer_Filter_Attribute {
public function getGroupName($setId = 4) {
$attribute = $this->getAttributeModel();
$group_id = $attribute->getData('attribute_set_info/' . $setId . '/group_id');
$group = Mage::getModel('eav/entity_attribute_group')->load($group_id);
$group_name = $group->getData('attribute_group_name');
return $group_name;
}
}
MyName/Navigation/Catalog/Model/Layer/Item.php:
class MyName_Navigation_Catalog_Model_Layer_Filter_Item extends Mage_Catalog_Model_Layer_Filter_Item {
public function getGroupName()
{
return $this->getFilter()->getGroupName();
}
}
MyName/Navigation/Catalog/Block/Layer/Filter/Attribute.php:
class MyName_Navigation_Catalog_Block_Layer_Filter_Attribute extends Mage_Catalog_Block_Layer_Filter_Attribute {
public function getGroupName() {
return $this->_filter->getGroupName();
}
}
Tell magento to use my module and not the core files.
MyName/Navigation/etc/config.xml
<?xml version="1.0" encoding="UTF-8"?>
<config>
<modules>
<MyName_Navigation>
<version>0.1.0</version>
</MyName_Navigation>
</modules>
<global>
<blocks>
<catalog>
<rewrite>
<layer_filter_attribute>MyName_Navigation_Catalog_Block_Layer_Filter_Attribute</layer_filter_attribute>
</rewrite>
</catalog>
</blocks>
<models>
<catalog>
<rewrite>
<layer>MyName_Navigation_Catalog_Model_Layer</layer>
<layer_filter_attribute>MyName_Navigation_Catalog_Model_Layer_Filter_Attribute</layer_filter_attribute>
<layer_filter_item>MyName_Navigation_Catalog_Model_Layer_Filter_Item</layer_filter_item>
</rewrite>
</catalog>
</models>
</global>
</config>
Now you can call
$_item->getGroupName();
from your template file: template/catalog/layer/filter.php
or
$_filter->getGroupName();
from your template file: template/catalog/layer/view.php
and Group/Sort the attributes from there.

The code for the filtered navigation has been on the Magento forums for a long time, it still works in the most recent versions:
http://www.magentocommerce.com/boards/viewthread/5500/
This may provide what you need to customise the appearance of the filtered navigation to suit your needs.
You can also define in your attribute the sort order in the layered navigation. Rather than use '1, 2, 3' go for '100, 200, 300' so that later on you can define - say - 'width' to 210, etc. and slot the attributes in to the sort order you need.

Related

Magento - Add custom block to existing tab in catalog product edit view

I need to add some content to the top of the images tab in the catalog product edit view. I do not want to add a new tab, i want to include some content (custom block) to the existing one.
I have seen a lot of tutorials on how to add a whole new tab, but nothing on how to edit an existing one.
I have managed to create an observer on the event "core_block_abstract_prepare_layout_after":
<core_block_abstract_prepare_layout_after>
<observers>
<edit_images_tab>
<type>singleton</type>
<class>custom_module/observer</class>
<method>editImagesTab</method>
</edit_images_tab>
</observers>
</core_block_abstract_prepare_layout_after>
and remove and recreate the tab in the same position:
public function editImagesTab(Varien_Event_Observer $observer) {
$block = $observer->getEvent()->getBlock();
if ($block instanceof Mage_Adminhtml_Block_Catalog_Product_Edit_Tabs) {
$block->removeTab('group_10');
$block->addTabAfter(
'group_10',
array(
'label' => 'Upload Product Files',
'content' => $block->getLayout()->createBlock('adminhtml/catalog_product_helper_form_gallery_content')->toHtml() . 'custom content'
),
'group_9'
);
}
}
Anyway, it seems that $block->getLayout()->createBlock('adminhtml/catalog_product_helper_form_gallery_content')->toHtml() is not enough to recreate the images tab.
Not sure if i'm going in the right direction.
Any hint would be greatly appreciated.
I've found another way to achieve my goal, here is what I did.
I have overridden the method toHtml() of the class "Mage_Adminhtml_Block_Catalog_Product_Helper_Form_Gallery" in that way:
class Custom_Module_Block_Adminhtml_Catalog_Product_Helper_Form_Gallery
extends Mage_Adminhtml_Block_Catalog_Product_Helper_Form_Gallery {
public function toHtml() {
$myBlock = Mage::getSingleton('core/layout')->createBlock('custom_module/custom_block')->toHtml();
return $myBlock . parent::toHtml();
}
}
and added this in the config.xml file:
<global>
<blocks>
<adminhtml>
<rewrite>
<catalog_product_helper_form_gallery>Custom_Module_Block_Adminhtml_Catalog_Product_Helper_Form_Gallery</catalog_product_helper_form_gallery>
</rewrite>
</adminhtml>
</blocks>
</global>
not sure if this is the best approach but it works.

Override Mage_Catalog_Model_Resource_Product_Collection

I'm trying to override this class in order to change the behavior of the function
_applyProductLimitations
and add another new function (so i can filter by two or more categories)
Anyone can help telling me how to override it in order that all the product collection can call my new function without getting the error that it's not defined in
Mage_Catalog_Model_Resource_Product_Collection ?
Thanks :)
add this to the config.xml file of your module under the <global> tag
<models>
<catalog_resource>
<rewrite>
<product_collection>Namespace_Module_Model_Resource_Product_Collection</product_collection>
</rewrite>
</catalog_resource>
</models>
Then create the file app/code/local/Namespace/Module/Model/Resource/Product/Collection.php with the following content.
<?php
class Namespace_Module_Model_Resource_Product_Collection extends Mage_Catalog_Model_Resource_Product_Collection {
protected function _applyProductLimitations(){
//your magic here
}
}

Magento - Convert a module using <rewrite> to use Events for the Sales > Order Grid

I've made a simple module that adds extra fields to the Sales > Order Grid. It works great but the problem is that another module we're using <rewrites> the order grid to add their field to the grid. I wanted to try to change it to use Events instead (besides, it's a better method)...
The issue is that I've been trying and trying and I just can't make it happen. (Maybe I just can't grasp the event/observer concept yet...)
Here is my current module structure:
app/code/local/Artizara/OrderGridAdditions/
app/code/local/Artizara/OrderGridAdditions/Block/Sales/Order/Grid.php
app/code/local/Artizara/OrderGridAdditions/etc/config.xml
app/code/local/Artizara/OrderGridAdditions/controllers [empty]
app/code/local/Artizara/OrderGridAdditions/Helper [empty]
app/code/local/Artizara/OrderGridAdditions/Model [empty]
Inside my Grid.php file, I have copied the main Grid.php file contents into my Grid.php file and edited the _getCollectionClass(), _prepareCollection() and _prepareColumns() functions.
I've changed the _getCollectionClass() to this:
//return 'sales/order_grid_collection';
return 'sales/order_collection';
I've changed the _prepareCollection() to this:
$collection = Mage::getResourceModel($this->_getCollectionClass());
$collection->getSelect()->joinLeft(array('sfog' => 'sales_flat_order_grid'),'main_table.entity_id = sfog.entity_id',array('sfog.shipping_name','sfog.billing_name'));
$collection->getSelect()->joinLeft(array('sfo'=>'sales_flat_order'),'sfo.entity_id=main_table.entity_id',array('sfo.customer_email','sfo.weight','sfo.discount_description','sfo.increment_id','sfo.store_id','sfo.created_at','sfo.status','sfo.base_grand_total','sfo.grand_total','shipping_description','sfo.total_item_count'));
$collection->getSelect()->joinLeft(array('sfoa'=>'sales_flat_order_address'),'main_table.entity_id = sfoa.parent_id AND sfoa.address_type="shipping"',array('sfoa.street','sfoa.city','sfoa.region','sfoa.postcode','sfoa.telephone'));
//$collection->getSelect()->joinLeft(array('sfop' => 'sales_flat_order_payment'),'main_table.entity_id = sfop.entity_id',array('sfop.method'));
$this->setCollection($collection);
return parent::_prepareCollection();
I've added columns to the _prepareColumns() like this (only added one here as example):
$this->addColumn('total_item_count', array(
'header' => Mage::helper('sales')->__('Total Items'),
'index' => 'total_item_count',
'filter_index' => 'sfo.total_item_count',
'width' => '50px',
));
In my config.xml file I have a simple <rewrite>:
<modules>
<Artizara_OrderGridAdditions>
<version>0.1.0</version>
</Artizara_OrderGridAdditions>
</modules>
<global>
<blocks>
<adminhtml>
<rewrite>
<sales_order_grid>Artizara_OrderGridAdditions_Block_Sales_Order_Grid</sales_order_grid>
</rewrite>
</adminhtml>
<ordergridadditions>
<class>Artizara_OrderGridAdditions_Block</class>
</ordergridadditions>
</blocks>
</global>
Changing it over to Events/Observers
I've been trying a lot to change this up to a module that uses an Event but am hitting a wall with it. I've been trying to follow some other answers on here (the ones that are not rewrites, but they use a different method to add custom tables to the grid from the database). I'm looking to use the same setup I already have.
I've added /Helper/Data.php container that contains this:
class Artizara_OrderGridAdditions_Helper_Data extends Mage_Core_Helper_Abstract{ }
In /etc/config.xml I've tried many things. Here's my latest attempt:
<modules>
<Artizara_OrderGridAdditions>
<version>0.1.0</version>
</Artizara_OrderGridAdditions>
</modules>
<adminhtml>
<events>
<adminhtml_block_html_before>
<observers>
<Artizara_OrderGridAdditions_Observer>
<class>Artizara_OrderGridAdditions_Model_Observer</class>
<method>addAdditionsToGrid</method>
</Artizara_OrderGridAdditions_Observer>
</observers>
</adminhtml_block_html_before>
</events>
</adminhtml>
<global>
<models>
<Artizara_OrderGridAdditions>
<class>Artizara_OrderGridAdditions_Model</class>
</Artizara_OrderGridAdditions>
</models>
<blocks>
<Artizara_OrderGridAdditions>
<class>Artizara_OrderGridAdditions_Block</class>
</Artizara_OrderGridAdditions>
</blocks>
<helper>
<Artizara_OrderGridAdditions>
<class>Artizara_OrderGridAdditions_Helper</class>
</Artizara_OrderGridAdditions>
</helper>
</global>
Then in /Model/Observer.php I have:
class Artizara_OrderGridAdditions_Model_Observer {
public function addAdditionsToGrid(Varien_Event_Observer $observer) {
// code here
}
}
Inside addAdditionsToGrid(), I've tried many different things including copying the entire Grid.php file but nothing seems to work (errors) :(
Please help guide me in remaking this simple module using Events please!
There is no (good) way to add a column to Sales Order Grid with Observers, because there is no event call. Take a look yourself for Mage::dispatchEvent inside Mage_Adminhtml_Block_Sales_Order_Grid and all superclasses.
I think the best practice is extend the grid class like this:
class Artizara_OrderGridAdditions_Block_Sales_Grid extends Mage_Adminhtml_Block_Sales_Order_Grid {
protected function _prepareColumns() {
$this->addColumn(/* your definition here */);
}
}
If you really need do this by observers, you can watch the adminhtml_block_html_before event and dig a way out, but a lot of blocks will call this event either.

How to send category based order emails in magento?

I have two root categories in my magento site. One is "Home Products" and the other is "Office products".
These two root categories have some sub categories also.
I want to send "Home Products" related orders to this email address "email_home#example.com",
And to send "Office Products" related orders to this email address "email_office#example.com".
How will I do this?
I suggest you to write own Observer to order.
sales_order_place_after
event suits best for your purpose.
If buyer can add to shopping cart items only from 1 cateogry.
Your module should:
Get order via observer.
Get order first item and get it's category
Choose email based on category
Send email
public function sendOrder(){
$order = $observer->getEvent()->getOrder();
...
//Implement logic here
...
$emailTemplate = Mage::getModel('core/email_template')
->loadDefault('your_template');
$emailTemplateVariables = array();
$emailTemplateVariables['order'] = $order;
$emailTemplate->setSenderName('Your shops name');
$emailTemplate->setSenderEmail('addres#from.com');
$emailTemplate->setTemplateSubject(Subject');
$emailTemplate->send('to#addres.com','Name', $emailTemplateVariables);
}
Update 1
First of all I insist that you see the link I provide in the comments area.
Then:
To create module:
Create in app/etc/modules/ Company_Module.xml file. With the content similiar to this one:
true
local
This eill tell magento, that in app/code/local/Company/Module there is something interesting to watch.
Create proper folder and file structure.
For you module I think it would be enough:
Company
-Module
--etc
---config.xml
--Model
---Observer.php
--Helper
---Data.php
Magento should know everything about your module. Moreover you should define observer for event.
Important note: we will catch Magento's event. Not ours.
config.xml:
<?xml version="1.0"?>
<config>
<modules>
<Company_Module>
<version>0.1.0</version>
</Company_Module>
</modules>
<global>
<models>
<company_module>
<class>Company_Module_Model</class>
</company_module>
</models>
<helpers>
<cmod>
<class>Company_Module_Helper</class>
</cmod>
</helpers>
<events>
<sales_order_place_after>
<observers>
<sales_order_place_after_observer>
<class>company_module/observer</class>
<method>handleOrder</method>
</sales_order_place_after_observer>
</observers>
</sales_order_place_after>
</events>
</global>
</config>
Data.php - It is empty but it should be.
class Company_Module_Helper_Data extends Mage_Core_Helper_Abstract{
}
Observer.php
class Company_Module_Model_Observer{
public function handleOrder($observer){
$order = $observer->getEvent()->getOrder();
...
//Implement logic here
...
$emailTemplate = Mage::getModel('core/email_template')
->loadDefault('your_template');
$emailTemplateVariables = array();
$emailTemplateVariables['order'] = $order;
$emailTemplate->setSenderName('Your shops name');
$emailTemplate->setSenderEmail('addres#from.com');
$emailTemplate->setTemplateSubject(Subject');
$emailTemplate->send('to#addres.com','Name', $emailTemplateVariables);
}
}
#Jevgeni (and anyone else needing the link), the Link for Magento has moved
http://www.magentocommerce.com/wiki/5_-_modules_and_development/0_-_module_development_in_magento/customizing_magento_using_event-observer_method

Magento 1.4 - Displaying some products under specific category

Hi
I have assigned 20 products to a category called Phone, I would like to create a module to retrieve these products and displayed as a list format. Could someone tell me how to do this?
thanks
To create a widget (which you can insert via the cms) that uses a category to do something, begin by creating a standard module structure with:
/Block
/etc
/Helper
/Model
Note that in my code samples and filenames below you will need to replace [Namespace], [Module], and [module] with the appropriate namespace and module that you want to use. Case is important!
Begin by creating app/code/local/[Namespace]/[Module]/etc/config.xml
<?xml version="1.0"?>
<config>
<modules>
<[Namespace]_[Module]>
<version>0.0.1</version>
</[Namespace]_[Module]>
</modules>
<global>
<helpers>
<[module]>
<class>[Namespace]_[Module]_Helper</class>
</[module]>
</helpers>
<blocks>
<[module]>
<class>[Namespace]_[Module]_Block</class>
</[module]>
</blocks>
<models>
<[module]>
<class>[Namespace]_[Module]_Model</class>
</[module]>
</models>
</global>
</config>
Then create a app/code/local/[Namespace]/[Module]/etc/widget.xml This widget includes a setting called "selected_category"
<?xml version="1.0"?>
<widgets>
<[module]_category type="[module]/category">
<name>[Module]: Category</name>
<description type="desc">Adds a [module] for a category.</description>
<parameters>
<selected_category>
<label>Categories</label>
<visible>1</visible>
<required>1</required>
<type>select</type>
<source_model>[module]/catopt</source_model>
</selected_category>
</parameters>
</[module]_category>
</widgets>
Then the obligatory Helper file in app/code/local/[Namespace]/[Module]/Helper/Data.php
<?php
class [Namespace]_[Module]_Helper_Data extends Mage_Core_Helper_Abstract
{
}
Then a model to allow the user to select the category in the widget dialog box. This goes in app/code/local/[Namespace]/[Module]/Model/Catopt.php
<?php
class [Namespace]_[Module]_Model_Catopt
{
public function toOptionArray()
{
$category = Mage::getModel('catalog/category');
$tree = $category->getTreeModel();
$tree->load();
$ids = $tree->getCollection()->getAllIds();
$arr = array();
if ($ids){
foreach ($ids as $id){
$cat = Mage::getModel('catalog/category');
$cat->load($id);
array_push($arr, array('value' => $id, 'label' => $cat->getName().' ('.$cat->getProductCount().')'));
}
}
uasort($arr, array($this, 'labelsort'));
return $arr;
}
function labelsort($a, $b){
if ( $a['label'] == $b['label'] )
return 0;
else if ( $a['label'] < $b['label'] )
return -1;
else
return 1;
}
}
Finally on the module side of things a block which goes in app/code/local/[Namespace]/[Module]/Block/Category.php This block is using a custom .phtml file for it's display but you can change that to use anything else you might need to show by changing the type of block and input to setTemplate.
<?php
class [Namespace]_[Module]_Block_Category
extends Mage_Core_Block_Template
implements Mage_Widget_Block_Interface
{
/**
* A model to serialize attributes
* #var Varien_Object
*/
protected $_serializer = null;
/**
* Initialization
*/
protected function _construct()
{
$this->_serializer = new Varien_Object();
$this->setTemplate('[module]/[module].phtml');
parent::_construct();
}
public function getCategory(){
return $this->getData('selected_category');
}
}
Don't forget to add a module install file under /app/etc/modules/[Namespace]_[Module].xml like this
<?xml version="1.0"?>
<config>
<modules>
<[Namespace]_[Module]>
<active>true</active>
<codePool>local</codePool>
<depends>
<Mage_Cms />
</depends>
</[Namespace]_[Module]>
</modules>
</config>
Lastly you need to create a template file to display the block content. This will go under /app/design/frontend/default/default/template/[module]/[module].phtml
This .phtml file can use $this->getCategory() to get the category and go from there. You can easily customize the block included in these samples to display the default magento product list grids instead of using a custom .phtml file.
No need to create a module. just place this in a block in your layout: It will show all the products linked to the specified category (id=XXX).
<!-- Show all products linked to this category -->
<block type="catalog/product_list" name="best_sellers" template="catalog/product/list.phtml">
<action method="setCategoryId">
<category_id>XXX</category_id>
</action>
</block>
Update:
You can create a module that overide the "Mage_Catalog_Block_Product_List", and add a method to limit a certain number of products.
1- Create "app/code/local/[Namespace]/Catalog/etc/config.xml" and put this in it:
<config>
<modules>
<[Namespace]_Catalog>
<version>0.1.0</version>
</[Namespace]_Catalog>
</modules>
<global>
<blocks>
<catalog>
<rewrite>
<product_list>[Namespace]_Catalog_Block_Product_List</product_list>
</rewrite>
</catalog>
</blocks>
</global>
</config>
2- Override the Block by creating the class: "app/code/local/[Namespace]/Catalog/Block/Product/List.php"
class [Namespace]_Catalog_Block_Product_List extends Mage_Catalog_Block_Product_List
{
/**
* Default number of product to show.
*
* #var int default = 5
*/
private $_productCount = 5;
/**
* Initialize the number of product to show.
*
* #param int $count
* #return Mage_Catalog_Block_Product_List
*/
public function setProductCount($count)
{
$this->_productCount = intval($count);
return $this;
}
/**
* Get the number of product to show.
*
* #return int
*/
public function getProductCount()
{
return $this->_productCount;
}
}
3- Overide your theme to add the product limit feature:
copy "app/design/frontend/default/default/template/catalog/product/list.phtml" to "app/design/frontend/default/[your_theme]/template/catalog/product/list.phtml"
// Insert between the foreachs and <li> for the list mode and grid mode
<?php if($_iterator < $this->getProductCount()) : ?>
...
// Insert between the foreachs and <li> for the list mode and grid mode
<?php endif; ?>
4- In the home page content tab, add this line where you want it:
// category_id = Procucts linked to this category
// product_count = Maximum number of product
{{block type="catalog/product_list" category_id="7" product_count="3" template="catalog/product/list.phtml"}}
Hope this help someone.
Thanks for the informative post. For those of you who are not so fluent in PHP but landed on this page because you were looking for a solution to display a product name list from a given category I managed to find a solution by simply modifying someone else's template file. For this solution I found the best suited extension was:
http://www.cubewebsites.com/blog/magento/extensions/freebie-magento-featured-products-widget-version-2/
(find the latest version on github: https://github.com/cubewebsites/Cube-Category-Featured-Products/tags).
After logging in and out and clearing the cache I was able to insert the widget into a static block and modify the .phtml file used to produce the custom view that I wanted.
The widget looked like this when inserted:
{{widget type="categoryfeatured/list" template="categoryfeatured/block.phtml" categories="118" num_products="10" products_per_row="1" product_type="all"}}.
I simply opened
app/design/frontend/base/default/template/categoryfeatured/block.phtml
copied it's contents and created a new .phtml file called category_product_listing.phtml
and then pointed the widget instance to the new .phtml file as follows:
{{widget type="categoryfeatured/list" template="categoryfeatured/category_product_listing.phtml" categories="118" num_products="10" products_per_row="1" product_type="all"}}.
I then went through this .phtml file with my basic understanding of PHP and removed all items like images, add to cart buttons, reviews, etc. until I was left with just the basic linked product title as well as the category title left intact.
I hope this helps someone as I spent hours trying to figure this out.

Resources