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
Related
I'm building a custom search results page, and I have the IDs of all products that have to be included in the results. I want to override the default search criteria, and yes, I can override $this->_searchCriterias, but it does not change the results page itself.
This is my custom code of CatalogSearch/Model/Advanced.php
public function getSearchCriterias()
{
$search = $this->_searchCriterias;
var_dump($search);
$search = array();
if(isset($_GET['productid'])) {
$value = $this->getIdsFromSearchUrl($_GET['productid']);
if(is_array($value)){
foreach($value as $v){
if(is_numeric($v)){
$product = Mage::getModel('catalog/product')->load($v);
var_dump($product->getId());
$search[] = array('name'=>'Name','value'=>$product->getName());
}
}
} else {
if(is_numeric($value)){
$product = Mage::getModel('catalog/product')->load($value);
$search[] = array('name'=>'Name','value'=>$product->getName());
}
}
}
var_dump($search);
$this->_searchCriterias = $search;
return $search;
}
Any help appreceated.
The way I understand is that you want the site to always include some "featured products", which are not necessarily related to the search term.
I would suggest an alternative method instead of tampering with the search engine logic:
Create a block and template for displaying featured products.
Add the block to Search engine result page inside the product_list block (under catalogsearch_result_index)
Modify list.phtml and echo out the child block you just added.
Let me know if this helps.
i am searching for a way to create magento attribute options multilingual, for more than one language.
Let's say i do have store view name 'german' and 'english'.
I do retrieve the store language codes with (the languages must be set each on the store view configuration pages):
$storelist = Mage::app()->getStores();
$storelang = array();
foreach ($storelist as $id => $s) {
$storelang[$id] = substr(Mage::getStoreConfig('general/locale/code', $id), 0, 2);
}
This way i do create attribute options (the attributes do exist already):
function addAttributeValue($arg_attribute, $arg_value) {
$attribute_model = Mage::getModel('eav/entity_attribute');
$attribute_code = $attribute_model->getIdByCode('catalog_product', $arg_attribute);
$attribute = $attribute_model->load($attribute_code);
if (!attributeValueExists($arg_attribute, $arg_value)) {
$value['option'] = array($arg_value, $arg_value);
$result = array('value' => $value);
$attribute->setData('option', $result);
$attribute->save();
echo "Attribute '" . $arg_attribute . "' with
option '" . $arg_value . "' saved.<br />";
}
But where does the 2nd language come to play? Right now only the default value/default value gets filled into the database.
I would like to prepare a loop for each language, but i do not know the right "switch" for the language.
When creating products, not attribute options, there is a method so set all product fields according to the language with
$Product->setStoreId($lang_value);
but i am not sure about this on attribute options.
Can you guys give me a hint?
Thanks.
Problem solved. Thanks to Marius for pointing out my messed up array.
This line was wrong:
$value['option'] = array($arg_value, $arg_value);
Set it to something like:
$value['option'] = array($arg_value_label, $arg_value_lang1, $arg_value_lang2);
Now i am able to load the the values for each language and set them with that single line above. Maybe this is not the best solution, but it works for me at the moment.
Have a nice weekend everyone.
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.
I have a bit of a dilemma with a Magento website I am building. I have two websites with a store each set up in order to enable multiple currencies checkout for each site. So the only difference between the two sites (on two different domains) that are managed via one common magento installation is the currency display and checkout currency. This is all working fine so far.
However I am trying to share the checkout session between the sites so the shopping cart stays the same when switching between the sites. I manage to get the correct session id added to the switching url so each site knows what session we are looking for. However the method that actually displays the shopping cart does not seem to work website independent - for example in
Mage_Checkout_Model_Session
_getQuoteIdKey() -> uses the current website id to check for the quote id in the session.
And I can not figure out what/how to overwrite this functionality so that each website shares exactly the same shopping cart data!
my $_SESSION['checkout'] variable shows the same on each site but with this website id included the data is no use for the shopping cart:
'quote_id_4' => string '13' (length=2)
Any ideas whether this is possible at all?
After I searched for an answer to this and stumbled across the same question being asked since 2009 without a definite solution, I finally had to look into the deep end of the code myself - and voila, I have a working solution. Here a detailed guide for anyone who wants to set up Magento with
multiple currencies that don't just get displayed but actually charged in the selected currency
share the shopping cart throughout websites and not just stores
The main problem with this combination is that with the default Magento structure you can only ever do one or the other, not the two combined.
So lets set Magento up for multiple currencies first.
Create a website for each currency with a corresponding store and store view (not just store views, complete websites)
Set System - Configuration - Currency Setup per website to the respective currency. All three entries Base Currecny, Default Display Currency and Allowed currencies should be set to just one and the same currency.
Go back to the default overall config scope and set System - Configuration - Catalog - - - Price the Catalog Price Scope to “Website”
You can also define you currency rates in System - Manage Currency Rates
For each website scope set the appropriate System - Configuration - Web - Secure and Unsecure base url.
In your .htaccess file add this at the top (replace the appropriate website domains and code you entered when setting up the websites (here http://website-us.local with base_us and http://website-uk.local with code base_uk)
SetEnvIf Host website-us.local MAGE_RUN_CODE=base_us
SetEnvIf Host website-us.local MAGE_RUN_TYPE=website
SetEnvIf Host ^website-us.local MAGE_RUN_CODE=base_us
SetEnvIf Host ^website-us.local MAGE_RUN_TYPE=website
SetEnvIf Host website-uk.local MAGE_RUN_CODE=base_uk
SetEnvIf Host website-uk.local MAGE_RUN_TYPE=website
SetEnvIf Host ^website-uk.local MAGE_RUN_CODE=base_uk
SetEnvIf Host ^website-uk.local MAGE_RUN_TYPE=website
Overwrite the method convertPrice in Mage/Core/Model/Store and change the method convertPrice - this will ensure that the prices are always displayed in the correct conversion AND the correct currency sign.
/**
* Convert price from default currency to current currency
*
* #param double $price
* #param boolean $format Format price to currency format
* #param boolean $includeContainer Enclose into <span class="price"><span>
* #return double
*/
public function convertPrice($price, $format = false, $includeContainer = true)
{
$categories = Mage::getModel('catalog/category')->getCollection();
$categ_ids=$categories->getAllIds();
$baseCurrencyCode = Mage::app()->getBaseCurrencyCode();
$allowedCurrencies = Mage::getModel('directory/currency')->getConfigAllowCurrencies();
$currencyRates = Mage::getModel('directory/currency')->getCurrencyRates($baseCurrencyCode,array_values($allowedCurrencies));
if ($this->getCurrentCurrency() && $this->getBaseCurrency()) {
$value = $this->getBaseCurrency()->convert($price, $this->getCurrentCurrency());
} else {
$value = $price;
}
if($this->getCurrentCurrencyCode() != $baseCurrencyCode)
{
$value = $price * $currencyRates[$this->getCurrentCurrencyCode()];
}
if ($this->getCurrentCurrency() && $format) {
$value = $this->formatPrice($value, $includeContainer);
}
return $value;
}
}
But of course we also want to share the users data, cart and login throughout the websites we just set up.
While in default config scope set System - Configuration - Customer Configuration - Account Sharing Options - Share Customer Accounts to Global
Overwrite magento/app/code/core/Mage/Checkout/Model/Session.php and replace this method:
protected function _getQuoteIdKey()
{
return 'quote_id';
//return 'quote_id_' . $websites[1];
}
Overwrite magento/app/code/core/Mage/Sales/Model/Quote.php and change the method getSharedStoreIds to:
public function getSharedStoreIds()
{
$ids = $this->_getData('shared_store_ids');
if (is_null($ids) || !is_array($ids)) {
$arrStoreIds = array();
foreach(Mage::getModel('core/website')->getCollection() as $website)
{
$arrStoreIds = array_merge($arrStoreIds,$website->getStoreIds());
}
return $arrStoreIds;
/*if ($website = $this->getWebsite()) {
return $website->getStoreIds();
}
var_dump($this->getStore()->getWebsite()->getStoreIds());exit();
return $this->getStore()->getWebsite()->getStoreIds();
*/
}
return $ids;
}
Overwrite magento/app/code/core/Mage/Customers/Model/Customer.php and change again the method getSharedWebsiteIds() to:
public function getSharedWebsiteIds() {
$ids = $this->_getData('shared_website_ids');
if ($ids === null) {
$ids = array();
if ((bool)$this->getSharingConfig()->isWebsiteScope()) {
$ids[] = $this->getWebsiteId();
} else {
foreach (Mage::app()->getWebsites() as $website) {
$ids[] = $website->getId();
}
}
$this->setData('shared_website_ids', $ids);
}
return $ids;
}
If you use the wishlist option you should do the same for the method in magento/app/code/core/Mage/Wishlist/Model/Wishlist.php and change getSharedWebsiteIds so it not only loads the store ids from the current website but from all of them
Now we also have to implement a currency (website) switch on the frontend stores and pass the correct session ids inbetween so magento knows what stores to look for. I imitated the currency switch here and added the following dropdown to
magento/app/design/frontend/default/yourtheme/template/directory/currency.phtml
This loads all websites and applies the current Session Id as a query string so magento knows on any domain which session to use.
<?php
/**
* Currency switcher
*
* #see Mage_Directory_Block_Currency
*/
?>
<div class="top-currency">
<?php
$websites = Mage::getModel('core/website')->getCollection();
$this_session_id = Mage::getSingleton('core/session', array('name' => 'frontend'))->getSessionId();
?>
<select id="website-changer" onChange="document.location=this.options[selectedIndex].value">
<?php
foreach($websites as $website):
$default_store = $website->getDefaultStore();
$website_currency = $default_store->getBaseCurrency()->getCurrencyCode();
$url_obj = new Mage_Core_Model_Url();
$default_store_path = $url_obj->getBaseUrl(array('_store'=> $default_store->getCode()));
$default_store_path .= Mage::getSingleton('core/url')->escape(ltrim(Mage::app()->getRequest()->getRequestString(), '/'));
$default_store_path = explode('?', $default_store_path);
$default_store_path = $default_store_path[0] . '?SID=' . $this_session_id;
?>
<option <? if(strstr($default_store_path,Mage::getBaseUrl())):?>selected="selected"<?endif; ?> value="<?=$default_store_path ?>">
<?=$website_currency?>
</option>
<?endforeach;?>
</select>
</div>
This query string will only be applied the first time you switch but magento will remember the session id after that stored in a cookie.
In order for this to work properly, overwrite
magento/app/code/core/Mage/Core/Model/Session/Abstract/Varien.php
and
replace this
// potential custom logic for session id (ex. switching between hosts)
$this->setSessionId();
with
// potential custom logic for session id (ex. switching between hosts)
/* Amend to ensure shopping carts are shared between websites */
if (isset($_COOKIE['lastsid']))
{
session_decode(file_get_contents(Mage::getBaseDir('session').'/sess_'.$_COOKIE['lastsid']));
setcookie ('lastsid', '', time() - 3600);
}
if (isset($_GET['SID']))
{
$this->setSessionId($_GET['SID']);
session_decode(file_get_contents(Mage::getBaseDir('session') . '/sess_' . $_GET['SID']));
setcookie('lastsid', $_GET['SID']);
$_COOKIE['lastsid'] = $_GET['SID'];
}
else
{
$this->setSessionId();
}
/* Amend end */
This should now display multiple currencies, charge in multiple currencies across mutliple websites and on top of this share logins and shopping carts. This solution is a collection of knowledge I found on the interwebs combined with a few bits and pieces I figured out myself, so thanks for anyone who gave advice!
I have a script that pulls in data from a 3rd party file. My import simply parses and inserts rows, which is working fine.
The problem comes with images.
When the import script runs, it first deletes all the current items and then the import begins, inserting all products and images into the gallery.
On the first import, everything is fine, the images go in and I see them on the frontend no problem. The problem comes with everytime I then re-import these products, it doesn't seem to delete all images, as when the products re-import, I see, for example the 4 images correct, then then loads of blank rows, like images should be there, but can't be found.
I don't want to see these blank lines, but I'm not sure why they are there.
Could it be because the images for the product are already in the catalogue?
I am really unsure what and why this is doing what it is.
Thanks
EDIT:
My code is:
require_once('app/Mage.php');
$app = Mage::app('default');
$product = Mage::getSingleton('catalog/product');
$txt_file = file_get_contents('test.txt');
$rows = explode("\n", $txt_file);
array_shift($rows);
foreach($rows as $row => $data)
{
//get row data
$row_data = explode('^', $data);
$info[$row]['uniqueid'] = $row_data[0];
$info[$row]['client'] = $row_data[1];
$info[$row]['make'] = $row_data[2];
$info[$row]['model'] = $row_data[3];
$info[$row]['adtext'] = $row_data[4];
//display images
$row_images = explode(',', $info[$row]['picturereference']);
foreach($row_images as $row_image)
{
$product->addImageToMediaGallery(Mage::getBaseDir('media') . DS . 'import/' . $row_image, array('image', 'small_image','thumbnail'), false, false);
}
$product->setStoreId(Mage::app()->getStore(true)->getWebsite()->getId());
$product->setWebsiteIds(array(Mage::app()->getStore(true)->getWebsite()->getId()));
$product->setId($info[$row]['id']);
$product->setSku(strtolower($info[$row]['make']).'-'.strtolower($info[$row]['model']));
$product->setName($info[$row]['make']);
$product->setDescription($info[$row]['adtext']);
try {
$product->save();
echo "Saved";
}
catch (Exception $ex) {
echo "<pre>".$ex."</pre>";
}
}
Is this because the addImageToMediaGallery is called on each iteration and adding all images to each product?
Thanks
Ok so I figured out my problem
Inside the foreach I moved the call to the getSingleton and I added the the following: $product = Mage::getModel('catalog/product');
I then, after each iteration, unset the following:
unset($product);
unset($info);
unset($stockData);
unset($row_images);
This seemed to fix my script and now imports each products images into the proper product rather than importing other and adding random blank entries
Thanks all
A few files you'll want to examine to break down addImageToMediaGallery and determine what exactly its doing.
app/code/core/Mage/Catalog/Model/Product.php - Contains the method your using, breaking it down more you'll find...
app/code/core/Mage/Catalog/Model/Product/Attribute/Backend/Media.php - Contains more of the "bits and pieces" of addImageToMediaGallery like addImage etc.
Some possibilities to try would be either
A) determine if the files already exist and are attached to the product and ignoring them upon a second round of import. Perhaps looking for different file stamp. getMediaGalleryImages within Product.php.
B) clear the media files associated with the products BEFORE importing again? clearMediaAttribute and removeImage within Media.php.
I would also try the $move option set to true within your addImageToMediaGallery call as well.
/**
* Add image to media gallery
*
* #param string $file file path of image in file system
* #param string|array $mediaAttribute code of attribute with type 'media_image',
* leave blank if image should be only in gallery
* #param boolean $move if true, it will move source file
* #param boolean $exclude mark image as disabled in product page view
*/
public function addImageToMediaGallery($file, $mediaAttribute=null, $move=false, $exclude=true)
{
Another option would be to try to specify null for the second param, if you note the PHPDoc comments, leaving it blank will only be for the gallery which sounds like what you are wanting...
foreach($row_images as $row_image)
{
$product->addImageToMediaGallery(Mage::getBaseDir('media') . DS . 'import/' . $row_image, null, false, false);
}
Let me know if any of these help.
Give something like this a try:
//Check if gallery attribute exists then remove all images if it exists
//Get products gallery attribute
$attributes = $product->getTypeInstance()->getSetAttributes();
if (isset($attributes['media_gallery'])) {
$gallery = $attributes['media_gallery'];
//Get the images
$galleryData = $product->getMediaGallery();
foreach($galleryData['images'] as $image){
//If image exists
if ($gallery->getBackend()->getImage($product, $image['file'])) {
$gallery->getBackend()->removeImage($product, $image['file']);
}
}
}
This blog posting may also help, as its where I got the code snippet form also:
http://www.sharpdotinc.com/mdost/2010/03/02/magento-import-multiple-images-or-remove-images-durring-batch-import/