Which controller in Magento do I need to override if I want to redirect a certain product view page to another url?
I'd like to use the following code for redirection. Is there any more Magento-like way of doing it?
if($this->getProductId() == 10) {
header("Location: /mymodule");
die();
}
Magento Admin has a feature for this under Catalog > URL Rewrite Management. Create a new product rewrite with these steps:
Click the Add URL Rewrite button at top right.
Select “Custom” from Create URL Rewrite.
Choose the appropriate Store.
Set Request Path to something like this catalog/product/view/id/10 (assuming 10 is the ID of your product).
Set Target Path to whatever route or URL you want to send the request to.
Set Redirect to probably “Temporary (302)”.
Found a solution. Might not be the best one but it works:
Observer.php:
class Namespace_Mymodule_Model_Observer {
public function redirect(){
//request object
$request = Mage::app()->getRequest();
//only redirect in the frontend/catalog
$storeId = Mage::app()->getStore()->getId();
if(in_array($request->getModuleName(), array("catalog")) && $storeId != 0) {
$response = Mage::app()->getResponse();
$params = Mage::app()->getRequest()->getParams();
//check the product id
if($params[id] == 10) {
return $response->setRedirect("/mymodule", 301)->sendHeaders();
}
}
}
}
And the config.xml in the global/events section:
<controller_action_predispatch>
<observers>
<namespace_mymodule_observer>
<type>singleton</type>
<class>namespace_mymodule/observer</class>
<method>redirect</method>
</namespace_mymodule_observer>
</observers>
</controller_action_predispatch>
I believe a better approach is to actually utilize the observer event since all you need is included here already. Also, the answer does not differentiate between products and categories since in_array($request->getModuleName(), array("catalog")) would be true for both.
class Namespace_Mymodule_Model_Observer {
public function redirect(Varien_Event_Observer $observer) {
$actionName = $observer->getEvent()->getControllerAction()->getFullActionName();
$productId = $observer->getEvent()->getControllerAction()->getRequest()->getParam('id');
if($actionName == 'catalog_product_view' && $productId == 10) {
$response = $observer->getEvent()->getControllerAction()->getResponse();
$response->setRedirect('/mymodule', 301)->sendHeaders();
}
}
}
Related
I like to add checkboxes for every product in the cart, so the client can decide wich product (balloons) he want to befill with helium. I'm unable to save the infomation to quote respectively to the sales_flat_order.. tables.
I followed this tutorial: http://www.atwix.com/magento/custom-product-attribute-quote-order-item/
By clicking on "Refrech Cart" the function _updateShoppingCart() from my CartController is called.
protected function _updateShoppingCart()
{
$cartData = $this->getRequest()->getParam('cart');
if (is_array($cartData)) {
$cart = $this->_getCart();
$quote = $cart->getQuote();
foreach ($cartData as $index => $data) {
if (isset($data['qty'])) {
$cartData[$index]['qty'] = $data['qty'];
}
if (isset($data['ballo_add_gas']) && $data['ballo_add_gas'] == 1) {
$cartData[$index]['ballo_add_gas'] = $data['ballo_add_gas'];
}
}
$cartData = $cart->suggestItemsQty($cartData);
MAGE::log($cartData);
$cart->updateItems($cartData)
->save();
}
$this->_getSession()->setCartWasUpdated(true);
}
This function is called, properly. The Informations in $cartData are according to the log file are:
[70] => Array
(
[qty] => 5
[ballo_add_gas] => 1
[before_suggest_qty] => 5
)
So that's ok. If I set a fix value for qty in this function , everything works as espected-> the cart is updated with the fix quantity. So my direction should be ok.
Unfortunately the ballo_add_gas value isn't saved to quote eg. database.
I've tried to save the value in app\code\local\Mage\Checkout\Model\Cart.php in the function updateItems($data).
$item->setData('ballo_add_gas', $itemInfo['ballo_add_gas']);
But nothing happens.
Next, in Gas\Model\Observer.php I've created an function.
public function salesQuoteItemSetCustomAttribute($observer)
{
$quoteItem = $observer->getQuoteItem();
$product = $observer->getProduct();
$quoteItem->setBallo_add_gas($product->getBallo_add_gas());
//$quoteItem->setBallo_add_gas(1); THIS WORKS
}
This function should copy the informations. See config.xml
<sales_quote_item_set_product>
<observers>
<XXX_Gas_Model_Observer>
<class>Mexan_Gas_Model_Observer</class>
<method>salesQuoteItemSetCustomAttribute</method>
</XXX_Gas_Model_Observer>
</observers>
</sales_quote_item_set_product>
</events>
And again config.xml
<fieldsets>
<sales_convert_quote_item>
<ballo_add_gas>
<to_order_item>*</to_order_item>
</ballo_add_gas>
</sales_convert_quote_item>
<sales_convert_order_item>
<ballo_add_gas>
<to_quote_item>*</to_quote_item>
</ballo_add_gas>
</sales_convert_order_item>
</fieldsets>
When I change $product->getBallo_add_gas() to a fixed value 1 everything works fine. So I assume when I'm able to save the value in _updateShoppingCart() properly. Than everything should be ok.
By the way. I've created the column ballo_add_gas in the database tables sales_flat_order_item and sales_flat_quote_item.
--
Another approach I followed was saving the Information directly into the DB.
private function saveGas($item_id, $gas)
{
$cartItem = Mage::getSingleton('checkout/cart')->getQuote()->getItemById($item_id);
$cartItem->setBalloAddGas($gas);
$cartItem->save();
$sales_flat_quote_item_table = Mage::getSingleton('core/resource')->getTableName('sales_flat_quote_item');
$db = Mage::getSingleton('core/resource')->getConnection('core_write');
$qry = "UPDATE " . $sales_flat_quote_item_table . " SET ballo_add_gas=" . $gas . " WHERE item_id=".$item_id;
MAGE::log($qry);
$db->query($qry);
}
The information was saved to the DB, but disappeared after reloading the cart, and well there should be an easier way?
Any ideas?
Thanks!
We have been using a third party to pack and ship our packages. Therefore we don't see all orders that pass by anymore.
But there are several products that we have to supply manually ourselves, such as a digital gift card. Is there a possibility to have Magento send us an email when a specific SKU has been ordered by a customer? For instance to inform us that we need to create a gift card for a customer?
I don't want to see every order in our emailbox, just with some specific SKU's in it.
Thanks,
Menno
Yes this can be achieved with a custom module. Create your module and add an event observer to it's config.xml;
<events>
<checkout_onepage_controller_success_action>
<observers>
<copymein>
<type>singleton</type>
<class>dispatcher/observer</class>
<method>ccMyEmail</method>
</copymein>
</observers>
</checkout_onepage_controller_success_action>
</events>
Then in Model/Observer.php declare your function;
public function ccMyEmai($observer) {
$order_ids = $observer->getData('order_ids');
if(isset($order_ids)) {
foreach ($order_ids as $order_id) :
$sendToMe = false;
$order = Mage::getModel('sales/order')->load($order_id);
if (isset($order)) {
$orderItems = $order->getAllItems();
foreach ($orderItems as $_item) {
$product = Mage::getModel('catalog/product')->load($item->getData('product_id'));
if($product->getSku() == ('123' || '234' || '345')) { // Your SKUs
$sendToMe = true;
}
}
}
if($sendToMe) {
$mail = Mage::getModel('core/email');
$mail->setToName('Your name');
$mail->setToEmail('your#email.com');
$mail->setBody('Order number '.$order->getIncrementId().' has items that need action');
$mail->setSubject('Order '.$order->getIncrementId().' needs attention');
$mail->setFromName('Your from name');
$mail->setFromEmail('your#siteemail.com');
$mail->setType('text');
try {
$mail->send();
} catch (Exception $e) {
Mage::log($e);
}
}
endforeach;
}
}
Just a note that it would be more efficient to create a product attribute that isnt visible on the frontend that defines whether a product requires your attention - something along the lines of needs_attention Yes/No, then scan the ordered products for a yes value in that attribute. Much more manageable than hard coding the SKU's you are looking for ;)
You might create a custom module for this functionality. So in the new module, you have to hook Observer event: checkout_onepage_controller_success_action.
You can do like following as :
<checkout_onepage_controller_success_action>
<observers>
<xxx_checkout_success>
<type>singleton</type>
<class>[Your Module Name]/observer</class>
<method>sendEmailToCustomerForSales</method>
</xxx_checkout_success>
</observers>
</checkout_onepage_controller_success_action>
And, in this sendEmailToCustomerForSales() method, it can send an email to the customer according to a specific SKU.
Please refer this code:
public function sendEmailToCustomerForSales($observer) {
$orderId = (int)current($observer->getEvent()->getOrderIds());
$order = Mage::getModel('sales/order')->load($orderId);
$itemCollection = $order->getItemsCollection();
foreach($itemCollection as $item) {
$_product = Mage::getModel('catalog/product')->load($item->getProductId());
if($_product->getSku() == '[Your specific sku]') {
/*send an email to the customer*/
}
}
}
I have a Magento install with a default website and multiple 'franchise' websites.
My question is, how can I capture the event when a customer returns to the website after being away and is auto-logged in via Magento's persistent login mechanism? I would like to capture that event, load the customer, check if they are in the correct website id, then redirect them if they are not.
In order to make this work, you must register an event in your /app/code/local/Extension/Module/etc/config.xml like this:
<customer_session_init>
<observers>
<sessioninit_handler>
<type>singleton</type>
<class>Extension_Module_Model_Observer</class>
<method>on_customer_session_init</method>
</sessioninit_handler>
</observers>
</customer_session_init>
Then create an Observer method in /app/code/local/Extension/Module/Model/Observer.php like so:
/*
** on customer session init, checks for current website id and redirects if no-match
*/
public function on_customer_session_init(Varien_Event_Observer $observer){
$customer = $observer->customer_session->getCustomer();
$customer_website_id = $customer->getWebsiteId();
$current_website_id = Mage::app()->getWebsite()->getId();
if ($customer_website_id != $current_website_id){
$website = Mage::app()->getWebsite($customer_website_id);
$request = $this->_getRequest();
$response = $this->_getResponse();
$url = $website->getDefaultStore()->getBaseUrl().substr($request->getRequestString(), 1);
$response->setRedirect($url);
}
return $this;
}
I am trying to redirect specific users in Magento to the products.html page after logging in. Most every way I attempt to do this (setRedirect, header) results in a loop due to too many redirects.
Currently, I am trying to use an observer to setParam('return_url', "$customerRedirectUrl") as described in this rather popular post - Magento - Redirect Customer from Observer Method. The variable $customerRedirectUrl represents logic that together reliably creates the url I know I want the page to be. My relevant code looks like this.
public function redirect(Varien_Event_Observer $observer)
{
$helper = Mage::helper('personal_order');
$isPersonalOrderStore = $helper->isPersonalOrderStore(null);
$session = Mage::getSingleton('customer/session');
if ($isPersonalorderStore){
if(!$session->isLoggedIn()) {
$targetUrl = Mage::getBaseUrl(Mage_Core_Model_Store::URL_TYPE_WEB).'customer/account/login';
Mage::app()->getResponse()->setRedirect($targetUrl);
} else {
$baseUrl = Mage::getBaseUrl(Mage_Core_Model_Store::URL_TYPE_WEB);
$storeName = strtolower(Mage::app()->getStore()->getName());
$storeName = str_replace(' ', '', $storeName);
$customerRedirectUrl = "$baseUrl$storeName/products.html";
$observer->getRequest()->setParam('return_url',"$customerRedirectUrl");
}
}
The important part for my purposes now is the else statement, the rest of the function works fine. However, the call to setParam results in the following error:
Fatal error: Call to a member function setParam() on a non-object...
What about the Magento - Redirect Customer from Observer Method post am I not getting (there is a good chance I'm just oblivious to something due to being a fairly new user)? The observer is laid out in the relative config file under controller_action_postdispatch and is in an observer model. What is the context for getting setParam to operate correctly?
Thanks to any and all for your help!
I know this post is a bit old but I see have it worked out for a module of my own.
I run the redirect on 2 different events. When the customer registers or when a customer logs in.
<customer_register_success>
<observers>
<redirectAfterRegister>
<class>businessdirectory/profile_observer</class>
<method>redirectAfterRegister</method>
</redirectAfterRegister>
</observers>
</customer_register_success>
<customer_login>
<observers>
<redirectAfterLogin>
<class>businessdirectory/profile_observer</class>
<method>redirectAfterLogin</method>
</redirectAfterLogin>
</observers>
</customer_login>
I edited this answer because after testing I realized that two separate observers are needed for the two events. The good news is that you do not need to override files or rewrite controllers.
For the customer_register_success event, all you need to do is set the success_url param to whatever you want the url to be.
For the customer_login event, you will notice in your controller customer/account/_loginPostRedirect that the redirect URLs are being set on the customer session. As you can see in the second observer method below, all you need to do is grab the customer session and set the URL. For my purposes, I set the BeforeAuthUrl and AfterAuthUrl.
public function redirectAfterRegister($observer)
{
if(Mage::app()->getRequest()->getParam('listing_id') || Mage::app()->getRequest()->getParam('directory_id')){
$_session = Mage::getSingleton('customer/session');
$action = $_session->getDirectoryAction();
if(Mage::app()->getRequest()->getParam('listing_id')){
$listingId = Mage::app()->getRequest()->getParam('listing_id');
Mage::app()->getRequest()->setParam('success_url',Mage::getUrl($action,array('listing_id'=>$listingId)));
}elseif(Mage::app()->getRequest()->getParam('directory_id')){
$directoryId = Mage::app()->getRequest()->getParam('directory_id');
Mage::app()->getRequest()->setParam('success_url',Mage::getUrl($action,array('directory_id'=>$directoryId)));
}
}
}
public function redirectAfterLogin($observer)
{
if(Mage::app()->getRequest()->getParam('listing_id') || Mage::app()->getRequest()->getParam('directory_id')){
$_session = Mage::getSingleton('customer/session');
$action = $_session->getDirectoryAction();
if(Mage::app()->getRequest()->getParam('listing_id')){
$listingId = Mage::app()->getRequest()->getParam('listing_id');
$url = Mage::getUrl($action,array('listing_id'=>$listingId));
$_session->setBeforeAuthUrl($url);
$_session->setAfterAuthUrl($url);
}elseif(Mage::app()->getRequest()->getParam('directory_id')){
$directoryId = Mage::app()->getRequest()->getParam('directory_id');
$url = Mage::getUrl($action,array('directory_id'=>$directoryId));
$_session->setBeforeAuthUrl($url);
$_session->setAfterAuthUrl($url);
}
}
}
When you have a problem instantiating an object with $observer->getRequest(), try using $observer->getEvent()->getFront()->getResponse() instead. I believe this differs depending on what event the observer is listening to.
I have a magento(enterprise) site with 2 language stores. Each having their own dedicated url to a given item or resource be it a static page or a product page.
I am using the URL rules via the CMS to manage my SEF URLs for all resources.
The problem is the following scenario:
Site defaults to LANG #1.
When user switches from LANG#1 to LANG#2, switch happens with no issues - content switches to specific lang (_store=lang">http://www.sitename.com/?_store=lang)
But regardless of what lang store I am in, if I have enter a url from the other lang store into my current language store, I get a 404 error.
What I want the system checking the current store for the resource requested. If not found it should route to the next store and check for the resource in there. If found, store should switch to the lang store the item was found and url redirected.
What class should I extend in order to achieve this ( i am quite new to magento).
I went as far as inspecting if I can extend this class to do what I want: /app/code/core/Mage/Core/Model/Mysql4/Url/Rewrite.php
But not sure if I am in the right location for such requirements.
Any help will be appreciated!
Thanks
I was able to sort this issue out. All I did was extend the /app/code/core/Mage/Core/Model/Mysql4/Url/Rewrite.php file.
So I overode the loadByRequestPath function to serve the request in the current store, if not found, get a list of all the other available stores, loop through and find if the item exists. If found redirect to the store in which the URL key exists for the product and whola.
If none of the stores have it THEN return the 404 error.
And for static pages, the URL rewrite manager will be able to sort out the issue for you when you switch stores/languages.
I hope this helps someone!
I don't think mine is the most elegant of the solutions but I will post it anyway as it worked for me.
Basically I am searching in all stores the path that I am looking for in stead of only the specified store. Any suggestion would be more than welcome.
My config.xml
<?xml version="1.0"?>
<config>
<global>
<modules>
<Soipo_UrlRewrite>
<version>0.1</version>
</Soipo_UrlRewrite>
</modules>
<models>
<soipo_urlrewrite>
<class>Soipo_UrlRewrite_Model</class>
</soipo_urlrewrite>
<core_mysql4>
<rewrite>
<url_rewrite>Soipo_UrlRewrite_Model_Mage_Core_Model_Mysql4_Url_Rewrite</url_rewrite>
</rewrite>
</core_mysql4>
</models>
</global>
</config>
Rewrite.php
<?php
class Soipo_UrlRewrite_Model_Mage_Core_Model_Mysql4_Url_Rewrite extends Mage_Core_Model_Mysql4_Url_Rewrite{
/**
* This function get an array of store ids, containing the Admin store.
* #return array
*/
public function getStoreIds(){
$allStores = Mage::app()->getStores();
$storeIds = array();
$storeIds[] = Mage_Core_Model_App::ADMIN_STORE_ID;
foreach ($allStores as $_eachStoreId => $val)
{
$_storeId = Mage::app()->getStore($_eachStoreId)->getId();
$storeIds[] = $_storeId;
}
return $storeIds;
}
/**
* Load rewrite information for request
* If $path is array - we must load all possible records and choose one matching earlier record in array
*
* #param Mage_Core_Model_Url_Rewrite $object
* #param array|string $path
* #return Mage_Core_Model_Resource_Url_Rewrite
*/
public function loadByRequestPath(Mage_Core_Model_Url_Rewrite $object, $path)
{
if (!is_array($path)) {
$path = array($path);
}
$pathBind = array();
foreach ($path as $key => $url) {
$pathBind['path' . $key] = $url;
}
$storeIds = $this->getStoreIds();
// Form select
$adapter = $this->_getReadAdapter();
$select = $adapter->select()
->from($this->getMainTable())
->where('request_path IN (:' . implode(', :', array_flip($pathBind)) . ')')
->where('store_id IN(?)', $storeIds);
$items = $adapter->fetchAll($select, $pathBind);
// Go through all found records and choose one with lowest penalty - earlier path in array, concrete store
$mapPenalty = array_flip(array_values($path)); // we got mapping array(path => index), lower index - better
$currentPenalty = null;
$foundItem = null;
foreach ($items as $item) {
if (!array_key_exists($item['request_path'], $mapPenalty)) {
continue;
}
$penalty = $mapPenalty[$item['request_path']] << 1 + ($item['store_id'] ? 0 : 1);
if (!$foundItem || $currentPenalty > $penalty) {
$foundItem = $item;
$currentPenalty = $penalty;
if (!$currentPenalty) {
break; // Found best matching item with zero penalty, no reason to continue
}
}
}
// Set data and finish loading
if ($foundItem) {
$object->setData($foundItem);
}
// Finish
$this->unserializeFields($object);
$this->_afterLoad($object);
return $this;
}
}