Overriding Mage_Wishlist_IndexController::addAction() in Magento - magento

I am having trouble overriding one of Magento's core controllers, the WishList Index Controller. When I add a product in the wishlist, I need Magento to redirect back to the product page instead of the wishlist. Here is what I did so far
Created a folder in app/code/local, called MyCompany, with a subfolder called Coreextensions.
Inside the Coreextensions folder, I created etc/config.xml, with the following content:
No, this instance is intended for use outside of production or under the RDS Free Usage Tier
<?xml version="1.0"?>
<config>
<modules>
<MyCompany_Coreextensions>
<version>0.1.0</version>
</MyCompany_Coreextensions>
</modules>
<frontend>
<routers>
<wishlist>
<args>
<modules>
<MyCompany_Coreextensions before="Mage_Wishlist">
MyCompany_Coreextensions_Wishlist
</MyCompany_Coreextensions>
</modules>
</args>
</wishlist>
</routers>
</frontend>
</config>
Inside Coreextensions folder, I created controllers/Wishlist/IndexController.php, like this:
<?php
/* Stay on product page after adding to wishlist */
require_once(Mage::getModuleDir('controllers','Mage_Wishlist').DS.'IndexController.php');
class MyCompany_Coreextensions_Wishlist_IndexController extends Mage_Wishlist_IndexController
{
/**
* Add the item to wish list
*
* #return Mage_Core_Controller_Varien_Action|void
*/
protected function _addItemToWishList()
{
$wishlist = $this->_getWishlist();
if (!$wishlist) {
return $this->norouteAction();
}
$session = Mage::getSingleton('customer/session');
$productId = (int)$this->getRequest()->getParam('product');
if (!$productId) {
$this->_redirect('*/');
return;
}
$product = Mage::getModel('catalog/product')->load($productId);
if (!$product->getId() || !$product->isVisibleInCatalog()) {
$session->addError($this->__('Cannot specify product.'));
$this->_redirect('*/');
return;
}
try {
$requestParams = $this->getRequest()->getParams();
if ($session->getBeforeWishlistRequest()) {
$requestParams = $session->getBeforeWishlistRequest();
$session->unsBeforeWishlistRequest();
}
$buyRequest = new Varien_Object($requestParams);
$result = $wishlist->addNewItem($product, $buyRequest);
if (is_string($result)) {
Mage::throwException($result);
}
$wishlist->save();
Mage::dispatchEvent(
'wishlist_add_product',
array(
'wishlist' => $wishlist,
'product' => $product,
'item' => $result
)
);
$referer = $session->getBeforeWishlistUrl();
if ($referer) {
$session->setBeforeWishlistUrl(null);
} else {
$referer = $this->_getRefererUrl();
}
/**
* Set referer to avoid referring to the compare popup window
*/
$session->setAddActionReferer($referer);
Mage::helper('wishlist')->calculate();
$message = $this->__('%1$s has been added to your wishlist. Click here to continue shopping.',
$product->getName(), Mage::helper('core')->escapeUrl($referer));
$session->addSuccess($message);
} catch (Mage_Core_Exception $e) {
$session->addError($this->__('An error occurred while adding item to wishlist: %s', $e->getMessage()));
}
catch (Exception $e) {
$session->addError($this->__('An error occurred while adding item to wishlist.'));
}
//$this->_redirect('*', array('wishlist_id' => $wishlist->getId()));
$this->_redirectReferer();
}
}
In app/etc/modules, I created MyCompany_Coreextensions.xml, like this:
<?xml version="1.0"?>
<!--we need to enable this module as any other if-->
<!--you wish to do it as standalone module extension-->
<config>
<modules>
<MyCompany_Coreextensions>
<active>true</active>
<codepool>local</codepool>
</MyCompany_Coreextensions>
</modules>
</config>
Of course, this doesn't work and it's driving me nuts. If I make the change in the Core file, it works as I want it to, but I wouldn't want to alter the Core files... Let me say that YES, I did clear the cache!

If you use Magento EE, you should replace:
<MyCompany_Coreextensions before="Mage_Wishlist">
with:
<MyCompany_Coreextensions before="Enterprise_Wishlist">

Your steps are right but only two things:
you have to add this row require_once Mage::getModuleDir('controllers', 'Mage_Wishlist') . DS . 'IndexController.php'; first of Controller class declaration;
the name of your Controller class must be without '_Wishlist' so MyCompany_Coreextensions_IndexController instead of MyCompany_Coreextensions_Wishlist_IndexController (you have to change it into config.xml too -> <MyCompany_Coreextensions before="Mage_Wishlist">MyCompany_Coreextensions</MyCompany_Coreextensions> instead of <MyCompany_Coreextensions before="Mage_Wishlist">MyCompany_Coreextensions_Wishlist</MyCompany_Coreextensions>)

