• Hi All,

    we have a PHP procedure that automatically imports (through a CRON process every night) all products from a CSV file to our Woocommerce.

    The problem is that, when setting subcategories, if there are 2 (or more) of them with the same name, under DIFFERENT parent categories, it automatically gives the product the first one found.

    For example, I want to get this:

    Medals
    |-> Silver
    |--> Large
    |--> Small
    |-> Gold
    |--> Large
    |--> Small

    So, under the parent category “Medals”, there are 2 different subcategories “Silver” and “Gold”. They both have another depth level of subcategories with the same NAME.

    Instead, when importing, I get this:

    Medals
    |-> Silver
    |-> Gold
    |--> Large
    |--> Small

    So every Silver medal takes “Large” or “Small” subcategory under the “Gold” tree (instead of “Silver” tree) since Gold is the first one found in the CSV and so the first to create “Large” and “Small” subcategories.

    It’s like WordPress says “Hey, there’s already a Large subcategory existing, I’m going to put all your products there” ignoring the fact that the parent category is “Silver” instead of “Gold”.

    The code creating categories from the CSV is:

    $cat = sanitize_text_field($data[2]);
    $cat = strtolower($cat);
    $cat2 = sanitize_text_field($data[3]);
    $cat2 = strtolower($cat2);
    $cat3 = sanitize_text_field($data[4]);
    $cat3 = strtolower($cat3);
    wp_set_object_terms($post_id, $cat, ‘product_cat’);
    wp_set_object_terms($post_id, $cat2, ‘product_cat’, $append = true ) ;
    wp_set_object_terms($post_id, $cat3, ‘product_cat’, $append = true ) ;

    where $data is an array of values of the CSV file (every row in the CSV is a single product, in this case, a medal).

    Sorry for the wall of text but I’ve tried a lot and cannot figure this out.
    If I wasn’t clear explaining this, go ahead and tell me!

    Thanks in advance. Would be really grateful if you have any ideas.

    • This topic was modified 4 years, 10 months ago by bcworkz.
    • This topic was modified 4 years, 10 months ago by Jan Dembowski. Reason: Moved to Fixing WordPress, this is not an Developing with WordPress topic
