Magento - How I can Run Store by Country by GeoIP? - magento

I want run store by IP of the customer.
In the backend of Magento, the user may configure the concret Store to load per country.
Taking a glance, I see the method at class Mage_Core_Model_App
public function run($params)
{
$options = isset($params['options']) ? $params['options'] : array();
$this->baseInit($options);
if ($this->_cache->processRequest()) {
$this->getResponse()->sendResponse();
} else {
$this->_initModules();
$this->loadAreaPart(Mage_Core_Model_App_Area::AREA_GLOBAL, Mage_Core_Model_App_Area::PART_EVENTS);
if ($this->_config->isLocalConfigLoaded()) {
//$scopeCode = isset($params['scope_code']) ? $params['scope_code'] : '';
//===============custom scope by country======================
$scopeCode = Mage::helper('custom/module')->getStoreByGeoip();
//===============custom scope by country======================
$scopeType = isset($params['scope_type']) ? $params['scope_type'] : 'store';
$this->_initCurrentStore($scopeCode, $scopeType);
$this->_initRequest();
Mage_Core_Model_Resource_Setup::applyAllDataUpdates();
}
$this->getFrontController()->dispatch();
}
return $this;
}
In my progress to get a good solution, I thought another alternative.
In the index.php write the next code:
Mage::app();
Mage::Helper('custom/helper')->getRunCodeByGeoio();
Mage::run($mageRunCode, $mageRunType);
I thinks this haven´t dangerous of performance because this method only create object if you not have before
/**
* Get initialized application object.
*
* #param string $code
* #param string $type
* #param string|array $options
* #return Mage_Core_Model_App
*/
public static function app($code = '', $type = 'store', $options = array())
{
if (null === self::$_app) {
self::$_app = new Mage_Core_Model_App();
self::setRoot();
self::$_events = new Varien_Event_Collection();
self::$_config = new Mage_Core_Model_Config();
Varien_Profiler::start('self::app::init');
self::$_app->init($code, $type, $options);
Varien_Profiler::stop('self::app::init');
self::$_app->loadAreaPart(Mage_Core_Model_App_Area::AREA_GLOBAL, Mage_Core_Model_App_Area::PART_EVENTS);
}
return self::$_app;
}
And my question is......
Are this the best approach for get the solution??
I think is very dangerous modify Mage_Core_Model_App even using rewrite
I don´t have any event at tier
Another option is made the business in the index.php but lost the management by the backend
Searching...., found a extension that cover many of my requirements,
http://www.mageworx.com/store-and-currency-auto-switcher-magento-extension.html
then I'll buy this or made a similar extension.

You shyould never touch any core files when developing with Magento, or any other application if you can avoid it.
Doing this will mean possible future upgrades will overwrite your changes and break your store.
The simplest way would be to do everything index.php as this is the entry point where the store is selected anyway, all you are doing is selecting the store on different criteria (ie IP address).
One simple way would be to use a free library, such as maxmind GeoLite: http://dev.maxmind.com/geoip/geolite
You can either load an apache module, or via a pecl extensions, or even plain PHP.
This will return you the iso country code for the country of your visitor.
You could then name your stores with a country iso code for the store code, and this will make it really simple to load the correct store depending on IP
something simple like this:
$countryCode = getUsersCountryCode(); // which ever method you use in here...
$stores = array(
'gb',
'us',
'fr',
);
if(in_array(countryCode, $stores)) {
Mage::run(countryCode, 'store');
}
else {
Mage::run($mageRunCode, $mageRunType);
}
You could of course make it into a Magento extensions, but this is by far the simplest way. You could even get a list of the countries/stores from Magento rather than hard coding them if you required.

Related

Error when adding SOAP/XML-RPC users and roles

