I am looking to change the order in which a list is being brought together in our Magento cart.
We have the following coding:
public function getOptionList()
{
$options = false;
if (Mage::getStoreConfig('SCP_options/cart/show_custom_options')) {
$options = parent::getOptionList();
}
if (Mage::getStoreConfig('SCP_options/cart/show_config_product_options')) {
if ($this->getConfigurableProductParentId()) {
$attributes = $this->getConfigurableProductParent()
->getTypeInstance()
->getUsedProductAttributes();
foreach($attributes as $attribute) {
$options[] = array(
'label' => $attribute->getFrontendLabel(),
'value' => $this->getProduct()->getAttributeText($attribute->getAttributeCode()),
'option_id' => $attribute->getId(),
);
}
}
}
return $options;
}
Which displays the following: http://awesomescreenshot.com/053ffeie9
We are looking to swap the Attributes and Options over so the Attributes display at the top of the item.
In the coding we've established that the top if statement is for options and the bottom if statement is for the attributes, so theory being it should just be a case of swapping them over... unfortunately it doesn't seem as simple as that.
If we swap them the attributes don't show but the options do.
Would someone be able to recommend anything to try as we're getting very frustrated trying to sort this.
swap them and then use array_merge on the bottom half. When you swap them, the second part was just assigning options and wiping out the attributes part. This puts the two together instead of overwriting:
if (Mage::getStoreConfig('SCP_options/cart/show_custom_options')) {
$options = array_merge($options, parent::getOptionList();
}
Related
I made a simple import script and I'm trying to programatically save 3 custom attributes (att1, att2, att3) together with all other info (name, description, price, category..).
So basically I have:
public function insert_product($data) {
$product = Mage::getModel('catalog/product');
try {
$sku = $data['code'];
if ($this->prodottiImportati[$sku]) {
$sku = $data['code'] . '-1';
}
$this->prodottiImportati[$sku] = true;
$product->setSku($sku);
$product->setName($data['name']);
$product->setDescription($data['desc']);
$product->setShortDescription($data['short_desc']);
$product->setManufacturer('');
$product->setPrice($data['price']);
$product->setTypeId('simple');
$product->setAttributeSetId($this->attributeSet);
$categorie = $this->get_categories($data);
$product->setCategoryIds($categorie);
$product->setWeight($data['peso']);
$product->setTaxClassId(2); // taxable goods
$product->setVisibility(4); // catalog, search
$product->setStatus(1); // enabled
$product->setWebsiteIds($data['store_id']);
$stockData = $product->getStockData();
$stockData['qty'] = $data['qty'];
if ($data['quantita'] > 0) {
$stockData['is_in_stock'] = 1;
} else {
$stockData['is_in_stock'] = 0;
}
$stockData['manage_stock'] = 1;
$stockData['use_config_manage_stock'] = 0;
$product->setStockData($stockData);
$product->setIsMassupdate(true)->setExcludeUrlRewrite(true);
$product->save();
$productID = $product->getId();
} catch(Exception $e) {
echo ($e->getMessage());
}
return $productID;
}
First thing I tryed was adding a
$productID = $this->insert_product($data);
Mage::getSingleton('catalog/product_action')->updateAttributes(
array($productID), array(
'att1' => $data['att1'],
), $data['store_id']);
So basically updating things after the insert function was called, using the ID got after the insert. store_id is the ID of the store in that given language. Didn't save anything.
Second attempt, I follwed this: Magento add custom options with programmatically importing products
I tryed that within the insert_product function and also outside after $productID = $this->insert_product($data); Neither worked.
Last I tryed a magical $product->setAtt1('value'); witin the insert_product function, not sure how Magento would understand how to set att1 that way, but...you know, I read it somewhere and I gave it a try ;)
att1, att2 and att3 are spelled lowercase, althoug they have an uppercase label (think that dosen't matter here), they are part of an attribute group (I'm passing it with $product->setAttributeSetId($this->setAttributi)) and they are all multiple selection attributes, so I could in teory pass multiple values to them.
I'm sure I'm missing something on the way. Can anyone help?
After 10 more minutes since I wrote here, I was able to find the way. I took me forever to solve it.
The clue of this is that you have to add attributes ID, not values. That happens at least for me with multiple selection attributes, not sure if it's true all the time.
Here is how I did:
In the function insert_product I added:
$optionId = $this->get_option_id_by_code('att1', 'Value of the attribute you need to add');
$product->setAtt1($optionId);
So if yor attribute is named, let's say "brand" it will be:
$optionId = $this->get_option_id_by_code('brand', 'Nike');
$product->setBrand($optionId);
If your attribute can have multiple values, you need to change the code above to:
$optionId = array();
foreach ($myAttributesArray as $someValues) {
$optionId[] = $this->get_option_id_by_code('att1', $someValues);
}
$product->setAtt1($optionId);
The foreach is just an example, you need to loop through your mutiple values and get the respective ID and add them all toghether with setAtt1 passing them as an array. I'm working on an improved version where the get_option_id_by_code function does all at once in a more efficient way. This is kust a "basic" version that works, feel free to make it fancy and smart.
Then I created an other function called get_option_id_by_code like this:
protected function get_option_id_by_code($attrCode, $optionLabel) {
$attrModel = Mage::getModel('eav/entity_attribute');
$attrID = $attrModel->getIdByCode('catalog_product', $attrCode);
$attribute = $attrModel->load($attrID);
$options = Mage::getModel('eav/entity_attribute_source_table')
->setAttribute($attribute)
->getAllOptions(false);
foreach ($options as $option) {
if ($option['label'] == $optionLabel) {
return $option['value'];
}
}
return false;
}
To be honest I found this with a collage of other sources / authors, so I need to be thankful to a bunch of smarter programmers here and there, since it took a while for me to strouggle with this simple task I wrote the solution here hoping to help you guys. Thanks!
My code is pretty basic. I'm using an array to generate a datasheet for a product based on it's SKU and a filepath.
My array looks like this:
$a=array(
"/images/ManualSheets/factSheetCLASSIC.pdf"=>"KE800/6",
"/images/ManualSheets/factSheetMICRO.pdf"=>"KE800/12",
"/images/ManualSheets/factSheetSMALL.pdf"=>"KE4000/12",
"/images/ManualSheets/factSheetMEDIUM.pdf"=>"KE8000/12",
);
Where the first Key is the filepath, and the second Key is the SKU (as generated by the system) I then use an if/else to generate a button - so if a product is not in the array it returns a blank value and doesn't have a button which leads to nowhere
$factsheetweblink_url = array_search($product_sku,$a);
if ($factsheetweblink_url==false) {
echo " ";
}
else {
echo "<div class='productpagestockistBTN'>
<img src='/images/FactSheet_btn.png' >
</div>";
}
?>
This code works fine. The catch comes when I have products with different SKUs but the same datasheet file, (same brand and make but a different model). Currently I can only get it to work by uploading multiple copies of the datasheets with different names, but it's becoming a big waste of space.
I have tried using an array as a key to hold multiple values to the one key..
"/images/ManualSheets/factSheetMEDIUM.pdf"=> array("KE8000/12","KE7000/12"),
but it doesn't seem to be working... I'm not quite sure if I need to refine my if statement to search within the sub arrays as well or..?
Any help would be appreciated, thanks in advance.
You should use arrays like this:
$products = array(
0 => array(
"pdf" => "/images/ManualSheets/factSheetCLASSIC.pdf",
"skus" => array("KE800/6","KE900/6")
),
1 => array(
"pdf" => "/images/ManualSheets/factSheetCLASSIC3.pdf",
"skus" => array("KE100/6","KE200/6"))
);
This is because array_search returns just first row whit that key.
Then just do your own search function like:
function findBySku($items, $sku) {
$pdf = ""; // return empty if not found.
foreach($items as $row) {
if (in_array($sku, $row['skus'])) {
$pdf = $row['pdf'];
break;
}
}
return $pdf;
}
and call that function:
$pdf = findBySku($products, "some sku");
I need to gather all of the available attributes for the given product and then create a multidimensional array with them. Hopefully you can create a multidimensional array with more than two dimensions? The resulting array declarations should look like this:
$simpleArray[$child->getVendor()][$child->getColor()]=$child->getPrice();
First I'm gathering all the attributes then adding them to a string where I can call each one later:
$_product = $this->getProduct();
$_attributes = Mage::helper('core')->decorateArray($this->getAllowAttributes());
//Gather all attribute labels for given product
foreach($_attributes as $_attribute){
$attributeString .= '[$child -> get' . ucfirst($_attribute->getLabel()) . '()]';
}
Then I'm attempting to append that string to the array to declare it:
foreach($childProducts as $child) { //cycle through simple products to find applicable
//CAITLIN you are going to need way to search for other attributes, GET list of attributes
$simpleArray. $attributeString =$child->getPrice();
}
Mage::log('The attributeString is '. $simpleArray. $attributeString, null, 'caitlin.log'); //This is logging as "The attributeString is Array74"
Any suggestions?
You'll need to use recursion to do what you're requesting without knowing the attribute names while writing the code.
This will loop through and provide all of the child product prices, in a multi dimensional array based on the configurable attributes. It assumes that $_product is the current product.
$attrs = $_product->getTypeInstance(true)->getConfigurableAttributesAsArray($_product);
$map = array();
foreach($attrs as $attr) {
$map[] = $attr['attribute_code'];
}
$childPricing = array();
$childProducts = $_product->getTypeInstance()->getUsedProducts();
foreach($childProducts as $_child) {
// not all of the child's attributes are accessible, unless we properly load the full product
$_child = Mage::getModel('catalog/product')->load($_child->getId());
$topLevel = array($child->getData($map[sizeof($map)]) => $_child->getPrice());
array_pop($map);
$childProducts = array_merge($childProducts,$this->workThroughAttrMap($map,$_child,$topLevel));
}
//print_r childProducts to test, later do whatever you were originally planning with it.
In the same controller include this:
protected function workThroughAttrMap(&$map,$child,$topLevel) {
$topLevel = array($child->getData($map[sizeof($map)]) => $topLevel);
array_pop($map);
if(sizeof($map) > 0) return workThroughAttrMap($map,$child,$topLevel);
else return $topLevel;
}
I haven't tested this code so there may be a few minor bugs.
There are a few things you could do to make the code a bit cleaner, such as moving the first $topLevel code into the function, making that an optional parameter and initializing it with the price when it doesn't exist. I also haven't included any error checking (if the product isn't configurable, the child product doesn't have its price set, etc).
I have code like this:
$something_type = $this->db
->where('something_type_id', $something->something_type_id)
->get('something_types')
->row();
if(!$something_type) {
$something->type = lang('data_not_specified');
} else {
$something->type = $something_type->something_type_name;
}
// everything is exactly the same here except for one word
$something_category = $this->db
->where('something_category_id', $something->something_category_id)
->get('something_categories')
->row();
if(!$something_category) {
$something->category = lang('data_not_specified');
} else {
$something->category = $something_category->something_category_name;
}
...
// and so on, about four times
One solution I thought of was:
$classfications = array('type', 'category');
foreach ($classifications as $classification) {
$id_property = "something_{$classificiation}_id";
$something_classification = $this->db
->where("something_{$classification}_id", $something->$id_property)
->get("something_{$classification}s")
->row();
if(!$something_classification) {
$something->$classification = lang('data_not_specified');
} else {
$name_property = "something_{$classificiation}_name";
$something->$classification = $something_classification->$name_property;
}
}
Of course, reading that will probably result in someone having the fits, so what do I do about this? This is probably a very common problem but I can't name it so having trouble Googling it.
Are you looking for Inflection?
The biggest challenge with the code snippet in the question is that the classifications you have provided have different pluralized forms (e.g., "type" becomes "types", yet "category" becomes "categories"). In order to structure this data without inflection, you could create a nested array hash, e.g.,
$classifications = array(
'type' => array(
'plural' => 'something_types',
'id' => 'something_type_id',
),
// etc.
);
foreach ($classifications as $singular => $data) {
/*
* Produces:
* $singluar = 'type';
* $data['plural'] = 'something_types';
* $data['id'] = 'something_type_id';
*/
}
However, most of the PHP frameworks I have used include an Inflector class (or similar) to handle the nuances in language that make using singular and plural names together problematic (and would avoid the need for a nested data structure, as described above).
Have a look at CodeIgniter's Inflector Helper to get an idea of what this entails. If you are already using a framework (your use of a $db helper suggests you might be) then also be sure to see if it supports ORM, which handles this kind of scenario automatically.
I have created a custom module which displays a tab and a section in admin configuration panel to manage customer attributes.
I have loaded all customer attributes with a check box each.
This is my code for displaying all customer attributes as checkboxes. I want the checkbox value selected from here to be added as a column in Manage Customer Grid.
Model/Attributes.php
$attributes = Mage::getModel('customer/entity_address_attribute_collection');
$result = array();
foreach ($attributes as $attribute)
{
if (($label = $attribute->getFrontendLabel()))
$result[$attribute->getId()] = $label;
}
$attributes1 = Mage::getModel('customer/entity_attribute_collection');
$result1 = array();
foreach ($attributes1 as $attribute1)
{
if (($label1 = $attribute1->getFrontendLabel()))
$result1[$attribute1->getId()] = $label1;
}
$final = array_merge($result, $result1);
return $final;
Now based on selection of these check boxes, I would like to add an extra column in 'Manage Customer' Grid.
I tried retrieving the value of selected checkbox but I just get the array index number.
Mage::getStoreConfig('sectionname/groupname/fieldname');
Can some one tell me how to fetch the the selected checkbox value and add a column based on the selection represented by that checkbox?
Thanks in advance.
When you use array_merge you are destroying the correct indexes, which are supposed to be the attribute IDs. Also it's good practice to give your variables meaningful names.
$result = array();
$addressAttributes = Mage::getModel('customer/entity_address_attribute_collection');
foreach ($addressAttributes as $addressAttribute)
{
if (($addrlabel = $addressAttribute->getFrontendLabel()))
$result[$addressAttribute->getId()] = $addrlabel;
}
$customerAttributes = Mage::getModel('customer/entity_attribute_collection');
foreach ($customerAttributes as $customerAttribute)
{
if (($custlabel = $customerAttribute->getFrontendLabel()))
$result[$customerAttribute->getId()] = $custlabel;
}
return $result;
I suppose the next step is to remove the columns that your grid's parent will add, these are stored in a grid's protected _columns property. Not all columns are to be removed, such as the massaction column. Then add your chosen columns back in.
protected function _prepareColumns()
{
parent::_prepareColumns();
// remove the excess columns here
$attributeIds = Mage::getStoreConfig('sectionname/groupname/fieldname');
$attributes = Mage::getModel('eav/entity_attribute')->getCollection()
->addFieldToFilter('attribute_id', array('in' => $attributeIds));
foreach ($attributes as $attribute)
{
$options = array();
if ($attribute->getFrontendInput() == 'select') {
foreach ($attribute->getSource()->getAllOptions() as $value) {
$options[$value['value']] = $value['label'];
}
}
$this->addColumn($attribute->getCode(), array(
'index' => $attribute->getCode(),
'header' => $attribute->getFrontendLabel(),
'type' => $attribute->getFrontendInput(),
'options' => $options
));
}
return $this;
}
This way may lose useful formatting like column widths, etc. so a more sophisticated way would be to work out which columns are already in place and leave them, then only remove those that haven't been selected.
I would, in your module, set in config.xml that you are overwrting the Block Mage_Adminhtml_Block_Customer_Grid with your own block (which inherits from Mage_Adminhtml_Block_Customer_Grid) and in your own block make a function
protected function _prepareColumns()
{
$this->addColumn('mycolumn', array(
'header' => Mage::helper('customer')->__('My Column'),
'index' => 'key',
));
return parent::_prepareColumns();
}
Without knowing more about your data its hard to give better advice, but this should be enough to get you started.