I have the following functions to create a global product attribute and populate it with terms based on data from an API.
protected function getOrCreateAttribute($slug, $name)
{
$taxonomyId = wc_attribute_taxonomy_id_by_name($slug);
if (!empty($taxonomyId) && $taxonomyId > 0) {
return $taxonomyId;
}
$taxonomyId = wc_create_attribute([
'name' => $name,
'slug' => $slug,
'type' => 'select',
]);
if ($taxonomyId instanceof \WP_Error) {
throw new Exception($taxonomyId->get_error_message());
}
return $taxonomyId;
}
protected function getOrCreateTerm($slug, $name, $taxonomySlug)
{
$term = get_term_by('slug', $slug, $taxonomySlug);
if ($term === false) {
clean_taxonomy_cache($taxonomySlug);
/** @var \WP_Term|\WP_Error $term */
$term = wp_insert_term($name, $taxonomySlug, ['slug' => $slug]);
clean_term_cache($term->term_id, $taxonomySlug);
}
if ($term instanceof \WP_Error) {
throw new Exception($term->get_error_message());
}
return $term;
}
Now in my data processing loop I'm trying this way to create an attribute if it doesn't exist, and the same for each term in that attribute.
Finally I'm trying to add them to the product.
foreach ($featuresGroup->Features as $feature) {
$taxonomyName = $feature->Feature->Name->Value;
$taxonomySlug = $this->slugger->slugify($taxonomyName);
$taxonomyId = $this->getOrCreateAttribute($taxonomySlug, $taxonomyName);
$attribute = wc_get_attribute($taxonomyId);
$termsToSet = [];
$termName = $feature->PresentationValue;
$termSlug = $this->slugger->slugify($termName);
$term = $this->getOrCreateTerm($termSlug, $termName, $attribute->slug);
$termsToSet[] = $term->term_id;
if (array_key_exists($attribute->slug, $productAttributes)) {
$productAttribute = &$productAttributes[$attribute->slug];
$productAttribute->set_options($termsToSet);
} else {
$wcProductAttribute = new \WC_Product_Attribute();
$wcProductAttribute->set_name($attribute->name);
$wcProductAttribute->set_id($attribute->id);
$wcProductAttribute->set_visible(1);
$wcProductAttribute->set_options($termsToSet);
$productAttributes[$attribute->slug] = $wcProductAttribute;
}
}
Now my problem here is that I have to run the same piece of code multiple times to actually get a result and I'm not sure why. Normally on the first run I'm encountering an error
Invalid taxonomy
During the wp_insert_term
execution which instead of creating the WP_Term
produces a WP_Error
However if I run it multiple times, everything eventually gets generated.
I'm not sure what's going on here.
I've tried clearing the caches for terms and taxonomies in case it was failing due to cache, to no avail.
Let me add some info for example the $attribute
variable before getOrCreateTerm
function call
And the result of taxonomy_exists
shows false during wp_insert_term
even though it was clearly defined before and has an ID
I have the following functions to create a global product attribute and populate it with terms based on data from an API.
protected function getOrCreateAttribute($slug, $name)
{
$taxonomyId = wc_attribute_taxonomy_id_by_name($slug);
if (!empty($taxonomyId) && $taxonomyId > 0) {
return $taxonomyId;
}
$taxonomyId = wc_create_attribute([
'name' => $name,
'slug' => $slug,
'type' => 'select',
]);
if ($taxonomyId instanceof \WP_Error) {
throw new Exception($taxonomyId->get_error_message());
}
return $taxonomyId;
}
protected function getOrCreateTerm($slug, $name, $taxonomySlug)
{
$term = get_term_by('slug', $slug, $taxonomySlug);
if ($term === false) {
clean_taxonomy_cache($taxonomySlug);
/** @var \WP_Term|\WP_Error $term */
$term = wp_insert_term($name, $taxonomySlug, ['slug' => $slug]);
clean_term_cache($term->term_id, $taxonomySlug);
}
if ($term instanceof \WP_Error) {
throw new Exception($term->get_error_message());
}
return $term;
}
Now in my data processing loop I'm trying this way to create an attribute if it doesn't exist, and the same for each term in that attribute.
Finally I'm trying to add them to the product.
foreach ($featuresGroup->Features as $feature) {
$taxonomyName = $feature->Feature->Name->Value;
$taxonomySlug = $this->slugger->slugify($taxonomyName);
$taxonomyId = $this->getOrCreateAttribute($taxonomySlug, $taxonomyName);
$attribute = wc_get_attribute($taxonomyId);
$termsToSet = [];
$termName = $feature->PresentationValue;
$termSlug = $this->slugger->slugify($termName);
$term = $this->getOrCreateTerm($termSlug, $termName, $attribute->slug);
$termsToSet[] = $term->term_id;
if (array_key_exists($attribute->slug, $productAttributes)) {
$productAttribute = &$productAttributes[$attribute->slug];
$productAttribute->set_options($termsToSet);
} else {
$wcProductAttribute = new \WC_Product_Attribute();
$wcProductAttribute->set_name($attribute->name);
$wcProductAttribute->set_id($attribute->id);
$wcProductAttribute->set_visible(1);
$wcProductAttribute->set_options($termsToSet);
$productAttributes[$attribute->slug] = $wcProductAttribute;
}
}
Now my problem here is that I have to run the same piece of code multiple times to actually get a result and I'm not sure why. Normally on the first run I'm encountering an error
Invalid taxonomy
During the wp_insert_term
execution which instead of creating the WP_Term
produces a WP_Error
However if I run it multiple times, everything eventually gets generated.
I'm not sure what's going on here.
I've tried clearing the caches for terms and taxonomies in case it was failing due to cache, to no avail.
Let me add some info for example the $attribute
variable before getOrCreateTerm
function call
And the result of taxonomy_exists
shows false during wp_insert_term
even though it was clearly defined before and has an ID
In the end I added a quick check with
taxonomy_exists($slug)
and if it doesn't exist before adding the terms I use
register_taxonomy($taxonomySlug, 'product')
This seems to have allowed creation of all terms in one go.