I'm trying to add some custom options to already existing products in Magento. Seems to work fine, I added the needed rows in the following tables:
catalog_product_option
catalog_product_option_title
catalog_product_option_type_value
catalog_product_option_type_price
catalog_product_option_type_title
I also updated has_options and required_options for the right product, in the following tables:
catalog_product_entity
catalog_product_flat_1
catalog_product_flat_2
catalog_product_flat_3
When I open the product, the options doesn't show, actually, it shows less. The button to order it disappears. When I open the edit page, it does show the options. After saving, it appears on the front-end too.
What am I missing?
Update:
After manually going through literally every query that was executed after a save action, I discovered what I was missing. When a product has options, it has to display them in a different template (or whatever it's called in Magento). To do this, you'll have to change the value for the attribute options_container.
So, there's a really easy fix for that. Just look up the attribute_id in the table eav_attribute. Then just run the following query for each product:
UPDATE `catalog_product_entity_varchar` SET `value` = 'container1' WHERE `attribute_id` = 836 AND `entity_id` = $productId;
That'll do the trick! :)
After manually going through literally every query that was executed after a save action, I discovered what I was missing. When a product has options, it has to display them in a different template (or whatever it's called in Magento). To do this, you'll have to change the value for the attribute options_container.
So, there's a really easy fix for that. Just look up the attribute_id in the table eav_attribute. Then just run the following query for each product:
UPDATE `catalog_product_entity_varchar` SET `value` = 'container1' WHERE `attribute_id` = 836 AND `entity_id` = $productId;
That'll do the trick! :)
You really shouldn't be accessing the database directly for any reason. This undermines the power and resourcefulness of using an EAV system.
Extend Mage.php if outside of magento (disregard if not)
Make a collection of whatever entities you want to manipulate
Use said collection to write/read data
Save yourself headaches down the road!
Related
I am taking over a website from another developer, and have found the setup of attributes to be a bit of a mess.
Specifically, products have attributes that aren't associated with the relevant attribute sets.
If you take wine with an attribute set "Wines", one of whose attributes is "Grape Variety".
But I also have "Beers" with a completely different attribute set, but somehow one of my beers has a Grape Variety.
It's not assigned to the Beers attribute set, it doesn't show up in the back end for this product, (so I can't edit it) but if I look in the database it's there (in catalog_product_entity_* and catalog_product_index_eav), furthermore when I do an export it's there too, and if someone searches for "Merlot", they are coming up with this beer. There are hundreds of products like this.
What is the best way of removing all attributes from products that are not within their assigned attribute sets?
I could figure it out in SQL I'm sure, but that's not the best way of doing things as I'd be afraid of missing something and screwing up the products altogether.
This is what I ended up doing. A few weeks later and it doesn't seem to have caused any issues yet:
CREATE TABLE catalog_product_entity_int_old LIKE catalog_product_entity_int;
INSERT INTO catalog_product_entity_int_old SELECT * FROM catalog_product_entity_int;
DELETE FROM catalog_product_entity_int
WHERE value_id IN
(SELECT cpei.value_id
FROM catalog_product_entity_int_old cpei
WHERE cpei.attribute_id NOT IN
(SELECT eea.attribute_id
FROM eav_entity_attribute eea
JOIN catalog_product_entity cpe ON eea.attribute_set_id = cpe.attribute_set_id
WHERE cpe.entity_id = cpei.entity_id)
ORDER BY cpei.entity_id)
and
DELETE FROM catalog_product_index_eav WHERE
attribute_id NOT IN (
(SELECT eea.attribute_id
FROM eav_entity_attribute eea
JOIN catalog_product_entity cpe ON eea.attribute_set_id = cpe.attribute_set_id
WHERE cpe.entity_id = catalog_product_index_eav .entity_id)
);
Then regenerate the indices.
I would definitely use Magmi to clean this up:
First, do a product export from within Magento (System -> Import/Export -> Profiles) and choose "Export All Products." In the resulting CSV, you will have columns for each attribute and you can remove any irrelevant attribute values for each product. This will allow you to bypass the backend where attributes are set for a particular product, but not in the product's attribute set.
Take a good look at the Magmi Wiki, but a few quick tips: Magmi only imports the columns you specify, so you can safely remove most of the columns when you perform your import. For example, I always make sure to remove the image columns if I'm not importing images (or you may lose all of your images). Also, be sure to do a database backup before running your import in case something goes wrong.
I am trying to figure out how I might be able to do this - possibly in the mysql database, but I'm not sure of all the tables involved, so daren't go much further?
I have added an attribute called "condition" to the defaul attribute set.
I need to populate that attribute value for every product, but the admin system requires me to fill in many other attributes if I try to bulk update them using the admin form. This can't happen as "description" is different for every product, obviously.
So, can someone tell me how I might populate this attribute value with the value "new" for every product in my database?
Realistically, I can change this attribute value for the number of products that need a different value "used", but if the update could be filtered on SKU, I can make it work right first time. I think!
The programming approach is to save the following script in your Magento folder and execute it by visiting the address directly. It might be slow but that doesn't matter if it's only going to be run once and then deleted afterwards.
<?php
require 'app/Mage.php';
umask(0);
Mage::app();
$products = Mage::getResourceModel('catalog/product_collection');
foreach ($products as $product) {
// replace IS_NEW with a test perhaps using $product->getSku()
$product->setCondition(IS_NEW ? 'new' : 'used')
->save();
}
Not a programming answer so perhaps not suitable for Stack Overflow but there are a number of workarounds.
You could export all products to Excel, bulk update many rows at once then re-inport. Use Magmi if you have many products.
There are some extensions which let you update many attributes at once. This Mass Actions is expensive but gives you an idea what might be available if you search.
As much as I loathe desktop applications for web services there is Store Manager which specialises in bulk actions.
I understand how to programmatically create a product and also add to cart. I know this might sound dumb but is it is possible to generate a product on the fly and add that to the cart/quote but never actually save it in the database.
We want to create a made to order interface and I was thinking at the end it could add a bundle product with all the selections but that bundle product wouldn't actually exist in the backend.
I figured as long as you can make sure the quote and order has what it needs in terms of the product it would be ok, but obviously there is probably a lot that is tied to looking up stuff in the db on a specific sku or ID. I know that if you delete a product and then look at an order in the admin that causes issues, at least it did for this one scenario I was dealing with.
I was thinking of creating a giant bundle product that had like 6 different bundle items and each item could potentially have like 500 products and then based on what the user selects I programmatically add the bundle to cart. But then I wasn't sure if there would be a negative affect with having a gigantic bundle product like that as well.
UPDATE:
I don't think this will work, obviously there are a lot of information tied to the product in the database and we setup a test and right away we get an error for $item->getProduct(). We are moving forward with creating a giant bundle product and also the generic product with adding custom options on the fly, which Anda pointed out below. Any other suggestions will be greatly appreciated.
I'm not sure that clockworkgeek's approach is going to work. On every page load, Magento loads the items from the cart to make sure that they are still valid (in-stock, prices correct, etc), and amends the cart to reflect those values. My understanding of the system in the past has been that a product in the cart needs to have a corresponding database value to survive this process.
The "giant bundle product" approach is a pain, but in the past has been the best approach I have found. Attempting to change the values of the product (such as price or attributes) will be overridden by the cart checks, so you need a product w/ maximal flexibility, such as an overly-customized bundle product or configurable product.
Hope that helps!
Thanks,
Joe
Why not create a generic product in db and then set the product customization as custom options (additional_options) on the fly depending on the user selection. You can add custom options to the product (actually to the quote item) without having to save them in the database. I did this once for a website that sells glasses with prescription. The prescription was added as an option.
You can programmatically create Mage_Sales_Model_Quote_Items and add them to the cart. You've noticed it needs a product to match it's product ID but it needn't be a useful one. It could be a blank, disabled product, also created in code. All that's needed is a stub.
The necessary stuff for the cart is stored in the quote item - fields like name, value and quantity. Those fields are then copied directly to the order without using a product.
Mage::getModel('catalog/product')
creates a new product. you can add it to a cart, by doing something like this:
$cart = Mage::getSingleton('checkout/cart');
$product = Mage::getModel('catalog/product')
->setStoreId($storeid)
->setTypeId($type_id)
->setQty($quantyty)
->setWhatAttributYouWant($attribute);
$cart->addProduct($product);
product attributes you can find in the DB in tables that start like catalog_product_... or take an already created product, and see what attributes it has in the _data array (with debugger or just print_r($product->getData))
I am facing a problem while making product configurable i used this link http://www.magentocommerce.com/knowledge-base/entry/tutorial-creating-a-configurable-product/ but In associated tab the products doesnt show up
Thankds and regards
2 things you can check:
Are you sure that the simple products you want to associate to the configurable product actually have values for the attribute you made the configurable product configurable by? So if you made a configurable product based on 'color', do the simple products have values selected for 'color'?
When you are looking at the associated products tab, and seeing the blank grid there, have you tried resetting the filter, or selecting 'No' or 'Any' in the first column? If it is set to 'Yes', it is only looking for products that have already been associated.
How does configurables products linking works in magento ?
Getting rid of being trolled by the linking of configurables products with their simple counterparts ? Let's explain how does Magento link'em... and why it sometimes doesn't work as expected.
The first point to understand is how the data persistence is managed by the application. As expected, links are stored in database. Thought it was in catalog_product_relation ? You were wrong. It should be too simple to respect the Magento's spirit :)
catalog_product_relation vs catalog_product_super_* tables
I won't tell catalog_product_relation is useless – in fact, it's necessarily there for something. But from version 1.5+, this is not there that links are stored, and I can't explain what does its purpose is.
First step
The first step of the linking process is the definition of the configurable product's configurable attributes. Supposing we're creating a new configurable product from an attribute set having a few global-select attributes.
If you try to access to your configurable product, the application will ask you which of 'em should be used as configurable attributes, in a form using a list of checkboxes associated to each attribute. By selecting some and saving your product, you insert in catalog_product_super_attribute a row by attribute (an association between product's id and attribute's one).
Second step
The second step is the linking itself with the associated simple products. This step is a bit more complex, because it implies some checks of the database's content, which we'll detail further below. Some rules to keep in mind about that :
only products having the same attribute set as the current configurable product
options must be defined for the configurable attribute
only one simple can be linked for a given configurable attribute combination
simple can be linked to as many configurables as desired
Then, what happens when we go to our configurable's associated products tab ? Don't be scray to not see any of your simple-corresponding-product in the list that display – it's filter is configured by default to display only already linked products. Here is what happens behind the scene :
the application go check the catalog_product_super_attribute table, and bring back each corresponding attribute id defined there for the current product (our configurables attributes)
from them, it will go check eav_attribute to get some details about them – in which ones the backend_type, which is the more important part of this explanation
parallely, the catalog_product_super_link table is checked too. Any product linked to current_product is a potential linked product
for each attribute, the application check if a value exists in catalog_product_entity_{backend_type} for each potentially linked product. Note that if no value exists for a given product, it won't be validated nor as a potential link nor than an effective one, even if it has already been linked (we'll see below what it implies for attribute creation).
To resume, only products with a valid value are diplayable and effectively linked / linkable. Note that all of the combination must have valid values – if any of the configurable's attribute as none, game over, you'll not have any link between your simple product and its configurable counterpart.
We should think it's ok, and everything will go right now, since we know how everything works in database. That's true if you always create your attributes from the application's back-office. But since scripting attributes is a very common way to proceed, you're much like to be in this second case, which implies a potential HUGE problem.
Programatically created attributes and... What the hell !?! This attribute has change of backend type !
Edit note: this case happens effectively when using a eav/entity_attribute_source_table source model
This a trouble I personnally runned through. If you check attributes backend models in database (only for select attributes – we do not care about which ones are not usable as configurable's ones), you'll see some varchar, some int... In short, multiple ones, and we could rightfully expect any of them works.
And they do so. Since you do not decide to add an option to your attribute from the back-office, or anything else that require to click on the « save » button on the attribute page.
The point is that when you save your attribute, Magento, in it's great goodness, ask itself what is the type of the attribute you ask him to save. The point is that before anything else, it's a select. And a select has options. And options has id. Which are the values that will be put in catalog_product_entity_{backend_type}, in any case. The label is just properly ignored in that (it's stored in it's proper table and doesn't affect anything there). Only the id is used.
And what shall we expect from Magento :) ?
It just change the attribute backend type to int systematically.
So, if you have products that used to be linked and are no more, go check the catalog_product_entity_{backend_type} tables and the eav_attribute one – compare the backend type, look for values in each values table... If you find 'em in a table that does not correspond, you get your problem. You have a few ways to correct the problem, here are the both I find myself (and I really do not promote the first, which I put only for explanation purpose).
First way: get the backend type back (The Dirty Trick)
It has changed to int ? Don't care. Bring it back to what you want it to be.
Why it's dirty : because you want you user to be able to update it's attributes when he wants. If you update the backend type to varchar, for example, any label change in the back-office for an option will rollback to int as it will be saved.
Second way: let's correct everything ! (The Right Thing)
You can pass throught this... bad situation, with a bit of MySQL without harming your database. But please, first, dump it. Then you'll require 4 steps :
check that you don't already have the data in catalog_product_entity_int table
duplicate the rows of the current ...entity{attribute} table to the ..._entity_int one by using an INSERT / SELECT statement (this query can be a bit long)
update your configurable attributes (not all your attributes, ONLY the ones you know you have created and are use to set configurable products) to set their backend type to int (and never do something else again for configurable selects :) )
delete all entries corresponding to attribute in the ..._entity{attribute} table that you'll no more use (it can do pretty much entries since you can have a lot of products if you get a lot of options)
Here are some MySQL scripts, corresponding to these steps, supposing you have at start a list of the attributes codes concerned :
Check existing entries in entity int for a given list of attribute codes
-- Check existing entries to not duplicate
SELECT ea.attribute_code,
count(*)
FROM eav_attribute as ea
INNER JOIN catalog_product_entity_int as cpei
ON ea.attribute_id = cpei.attribute_id
WHERE ea.attribute_code IN(
{attributeCodesList}
)
GROUP BY ea.attribute_code
Duplicate entries from entity_varchar table (for example) to entity_int for a given list of attribute codes
-- Duplicating missed selects from varchat entity table to int
INSERT INTO catalog_product_entity_int (entity_type_id, attribute_id, store_id, entity_id, value)
SELECT cpev.entity_type_id,
cpev.attribute_id,
cpev.store_id,
cpev.entity_id,
cpev.value
FROM eav_attribute as ea
INNER JOIN catalog_product_entity_varchar as cpev
ON ea.attribute_id = cpev.attribute_id
WHERE ea.attribute_code IN(
{attributeCodesList}
)
Update attributes to never have the problem again!
-- Update missed select attributes from varchar backend type to int one
UPDATE eav_attribute as ea
SET ea.backend_type = 'int'
WHERE ea.attribute_code IN (
{attributeCodesList}
)
Remove the no more used entries from your database
-- Kill old varchar in varchar entity table
DELETE FROM catalog_product_entity_varchar
WHERE attribute_id IN (
SELECT ea.attribute_id
FROM eav_attribute as ea
WHERE ea.attribute_code IN (
{attributeCodesList}
)
)
Hope it will help all of the ones who can't make their associated products show up to get the trick!
$attributeInfo = Mage::getResourceModel('eav/entity_attribute_collection')
->setCodeFilter('modellijn')
->addAttributeToFilter('brand', 114)
->getFirstItem();
Hi there. I would like to know the right syntax for the following:
Select the attribute modellijn where the attribute brand=114. The above syntax gives back an error. I have been searching for 2 days now for the right syntax but no result so far unfortunately.
I am hoping someone here is willing to help me!
So the first problem I see here is... that you are attempting to select the attribute for a particular brand. Attributes do not in fact have brands (nor modellijns).
Can you please clarify the use case? Are you trying to get the modellijn (that's fun to type) value of all products with brand 114? What is your expected output?
Or, if you're more comfortable as such, what would be the SQL query you'd expect to see generated?
Thanks,
Joseph Mastey
Okay, based on your update, I just wanted to clarify a few things.
Attribute sets have attributes
Attributes have options (sometimes)
Products have attribute values
Categories have products
If you just need to find the modellijin of a particular product, then you just need to ask for it. If you have a single product, this should do the trick:
$product = Mage::getModel("catalog/product")->load($id); // Magento does this for you in some cases
$product->getModellijn(); // this will return your value
$product->getAttributeText('modellijn'); // IIRC, this works for <select> type attributes
If you're loading products from a collection, you need to make sure to tell Magento that you want to load that attribute too. Selecting everything from EAV is even more expensive than selecting everything from a standard, normalized database. Therefore, Magento expects you to tell it what you need.
$collection = Mage::getModel("catalog/product")->getCollection();
$collection->addAttributeToFilter("brand", 114); // limit for brand
$collection->addAttributeToSelect("modellijn"); // * also works but is slow
foreach($collection as $product) {
$product->getModellijn(); // just as above
$product->getAttributeText('modellijn');
}
Let me know if that does it for you. If it doesn't, please amend your post above to include a more complete SQL statement, and if possible more information about where you are using this data. That will help me understand the context within which you're executing the code.