Also you haven't "included" or "required" the original(core) IndexController of wishlist, you have to do in your module's index controller file like below:
require_once Mage::getModuleDir('controllers', 'Mage_Wishlist') . DS . 'IndexController.php';
The above code should be placed before any class declaration in your module's IndexController.php file.
Also you have spaces between "<" and tag names, so do remove them or xml structure will break, showing fatal errors in magento.
Once you do that refresh magento caches and then try adding product to wishlist, you will be redirected to previous url.

< codepool >local< /codepool >
You have to change codepool to codePool if you still not figure it out

Related

How to edit tag url in magento?

I want to make SEO friendly tag URL in magento.
Currently it is abc.com/tag/product/list/tagId/17/
but i want to make it abc.com/tag/xyz
I tried this by using "URL rewrite management" but it is not working.
Please help.
First I want to say that this is a nice question. Got me all fired up.
It works with the url management but it's kind of a drag. To much work.
For example I added this in the url management.
Type : Custom
Store: Select any store here - if you have more you have to do this process for each one
ID Path: TAG_23
Request Path: tag/camera
Target Path: tag/product/list/tagId/23
Redirect: No
Saved. now when calling ROOT/tag/camera I see the prodcts tagged with 'camera'.
But for sure this is not the way to go. if you have more than 10 tags you get bored.
So the idea is to make a module that will make magento recognize tags like tag/something and will change the links for tags to the same format above, so you won't have to edit a lot of templates.
I named the module Easylife_Tag. You need for it the following files.
app/etc/modules/Easylife_Tag.xml - the declaration file
<?xml version="1.0"?>
<config>
<modules>
<Easylife_Tag>
<codePool>local</codePool>
<active>true</active>
<depends>
<Mage_Tag />
</depends>
</Easylife_Tag>
</modules>
</config>
app/code/local/Easylife/Tag/etc/config.xml - the configuration file
<?xml version="1.0"?>
<config>
<modules>
<Easylife_Tag>
<version>1.0.0</version>
</Easylife_Tag>
</modules>
<global>
<events>
<controller_front_init_routers><!-- add a custom router to recognize urls like tag/something -->
<observers>
<easylife_tag>
<class>Easylife_Tag_Controller_Router</class>
<method>initControllerRouters</method>
</easylife_tag>
</observers>
</controller_front_init_routers>
</events>
<models>
<tag>
<rewrite>
<tag>Easylife_Tag_Model_Tag</tag><!-- rewrite the tag model to change the url of the tags to tag/something -->
</rewrite>
</tag>
<tag_resource>
<rewrite>
<tag>Easylife_Tag_Model_Resource_Tag</tag> <!-- rewrite the tag resource model - see below why is needed -->
</rewrite>
</tag_resource>
</models>
</global>
</config>
app/code/local/Easylife/Tag/Model/Tag.php - the rewritten tag model
<?php
class Easylife_Tag_Model_Tag extends Mage_Tag_Model_Tag {
//change the url from `tag/product/list/tagId/23` to `tag/camera`
public function getTaggedProductsUrl() {
return Mage::getUrl('', array('_direct' => 'tag/'.$this->getName()));
}
}
app/code/local/Easylife/Tag/Model/Resource/Tag.php - rewritten tag resource model
<?php
class Easylife_Tag_Model_Resource_Tag extends Mage_Tag_Model_Resource_Tag {
//by default, when loading a tag by name magento does not load the store ids it is allowed in
//this method loads also the store ids
public function loadByName($model, $name){
parent::loadByName($model, $name);
if ($model->getId()) {
$this->_afterLoad($model);
}
else {
return false;
}
}
}
app/code/local/Easylife/Tag/Controller/Router.php - the custom router - see comments inline
<?php
class Easylife_Tag_Controller_Router extends Mage_Core_Controller_Varien_Router_Abstract{
public function initControllerRouters($observer){
$front = $observer->getEvent()->getFront();
$front->addRouter('easylife_tag', $this);
return $this;
}
public function match(Zend_Controller_Request_Http $request){
//if magento is not installed redirect to install
if (!Mage::isInstalled()) {
Mage::app()->getFrontController()->getResponse()
->setRedirect(Mage::getUrl('install'))
->sendResponse();
exit;
}
//get the url key
$urlKey = trim($request->getPathInfo(), '/');
//explode by slash
$parts = explode('/', $urlKey);
//if there are not 2 parts (tag/something) in the url we don't care about it.
//return false and let the rest of the application take care of the url.
if (count($parts) != 2) {
return false;
}
//if the first part of the url key is not 'tag' we don't care about it
//return false and let the rest of the application take care of the url
if ($parts[0] != 'tag') {
return false;
}
$tagName = $parts[1]; //tag name
//load the tag model
$tag = Mage::getModel('tag/tag')->loadByName($tagName);
//if there is no tag with this name available in the current store just do nothing
if(!$tag->getId() || !$tag->isAvailableInStore()) {
return false;
}
//but if the tag is valid
//say to magento that the request should be mapped to `tag/product/list/tagId/ID_HERE` - the original url
$request->setModuleName('tag')
->setControllerName('product')
->setActionName('list')
->setParam('tagId', $tag->getId());
$request->setAlias(
Mage_Core_Model_Url_Rewrite::REWRITE_REQUEST_PATH_ALIAS,
$urlKey
);
return true;
}
}
That's it. Clear the cache and give it a go.
[EDIT].
You can find the full extension here. The only difference is that it uses the community code pool instead of local as described above.
Im using Magento 1.8.1 and tried the Marius's solution but I had one problem: 2+ keyword tags (with a space between words) was going to 404 page and the spaces in url were changed to %20. One keyword tag is working like a charm!
So, I modified his module to show a spaced word on Tag Module and 'hyphenized' in the URL.
File: Easylife/Tag/Model/Tag.php
return Mage::getUrl('', array('_direct' => 'tag/'.str_replace(" ", "-", $this->getName())));
File: Easylife/Tag/Controller/Router.php
$tagName = str_replace("-", " ", $parts[1]); //tag name
Its working for me now.
Best regards and thanks for the module Marius!

