I would like to add a static link at the navigation bar that can link directly to a specific product.
As I only have one product listing under category "pillow", I wish to set it to go into the product directly, skipping the catalog view.
I am aware of two methods, being URL rewrite management and static block, however I experience problem with both.
For "URL rewrite", it worked but once I update something at the category (e.g. moving the position), the system generate a new "URL rewrite" and delete the my custom one.
For "static block", I do not know what code to put in it. My guess was to add below code, but it doesn't work.
{{block type="catalog/product_view" product_id="896" template="catalog/category/view.phtml"}}
How do I get it done? Thanks in advance.
I have taken a different approach to the problem which may be helpful. It seems like your end goal is to skip the category view if a category only contains one product. So rather than fussing with hard coding templates or trying to clobber the category with URL rewrite, you can accomplish this using an event observer.
The approach will listen for the <catalog_controller_category_init_after> event to fire and check whether the category only has one product. If so it will send the request directly to the product. You will need to add a new extension or modify an existing one.
etc/config.xml
Create a new node under config/frontend/events:
<catalog_controller_category_init_after>
<observers>
<redirectSingleProduct>
<class>My_MyExtension_Model_Observer</class>
<method>redirectSingleProduct</method>
</redirectSingleProduct>
</observers>
</catalog_controller_category_init_after>
Model/Observer.php
Create the corresponding method to handle the event:
class My_MyExtension_Model_Observer
{
/**
* Check whether a category view only contains one product, if so send the request directly to it.
* #param Varien_Event_Observer $observer
* #return $this
*/
public function redirectSingleProduct(Varien_Event_Observer $observer)
{
$category = $observer->getCategory();
if ($category->getProductCount() == 1) {
$product = $category->getProductCollection()->addUrlRewrite()->getFirstItem();
$url = $product->getProductUrl();
$observer->getControllerAction()->getResponse()->setRedirect($url);
}
return $this;
}
}
Related
I'm reposting this from magento.stackexchange because of practically no views/answers there.
We have an observer that modifies final price, that's triggered on the event catalog_product_get_final_price. Problem is, when you retrieve products via collection with addAttributeToSelect("*"), they come back with a final_price already set, and the product getFinalPrice function merely returns what's in the database instead of recalculating (and running the observers for) the final price.
Mage_Catalog_Model_Product
public function getFinalPrice($qty=null)
{
// *** Collection items already have a 'final_price' from flat tables
// but it's wrong because observers haven't run yet ***
$price = $this->_getData('final_price');
if ($price !== null) {
return $price;
}
return $this->getPriceModel()->getFinalPrice($qty, $this);
}
I've also noticed that all of our custom attributes are also not being interpreted (we save things as JSON but decode into objects them on product load before using them).
This behavior doesn't happen when you load the product directly -- all the observers and models are interpreted when the product is loaded.
Is there a way to ensure the data we're retrieving from a collection matches in format and value the data we would retrieve if we load the product directly?
I know I can just load the product individually to trigger all of the events that go along with it, but in the case of 3rd party software, that might not always be the case and the final price is wrong.
We're on version 1.7 if it helps.
Set up an event
<catalog_product_collection_load_after>
<observers>
<modulename>
<type>singleton</type>
<class>Seamus_Module_Model_Observer</class>
<method>changePrice</method>
</modulename>
</observers>
</catalog_product_collection_load_after>
On your observer do something like...
public function changePrice($observer)
{
$event = $observer->getEvent();
$products = $observer->getCollection();
foreach( $products as $product )
{
$product->setFinalPrice( $this->getPriceLogic($product) );
}
return $this;
}
We have several magento websites and some of them we would like to turn on the website restriction so only logged in customers can view it. This seems to work great except we have custom pages that we want the user to be able to access without having to login. And currently if we turn on access restriction it redirects all pages, except the login page and the password reset page, to the login page.
Does anyone know how to exclude other pages from being redirected to the login page? I think it would be a layout xml setting but I can't seem to figure it out or find anything on it.
Magento Enterprise version 1.12.02
Wow, this question is pretty valid, rather old, ranked high on on Google results, yet without a good answer. So here goes one.
The right way to exclude pages from restriction is by adding them to generic list of pages under Enterprise_WebsiteRestriction module config.
See app/code/core/Enterprise/WebsiteRestriction/etx/config.xml and config/frontend/enterprise/websiterestriction section in particular. Pages under full_action_names/generic are always accessible no matter what restriction level is set. Those in full_action_names/register are still accessible when restriction mode is set to "Login and Register" - i.e. they are intended for new registration to be possible.
The values under those sections are full actions names (i.e. <module>_<controller>_<action>), so e.g. to enable contact form for everyone, you need to add contacts_index_index to the generic list.
Note that editing files in core codepool is strongly discouranged, so to achieve this it's best to create your own module and add the configuration section.
It should look somewhat like this (remember to enable this module in app/etc/modules):
<?xml version="1.0"?>
<config>
<modules>
<Emki_WebsiteUnrestrict>
<version>0.1.0</version>
</Emki_WebsiteUnrestrict>
</modules>
<frontend>
<enterprise>
<websiterestriction>
<full_action_names>
<generic>
<contacts_index_index />
</generic>
</full_action_names>
</websiterestriction>
</enterprise>
</frontend>
</config>
Nick,There are several process for this function...
Step1:you can it from Controllers from using dispatch event.
/**
* Retrieve customer session model object
*
* #return Mage_Customer_Model_Session
*/
protected function _getSession()
{
return Mage::getSingleton('customer/session');
}
public function preDispatch()
{
// a brute-force protection here would be nice
parent::preDispatch();
if (!$this->getRequest()->isDispatched()) {
return;
}
$action = $this->getRequest()->getActionName();
/* put all action of this controllers for check ,if any actions of list is exit then redirect to login page*/
$openActions = array(
'index',
'post',
'autoy',
'confirmation'
);
$pattern = '/^(' . implode('|', $openActions) . ')/i';
if (!preg_match($pattern, $action)) {
if (!$this->_getSession()->authenticate($this)) {
$this->setFlag('', 'no-dispatch', true);
}
} else {
$this->_getSession()->setNoReferer(true);
}
}
/**
* Action postdispatch
*
* Remove No-referer flag from customer session after each action
*/
public function postDispatch()
{
parent::postDispatch();
$this->_getSession()->unsNoReferer(false);
}
Other thing is Using observer
I want to update the products description attribute after the product save.so for this i am using the observer called catalog_product_save_after and depending on some condition i create the description for the product and i will save the description of the products by following code
product->setDescription();
product->save();
the problem is when i am calling the product->save(); the site is loading and loading later i found that product->save(); this function is again calling the catalog_product_save_after. that's why it is going into the infinite loop.
Please help me to set the description for the product.
Option 1:
You can use catalog_product_save_before and just use $product->setDescription('something') (without the save).
Option 2
Make your observer run only once.
function doSomething($observer) {
//some code here
$id = $product->getId();
if (!Mage::registry('observer_already_executed_'.$id)) {
//do your magic here
Mage::register('observer_already_executed_'.$id, 1);
}
}
I've made controller_front_init_routers event observer, which retrieves data from a REST service to construct a menu.
All was ok until I discovered that the observer generates errors in the backend (no way to save products for example) and also in the rest services.
I am struggling for any conclusions, So I raised some interrogations.
I tried to make a condition in order to trigger my Observer
methods in case we are in frontend only. But Magento considers that we are
always in frontend area.
(var_dump(Mage::app()->getStore()->isAdmin()) return always false
and the same with var_dump(Mage::getDesign()->getArea() ==
'adminhtml'))
Can anyone explain what's happened ?
Also one solution is to place the event observer in frontend
area in the config.xml and to load it with
Mage::app()->loadArea($this->getLayout()->getArea()); but where should I
place this piece of code ? in a new observer ? Is that the most
appropriate process ?
Is it a way to listen once an event then to pause the listener?
(once my menu is registered, I don't need to listen to the event any more)
Is the use of controller_front_init_routers event the best choice ?
Who has ever seen that kind of problem ?
I work on Magento ver. 1.12.0.2
Here the config.xml
<globals>
....
<events>
<controller_front_init_routers>
<observers>
<connector_services_observer>
<type>singleton</type>
<class>Connector_Services_Model_Observer</class>
<method>getEvent</method>
</connector_services_observer>
</observers>
</controller_front_init_routers>
</events>
</globals>
Here the function getEvent in my model observer
public function getEvent($observer){
//model which do post or get requests and return xml and menu
$_getRest = Mage::getModel('connector_services/RestRequest');
//the paths
$_menu_url = Mage::getStoreConfig('connector_service_section/connector_service_url/service_menu_url');
//put a store config
$path_nlist = 'veritas-pages-list.xml';
$_isAdmin = Mage::helper('connector_services');
$currentUrl=Mage::helper("core/url")->getCurrentUrl();
//the way I found to trigger methods only in frontend
//that's not very beautiful I know
$admin = preg_match("#/admin/#",$currentUrl);
$api = preg_match("#/api/#",$currentUrl);
//
if ( !$admin && ! $api ){
$_menuXml = $_getRest->postRequest($_menu_url);
if( $_menuXml )
{
$_menu = $_getRest->makeMenu($_menuXml);
Mage::register('menu',$_menu);
}
}
You should be able to pass a querystring to the rest service, similar to how you'd just type it out in the address bar. Magento will forward it on to the observer, and you can use it as a flag.
Add something like the following to your code:
const USE_FRONTEND = 'usefront';
public function getEvent($observer){
this->request = $observer->getEvent()->getData('front')->getRequest();
// If the constant is in the query string
if ($this->request->{self::USE_FRONTEND}) {
// Do code related to this request
die('Frontend flag detected');
}
}
Call to your site like this and pass the querystring
http://www.yourmagentosite.com/?usefront=true
I am not extremely familiar with Magento's new REST api, but I know it works in the browser. Maybe this explanation can help you out.
I have an extremely simple module that allows a customer to "Purchase On Account". The module doesn't do anything special really (it was simply modified from a Cash On Delivery module.)
The problem is I only want to offer this payment method to logged in customers.
So far my module looks like this:
BuyOnAccount/
etc/
config.xml
system.xml
Model/
PaymentMethod.php
The content of PaymentMethod.php is:
class MyCompany_BuyOnAccount_Model_PaymentMethod extends Mage_Payment_Model_Method_Abstract
{
protected $_code = 'buyonaccount';
protected $_isInitializeNeeded = true;
protected $_canUseInternal = false;
protected $_canUseForMultishipping = false;
}
The config and system xml files contain the usual sort of thing (please let me know if you would like to see the code and i'll edit)
So bascically I need to disable the module if the user is not logged in (but obviously only for the current customer session!)
Any ideas?
Thanks
You can just add a method to your payment model called isAvailable(Mage_Sales_Model_Quote $quote) that returns a bool. For example, in your situation you could add something like:
public function isAvailable($quote = null) {
$isLoggedIn = Mage::helper('customer')->isLoggedIn();
return parent::isAvailable($quote) && $isLoggedIn;
}
The Mage_Payment_Model_Method_Free payment method that ships with Magento is an example of a payment method that employs this -- it'll only show if the basket total is zero.