I tried to upgrade Magento 1.9.0.1 to 1.9.1 via the Magento Connect facility and it seems to have stopped me being able to add users and roles for API access.
Here's the error:
Invalid method Mage_Admin_Model_User::validateCurrentPassword(Array
Has anyone ever come across this?
this issues can be solve
1) open the file app/code/core/Mage/Adminhtml/Controller/Action.php
2) After that see the function on line number 395 and comment the internel code into this.
protected function _validateCurrentPassword($password){
/*$user = Mage::getSingleton('admin/session')->getUser();
return $user->validateCurrentPassword($password);*/
}
I recently came across this same issue after upgrading Magento to a newer version of 1.9.
It should be noted that you should never modify core files, and the password validation should not necessarily be removed.
In my personal case, I restored the original function to the core file, however, you could just as easily extend the Mage_Admin_Model_User class.
The version of the function I used can be found below.
/**
* Validate password against current user password
* Returns true or array of errors.
*
* #return mixed
*/
public function validateCurrentPassword($password)
{
$result = array();
if (!Zend_Validate::is($password, 'NotEmpty')) {
$result[] = $this->_getHelper('adminhtml')->__('Current password field cannot be empty.');
} elseif (is_null($this->getId()) || !$this->_getHelper('core')->validateHash($password, $this->getPassword())){
$result[] = $this->_getHelper('adminhtml')->__('Invalid current password.');
}
if (empty($result)) {
$result = true;
}
return $result;
}

Availability of $this->var in Phalcon\Mvc\View\Simple