Viewing 15 replies - 1 through 15 (of 17 total)
  • Sorry, WooCommerce is not part of WordPress. For help with WooCommerce please visit their developer center here: https://docs.woocommerce.com

    Moderator bcworkz

    (@bcworkz)

    We could talk about the more general case of assigning hierarchical terms to posts. How is your code supposed to know which parent term the child term belongs to? Is it reliably the $data array element before? For example, is the $data[3] term’s parent always $data[2]? What you ask is impossible without some definitive information on what a term’s parent should be.

    If the term’s parent can reliably be determined based on other CSV data, you need to first do a term query using the “parent” argument in order to get the correct term ID for the term being set and pass the ID instead of the term name when assigning it to the post object. However, doing such a query on every term in a large data import will significantly add to the overhead of the import.

    FYI, the forum’s parser does undesirable things to structured content like your |--> indents. It also corrupts code. To avoid this use the code button or demarcate such content with backticks. I added the backticks to your OP, however the code snippet remains corrupted because it is flawed from its source. The quotes are the “curly” kind instead of "straight" kind.

    Moderator Jan Dembowski

    (@jdembowski)

    Forum Moderator and Brute Squad

    Moved to Fixing WordPress, this is not an Developing with WordPress topic.

    Please ask plugin specific questions in that plugin’s dedicated sub-forum instead.

    https://www.ads-software.com/support/plugin/woocommerce/#new-post

    Thread Starter charlieadmino

    (@charlieadmino)

    @bcworkz

    Yes, $data[3] term’s parent IS ALWAYS $data[2]

    For example, $data[2] is “Medals”, $data[3] is “Silver” and $data[4] is “Large”
    otherwise, it would mess up categories and subcategories while creating the product.

    I don’t really know how to do such a query. The code is executed for every CSV because every row is a single product.

    Our server is powerful and kinda low on load atm so it may not be so demanding to do such a query.

    Thanks a lot for answering and for formatting my code.

    Moderator bcworkz

    (@bcworkz)

    You can use get_terms() with appropriate arguments to do a term query. It works similar to get_posts() if you are familiar with that. The docs page:
    https://developer.www.ads-software.com/reference/functions/get_terms/

    Because the “parent” argument requires an ID value, you would need to do two queries per product. It’d be a good idea to cache the results so the same queries do not need to be repeated for various products.

    Thread Starter charlieadmino

    (@charlieadmino)

    @bcworkz

    I tested and when importing again, the category ID is always the same, so I might try to make “if” conditions with a fixed ID just for medals categories.

    After searching a lot even today, I have changed the code in:

    
    $cat = sanitize_text_field($data[2]);
    $cat = strtolower($cat);
    $cat2 = sanitize_text_field($data[3]);
    $cat2 = strtolower($cat2);
    $cat3 = sanitize_text_field($data[4]);
    $cat3 = strtolower($cat3);
    wp_set_object_terms($post_id, $cat, ‘product_cat’);
    wp_set_object_terms($post_id, $cat2, ‘product_cat’, $append = true ) ;
    
    if ( has_term( 'medaglie', 'product_cat', $post_id ) ) {
    				if ( has_term( 'argento', 'product_cat', $post_id ) ) {
    					wp_set_object_terms($post_id, 589, 'product_cat', $append = true );
    				}
    				else {
    					wp_set_object_terms($post_id, $cat3, 'product_cat', $append = true );
    				}
    			}
    

    Where 589 is the ID of “Small” under “Silver”.
    I have to make more if conditions and even one to check where to give 589 or “Large” ID.

    Is it similar to what you were thinking about?

    I don’t think this is the best solution but it seems to work for “Silver”.
    I’m sorry if I’m missing out a lot and not able to understand. This whole thing gives me a lot of confusion.

    Thread Starter charlieadmino

    (@charlieadmino)

    I’m sorry. “medaglie” is “Medals” and “argento” is “Silver”.

    Moderator bcworkz

    (@bcworkz)

    Your usage is much more specific than what I had in mind, but the logic is essentially the same. If you know the specific parent categories are where all the possible child ambiguity could occur and they are not too extensive, then your specific approach is better than my general approach because fewer queries are required and the import will run much faster.

    The drawback is that it’s limited. If some other ambiguous term is introduced in the future, you’ll need to update your code. It’s not at all adaptable by itself.

    I would advise against using has_term() to check for the parent category because it involves another query and could create a race condition since the term was just set in the prior line. You can instead just check the value in $cat to see if it’s “medaglie” or not.

    I assume medals and silver are not the only ambiguities possible. You can imagine all the if/else conditionals could grow to become quite cumbersome and confusing. There’s a better way. Define a lookup table in the form of a multi-dimensional, nested array which your code can use to learn the right ID to use for any ambiguous child term. The array replicates the term hierarchy.
    One element of the array would be $lookup = ['medaglie' => ['argento' => ['piccolo' => 589,],],]

    Code can access that value with $lookup[$cat][$cat2][$cat3]
    Use array_key_exists() to determine if there’s an entry or not. If so, get the value from the entry. If not, use wp_set_object_terms() like you always have.

    If medals are the only term under which ambiguity can occur, you really don’t need to check for the ‘medaglie’ term, the existence of gold or silver terms is enough to tell us that it is under the ‘medaglie’ term.

    Thread Starter charlieadmino

    (@charlieadmino)

    @bcworkz

    well about the drawback, the client will notice me if there gonna be new categories, so no problem. I can’t find another solution for now.
    I’m sure I saw other posts around reporting this issue but they solved it in another way specific for their situation.

    Well, I tried to check $cat == “medaglie” in the past but it didn’t work, don’t really know why. Will try again. Maybe I’m missing a specific string checker function.

    Also, I check for “medaglie” because even other products may have “argento” or something like that so I want to be sure it is affecting only medals.

    About the multi-dimensional nested array…well, I’m not that skilled and I have multiple doubts about it. Will try to read multiple times and test if I’m able to use it.

    Thanks a lot for the kind help.

    Moderator bcworkz

    (@bcworkz)

    Heh, I wasn’t concerned with you adding categories, but with your client adding other categories in the future that could introduce new ambiguities ??

    If 'medaglie' == $cat doesn’t work as intended, maybe there is added whitespace preventing a proper equivalency check. Try $cat = trim( strtolower($cat)); to strip out unneeded whitespace.

    It sounds like these ambiguities are fairly limited. If constructing an array lookup table is beyond your skills, a set of if/elseif/else statements will work. But use of array structures is an important coding skill. I encourage you to make a concerted effort to get a lookup array working and to understand the result to grow your skill set.

    Maybe start small and create $oro and $argento arrays which only contain two elements each. Use in place of the innermost if/else to get term IDs. Then once you see how that works combine those two into one $medaglie array. If medals are the only source of ambiguity, you don’t need to go further with another dimension.

    Thread Starter charlieadmino

    (@charlieadmino)

    @bcworkz

    I mean that with every new category created, my client calls me. I explicitly asked them for that.

    After using those new lines of code in the test website, I decided to use them in the live one.

    But it seems my efforts are still useless. When testing I used a short CSV (for low import time) containing only medals.
    In the real website, I have all their actual products, and when importing, the category IDs are changed every time.

    So yeah, not even this code works.

    Also, well I studied arrays in the past and used them. But nothing like multi-dimensional + nested array. Probably too complex for me.

    But as reported here, been able to use that array won’t be of any help, since IDs change on every import.

    Moderator bcworkz

    (@bcworkz)

    I have clients like that too, and I don’t even insist. They do so anyway.

    So any particular “oro” term or whatever has a different term ID on every import? How does that happen? Are the old terms wiped out and a new taxonomic structure created on every import? The fact remains you don’t want to be querying for the proper term parent for every medal item. It would be good to somehow cache such data so it can be repeatedly used throughout the import without re-querying data. One good way to do so is with a structured array (gasp!). But do whatever makes sense to you to make that happen. It’s more important to do it than how to do it.

    FWIW, WP does have a built in caching scheme. I’ve never used it though. It just stores data in a big global array. But you may find it more accessible by using helper functions like wp_cache_set() and wp_cache_get() instead of directly accessing an array.

    Thread Starter charlieadmino

    (@charlieadmino)

    @bcworkz

    Yes, it seems that new taxonomic structure is created on every import.

    You know what? I saw that for example the category “Small” under “Bronze” has slug “small”, while for example “Small” under “Gold” has a “small-gold” slug.

    Is there a function to set product/post category knowing the category slug?

    I’m reading that “wp_set_object_terms” can have slug term, instead of using category ID.

    That may solve this issue but I don’t seem to find a function like that around.

    What do you think?

    Thread Starter charlieadmino

    (@charlieadmino)

    @bcworkz

    I’ll be damned…”It just works” -Todd Howard

    Ok for sure not the best solution but still better than having to set categories manually every morning.

    This time I tested in on the live site. Everything is fine.

    Now the only thing missing is that these medals have an Upload file customizer for printing your own image on it, and since categories are deleted and reinserted every night, I lose them in the specific configurator field on the admin panel…have to figure out how to automatically re-add them at the end of every import, but that’s a whole new thread.

    As for subcategories here, I cannot think of a better solution for now. Don’t really understand how cache will come in handy.

    Moderator bcworkz

    (@bcworkz)

    There’s a distinct term slug provided with every item!? That’s useful ??

    A cache or lookup array can reduce the queries required and make the import process faster and more efficient. It’s also an alternative way to access a complex array of data saved for short term use. If the import process doesn’t take that long and does not time out then there is little need to use a cache, though it remains an alternative way to access arrays.

    The ability to specify a distinct slug instead of needing to lookup its ancestors is in itself more efficient and faster. The best solution is having the term ID as part of the import data. Short of that, the distinct slug is as good as it will get.

    You’re right, relating images to terms is another topic. I’ll just say in parting that there has to be something about the file besides visual appearance that is common between a term and the image. For example, if the file name or its EXIF data matched in whole or in part the term slug, the process could be automated. Or if the image is related to a term through an associated product.

Viewing 15 replies - 1 through 15 (of 17 total)
  • The topic ‘Issue importing Woocommerce products with same name subcategory’ is closed to new replies.