skip to Main Content

Add WooCommerce product attribute without losing existings doesn’t solve my problem because I’d create an array manually containing all existing attributes, and it’s not general as I want and seems to be a bad practice. Given a product with X attributes with X values for those ones I’d like to add a new attribute with a value to this product, below is my attempt:

$modelagem = "desconhecida"; // new attribute value
$attribute_pa_at_modelagem_id = wc_attribute_taxonomy_id_by_name('at-modelagem'); // new attribute, already registered in wordpress NOT IN THE PRODUCT
$modelagem_attribute = new WC_Product_Attribute(); // new attribute object
$modelagem_attribute->set_id($attribute_pa_at_modelagem_id); // setting attribute configs
$modelagem_attribute->set_name('pa_at-modelagem'); // setting attribute configs
$modelagem_attribute->set_options([$modelagem]); // setting attribute configs
$modelagem_attribute->set_visible(true); // setting attribute configs
$modelagem_attribute->set_variation(false); // setting attribute configs
$modelagem_attribute->set_position(0); // setting attribute configs
$existing_attributes = $product->get_attributes(); // taking existing attributes (IT'S EMPTY I DONT KNOW WHY)
$existing_attributes[] = $modelagem_attribute; // then appending new attribute to it

$product->set_attributes($existing_attributes); // IT ERASES ALL ATTRIBUTES
$product->save();

As I stated the code above erase all attributes and variations for the given product regardless that I need a way to just set a new attribute with its value without setting again all of its attributes at once, it’s a bad practice and can bug variations.

PS: Please ignore trivial problems, WooCommerce not loaded, plugins conflict etc…

2

Answers


  1. You can use the following custom function to add a pre-existing attribute and term ID(s) to a product (caution as it doesn’t work with term slugs):

    function set_pre_existing_attribute_to_product( $product, $attribute_name, $term_ids, $for_variations = false, $visible = true, $position = 0 ) {
        $taxonomy  = wc_attribute_taxonomy_name($attribute_name); // new attribute, already registered in wordpress
    
        $attribute = new WC_Product_Attribute(); // new attribute object
        $attribute->set_id( wc_attribute_taxonomy_id_by_name( $attribute_name ) ); // setting attribute configs
        $attribute->set_name($taxonomy); 
        $attribute->set_options($term_ids);
        $attribute->set_variation($for_variations); 
        $attribute->set_visible($visible); 
        $attribute->set_position($position);
    
        $attributes = (array) $product->get_attributes(); // Get existing attributes set in the product
    
        $product->set_attributes( array_merge( $attributes, array($taxonomy => $attribute) ) );
        $product->save();
    }
    

    Code goes in functions.php file of your child theme (or in a plugin). Tested and works.

    Note: It will keep other existing attributes set in the product

    Usage examples: from a defined WC_Product Object and pre-existing attribute:

    • With your "at-modelagem" attribute (not for variations | caution: replace "desconhecida" slug with the corresponding term ID)

      set_pre_existing_attribute_to_product( $product, 'at-modelagem', [34] );
      
    • With "Color" attribute (not for variations):

      set_pre_existing_attribute_to_product( $product, 'Color', [26] );
      
    • With "Color" attribute (for variations on a variable product):

      set_pre_existing_attribute_to_product( $product, 'Color', [24, 25, 26], true, false );
      
    Login or Signup to reply.
  2. Product Attributes are stored as a serialized array in wp_postmeta. Despite your desire to not setting all of the existing values again, merging your new value with the existing and setting is the correct way to do this.

    One of the issues I see with your code was that you were trying to use the output of WP_Product::get_attributes as-is. You need to iterate down and access the individual objects and push those onto your $existing_attributes array.

    $product_attributes = $product->get_attributes();
    
    foreach ($product_attributes as $attribute_name => $attribute_object) {
        $existing_attributes[] = $attribute_object;
    }
    
    $modelagem = "desconhecida"; // new attribute value
    $attribute_pa_at_modelagem_id = wc_attribute_taxonomy_id_by_name('at-modelagem'); // new attribute, already registered in wordpress NOT IN THE PRODUCT
    $modelagem_attribute = new WC_Product_Attribute(); // new attribute object
    $modelagem_attribute->set_id($attribute_pa_at_modelagem_id); // setting attribute configs
    $modelagem_attribute->set_name('pa_at-modelagem'); // setting attribute configs
    $modelagem_attribute->set_options([$modelagem]); // setting attribute configs
    $modelagem_attribute->set_visible(true); // setting attribute configs
    $modelagem_attribute->set_variation(false); // setting attribute configs
    $modelagem_attribute->set_position(0); // setting attribute configs
    
    $existing_attributes[] = $modelagem_attribute; // then appending new attribute to it
    
    $product->set_attributes($set_attributes);
    $product->save();
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search