I'm responsible for a rather large web app I built 8 years ago, then later refactored using ZF1 and now trying to move beyond that into more modern framework components. At the moment am trying to see if I can swap out Zend_View for Phalcon\Mvc\View\Simple without having to touch every .phtml file.
Problem I've run into is that while both assign a variable to the view in the same way (e.g. $this->view->foo = 'bar'), in Zend_View in the template you would <?=$this->foo;?> to print the var but in Phalcon it is <?=$foo;?>.
As I mentioned I don't want to go through each of several hundred .phtml files to remove $this->. Is there a way I can override Phalcon's render() or otherwise enable access to the view params using $this?
Here's what I came up with after fiddling with it all day. Simply extend the PHP view engine:
class Engine extends \Phalcon\Mvc\View\Engine\Php
{
/**
* Renders a view using the template engine
*
* #param string $path
* #param array $params
* #param boolean $mustClean
* #return string
*/
public function render($path, $params = null, $mustClean = null)
{
/**
* extract view params into current object scope
* so we can access them with <?=$this->foo;?>
* Maintains backward compat with all the .phtml templates written for Zend_View
*/
foreach($this->_view->getParamsToView() as $key => $val) {
$this->$key = $val;
}
return parent::render($path, $params, $mustClean);
}
You can use DI container to access any registered services in the view, so just put your variables into DI (in the action for example):
public function indexAction()
{
$this->getDi()->set('hello', function() { return 'world'; });
...
And then use it in the template via $this variable:
<div>
<?php echo $this->hello; ?>
</div>
P.S. This is not a good way to assign variables to the view, but should help in your particular case.

Magento translations ok in online program but not run as cronjob

I created a module (extends Mage_Core_Model_Abstract) and an admin controller.
When I run this module online translations are going right.
When I run this module as cronjob, everything goes allright but translations are not done, I specified translation file in config.xml in as well frontend as adminhtml.
What I am doing wrong?
I see this is a very old question. I've posted here to future reference and others.
Quick and dirty solution
// Fix unitialized translator
Mage::app()->getTranslator()->init('frontend', true);
just after
$initialEnvironmentInfo = $appEmulation>startEnvironmentEmulation($storeId);
for instance. Or in a foreach loop of your own, which is called via cron/admin. Since you're talking about crons, I assume that you know what you are doing.
The real problem
In Magento 1.9 in Mage_Core_Model_App_Emulation (in app/code/core/Mage/Core/Model/App/Emulation.php), there's this function:
/**
* Apply locale of the specified store
*
* #param integer $storeId
* #param string $area
*
* #return string initial locale code
*/
protected function _emulateLocale($storeId, $area = Mage_Core_Model_App_Area::AREA_FRONTEND)
{
$initialLocaleCode = $this->_app->getLocale()->getLocaleCode();
$newLocaleCode = $this->_getStoreConfig(Mage_Core_Model_Locale::XML_PATH_DEFAULT_LOCALE, $storeId);
if ($initialLocaleCode != $newLocaleCode) {
$this->_app->getLocale()->setLocaleCode($newLocaleCode);
$this->_factory->getSingleton('core/translate')->setLocale($newLocaleCode)->init($area, true);
}
return $initialLocaleCode;
}
The $initialLocaleCode != $newLocaleCode seems to be the issue here. When iteration orders/customers/subscribers/*, the locale could stay the same, which then prevents executing the code in the statement. And the locale is thus not set in the Translator (Mage::app()->getTranslator()).
We've yet to fix the issue, but you could change if ($initialLocaleCode != $newLocaleCode) { to if (true) { straight in the core source. Off course, this is ugly. I suggest something like extending the class and then :
/**
* Apply locale of the specified store. Extended
* to fix Magento's uninitialized translator.
*
* #see http://stackoverflow.com/questions/19940733/magento-translations-ok-in-online-program-but-not-run-as-cronjob#
* #param integer $storeId
* #param string $area
*
* #return string initial locale code
*/
protected function _emulateLocale($storeId, $area = Mage_Core_Model_App_Area::AREA_FRONTEND)
{
$initialLocaleCode = $this->_app->getLocale()->getLocaleCode();
$newLocaleCode = $this->_getStoreConfig(Mage_Core_Model_Locale::XML_PATH_DEFAULT_LOCALE, $storeId);
$this->_app
->getLocale()
->setLocaleCode($newLocaleCode);
$this->_factory
->getSingleton('core/translate')
->setLocale($newLocaleCode)
->init($area, true);
return $initialLocaleCode;
}
Magento 2
I guess the developers became aware it was borked and they changed the code in Magento 2. The _emulateLocale() function is gone all together and they added this line to the startEnvironmentEmulation() function, without any conditional around it:
$this->_localeResolver->setLocale($newLocaleCode);
It's a bug even with CE 1.9.0.1!
See what I've done about it:
https://magento.stackexchange.com/questions/25612/cron-job-template-block-not-being-translated-but-testobserver-is/25920#25920

Magento Admin Create Order not showing Custom Options

I have simple products with custom options in my store. They work perfectly from the front end, but if I try to add an order from the admin section, The custom options do not show up.
I only have this problem if the type of custom option is a dropdown, multi select, radio buttons, or check boxes. If it is a text field, date or anything else, it works fine.
I am assumming i need to make some changes to something in the /www/app/design/adminhtml/default/default/template/sales/order/create area, but no clue what i should try.
Looking a bit further, I found this /www/app/code/core/Mage/Adminhtml/Block/Sales/Order/Create/Items/grid.php
/**
* Get Custom Options of item
*
* #param Mage_Sales_Model_Quote_Item $item
* #return array
*/
public function getCustomOptions(Mage_Sales_Model_Quote_Item $item)
{
$optionStr = '';
$this->_moveToCustomerStorage = true;
if ($optionIds = $item->getOptionByCode('option_ids')) {
foreach (explode(',', $optionIds->getValue()) as $optionId) {
if ($option = $item->getProduct()->getOptionById($optionId)) {
$optionValue = $item->getOptionByCode('option_' . $option->getId())->getValue();
$optionStr .= $option->getTitle() . ':';
$quoteItemOption = $item->getOptionByCode('option_' . $option->getId());
$group = $option->groupFactory($option->getType())
->setOption($option)
->setQuoteItemOption($quoteItemOption);
$optionStr .= $group->getEditableOptionValue($quoteItemOption->getValue());
$optionStr .= "\n";
}
}
}
return $optionStr;
}
The best way to find the correct template path is to turn on admin template hints.
By default magento does not provide a way to accomplish from the admin, but you can easily accomplish this using one of these methods Enable template path hint in admin pages - Magento

Magento 404 error on language store specific URLs

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;
}
}

Resources