magento attributes filter only in last (level 3) category

I have category hierarchy up to level 3. ex,
Root Category
Category 1
Category 1.1
Category 1.1.1
Category 1.1.2
Category 1.1.3
Category 1.2
Category 1.2.1
Category 1.2.2
Category 1.2.3
Category 1.3
Category 2
. . .
. . .
. . .
Question
While browsing categories in layered navigation, the product's attribute's filters are displaying in all layers but i want to attribute filter in only last category (eg. 3rd level category). How to do that
Note: I have searched it a lot but on one question of magento meta, one answer was altering css to hide filters in particular page. but i want to do it on higher level ( without css and if possible then php hacks).
If you need to display layered navigation in level-3 only, you need to set a condition inside the template that render layered navigation block.
Layered navigation block is rendering by the template app/design/frontend/<your_package>/<your_theme>/template/catalog/layer/view.phtml. You have to modify the content as shown below
<?php
if(Mage::registry('current_category')->getData('level')== 4):
?>
<?php
/**
* Content in the template comes here :)
*
* Add content in this file, inside this condition
*/
?>
<?php endif; ?>
What we are done here is, we get the current category level using the method Mage::registry('current_category') and check whether it is level-4. If yes renders the content. else it will not.
Note : What you have described as level-3 in your context is actually level-4. That is because, magento counts root-category as level-1
Thats it. That will do the trick. Enjoy coding. Let me know if you have any doubts.
EDIT
So you need to display category navigation in all category levels, but need to show other filter attributes in level-4 only. If that is the case, let us implement it.
As I already stated, app/design/frontend/<your_package>/<your_theme>/template/catalog/layer/view.phtml is the starting point of layered navigation blocks. In that file you can see that, it invokes below method
<?php $_filters = $this->getFilters() ?>
to show the layered navigation content. This method is defined in Mage_Catalog_Block_Layer_View class and the file is in the location app/code/core/Mage/Catalog/Block/Layer/View.php. Let us analyze this method.
public function getFilters()
{
$filters = array();
if ($categoryFilter = $this->_getCategoryFilter()) {
$filters[] = $categoryFilter;
}
$filterableAttributes = $this->_getFilterableAttributes();
foreach ($filterableAttributes as $attribute) {
$filters[] = $this->getChild($attribute->getAttributeCode() . '_filter');
}
return $filters;
}
Here you can see that, when we call this method, it returns an array, i e $filters. Again you can see that, category-filter and attributes-filter are storing in $filters separately. So we are lucky. What we need to do is, include the attribute-filters to $filters array only when we are standing in level-4. You can easily achieve this by changing code in this format.
public function getFilters()
{
$filters = array();
if ($categoryFilter = $this->_getCategoryFilter()) {
$filters[] = $categoryFilter;
}
$current_layer = Mage::registry('current_category')->getData('level');
if($current_layer == 4) {
$filterableAttributes = $this->_getFilterableAttributes();
foreach ($filterableAttributes as $attribute) {
$filters[] = $this->getChild($attribute->getAttributeCode() . '_filter');
}
}
return $filters;
}
Thats it. you are done. But its not a good practice to change a core files. So in order to keep core files untouched, let us create a tiny module that overwrites this class. You just need only 3 files in your module.
config.xml
Location :app/code/local/Programmerrkt/Layerednav/etc/config.xml
<config>
<modules>
<Programmerrkt_Layerednav>
<version>0.1.0</version>
</Programmerrkt_Layerednav>
</modules>
<global>
<blocks>
<!-- rewrites Mage_Catalog_Block_Layer_View -->
<catalog>
<rewrite>
<layer_view>Programmerrkt_Layerednav_Block_Layer_View</layer_view>
</rewrite>
</catalog>
</blocks>
</global>
</config>
config.xml tells to magento that I am going to overwrite the core block Mage_Catalog_Block_Layer_View.
Programmerrkt_Layerednav.xml
Location :app/etc/modules/Programmerrkt_Layerednav.xml
<config>
<modules>
<Programmerrkt_Layerednav>
<active>true</active>
<codePool>local</codePool>
</Programmerrkt_Layerednav>
</modules>
</config>
This file activates our module.
View.php
Location : app/code/local/Programmerrkt/Layerednav/Block/Layer/View.php
<?php
class Programmerrkt_Layerednav_Block_Layer_View extends Mage_Catalog_Block_Layer_View {
/**
* Get all layer filters
*
* This method Overwrites getFilter() method of class Mage_Catalog_Block_Layer_View
*
* Adds attribute filter only when category leve is 4
*
* #return array
*/
public function getFilters()
{
$filters = array();
if ($categoryFilter = $this->_getCategoryFilter()) {
$filters[] = $categoryFilter;
}
$current_layer = Mage::registry('current_category')->getData('level');
if($current_layer == 4) {
$filterableAttributes = $this->_getFilterableAttributes();
foreach ($filterableAttributes as $attribute) {
$filters[] = $this->getChild($attribute->getAttributeCode() . '_filter');
}
}
return $filters;
}
}
This will overwrite the core class.
Now clear the cache and reload the pages. Check whether it worked or not. Remember that you need to remove all changes that you made to the file view.phtml
Thanks

Magento One-Page checkout mod

I'm writing a new shipping method for a customer; I've got the shipping calculations going great, and they appear in the 'shipping method' step - however, I want to:
a) Force the 'Shipping Information' tab to open after the user hits the billing.save() triggered by the continue button in the first (billing) tab, even if they select ship to billing address; and
b) Add options for 'receipted delivery', 'transport assurance' and 'tail-truck pickup' in the shipping information tab - which will be taken in to account when re-calculating the shipping quote.
In part b) I assume I override the shipping.phtml template with an xml config file in /layout, and then look for those added post fields in the collectRates() method.
Thanks in advance!
As for part a) you will need to overwrite the controller Mage_Checkout_OnepageController. To do so create your own module (I assume you know how to do this) and in the app/code/local/YourModule/etc/config.xml you should have this part:
<config>
...
<frontend>
<routers>
<checkout>
<args>
<modules>
<YourModule_Checkout before="Mage_Checkout">YourModule_Checkout</YourModule_Checkout>
</modules>
</args>
</checkout>
</routers>
</frontend>
</config>
then in app/code/local/YourModule/controllers/OnepageController.php you want to overwrite the behavior, so when you click the save billing button, you will always land on the shipping page.
include_once("Mage/Checkout/controllers/OnepageController.php");
class YourModule_Checkout_OnepageController extends Mage_Checkout_OnepageController
{
public function saveBillingAction()
{
if ($this->_expireAjax()) {
return;
}
if ($this->getRequest()->isPost()) {
$data = $this->getRequest()->getPost('billing', array());
$customerAddressId = $this->getRequest()->getPost('billing_address_id', false);
if (isset($data['email'])) {
$data['email'] = trim($data['email']);
}
$result = $this->getOnepage()->saveBilling($data, $customerAddressId);
if (!isset($result['error'])) {
/* check quote for virtual */
if ($this->getOnepage()->getQuote()->isVirtual()) {
$result['goto_section'] = 'payment';
$result['update_section'] = array(
'name' => 'payment-method',
'html' => $this->_getPaymentMethodsHtml()
);
} else { // Removed elseif block here which usually skips over shipping if you selected to use the same address as in billing
$result['goto_section'] = 'shipping';
}
}
$this->getResponse()->setBody(Mage::helper('core')->jsonEncode($result));
}
}
}
Then for part b) you have two options. Either as you pointed out you use the XML layout system to set a different template for the shipping.phtml:
<checkout_onepage_index>
<reference name="checkout.onepage.shipping">
<action method="setTemplate">
<new>my_shipping.phtml</new>
</action>
</reference>
</checkout_onepage_index>
or even easier, you overwritte the shipping.phtml template using your custom design folder.
To evaluate your custom data, the model Mage_Checkout_Model_Type_Onepage processes the data in the saveShipping() method, so I guess this would be a good point to look for implementing your custom logic.

Categories for layered navigation in 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.

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