Commit f38159076e for woocommerce
commit f38159076e4558e5bc523118e12c9462c255ff0a
Author: Ninos Ego <me@ninosego.de>
Date: Fri Jan 30 09:15:23 2026 +0100
Filter for modifying product attributes/downloads before reading & additional `extra_data` option (#62572)
diff --git a/plugins/woocommerce/changelog/PR-62572 b/plugins/woocommerce/changelog/PR-62572
new file mode 100644
index 0000000000..fc308d8106
--- /dev/null
+++ b/plugins/woocommerce/changelog/PR-62572
@@ -0,0 +1,4 @@
+Significance: minor
+Type: enhancement
+
+Add filter for modifying product attributes/downloads before reading & additional `extra_data` option
diff --git a/plugins/woocommerce/includes/class-wc-product-attribute.php b/plugins/woocommerce/includes/class-wc-product-attribute.php
index 3af608af8a..53e44f43a2 100644
--- a/plugins/woocommerce/includes/class-wc-product-attribute.php
+++ b/plugins/woocommerce/includes/class-wc-product-attribute.php
@@ -32,6 +32,14 @@ class WC_Product_Attribute implements ArrayAccess {
'variation' => false,
);
+ /**
+ * Extra data array.
+ *
+ * @since 10.6.0
+ * @var array
+ */
+ protected $extra_data = array();
+
/**
* Return if this attribute is a taxonomy.
*
@@ -124,6 +132,7 @@ class WC_Product_Attribute implements ArrayAccess {
*/
public function get_data() {
return array_merge(
+ $this->extra_data,
$this->data,
array(
'is_visible' => $this->get_visible() ? 1 : 0,
@@ -140,6 +149,17 @@ class WC_Product_Attribute implements ArrayAccess {
|--------------------------------------------------------------------------
*/
+ /**
+ * Set extra data by key.
+ *
+ * @since 10.6.0
+ * @param string $key Extra data key.
+ * @param mixed $value Extra data value.
+ */
+ public function set_extra_data( string $key, $value ): void {
+ $this->extra_data[ $key ] = $value;
+ }
+
/**
* Set ID (this is the attribute ID).
*
@@ -200,6 +220,27 @@ class WC_Product_Attribute implements ArrayAccess {
|--------------------------------------------------------------------------
*/
+ /**
+ * Get all extra data.
+ *
+ * @since 10.6.0
+ * @return array
+ */
+ public function get_all_extra_data() {
+ return $this->extra_data;
+ }
+
+ /**
+ * Get extra data by key.
+ *
+ * @since 10.6.0
+ * @param string $key Extra data key.
+ * @return mixed
+ */
+ public function get_extra_data( string $key ) {
+ return $this->extra_data[ $key ] ?? null;
+ }
+
/**
* Get the ID.
*
@@ -281,6 +322,9 @@ class WC_Product_Attribute implements ArrayAccess {
if ( is_callable( array( $this, "get_$offset" ) ) ) {
return $this->{"get_$offset"}();
}
+ if ( isset( $this->extra_data[ $offset ] ) ) {
+ return $this->extra_data[ $offset ];
+ }
break;
}
return '';
@@ -307,7 +351,9 @@ class WC_Product_Attribute implements ArrayAccess {
default:
if ( is_callable( array( $this, "set_$offset" ) ) ) {
$this->{"set_$offset"}( $value );
+ break;
}
+ $this->extra_data[ $offset ] = $value;
break;
}
}
@@ -328,6 +374,6 @@ class WC_Product_Attribute implements ArrayAccess {
*/
#[\ReturnTypeWillChange]
public function offsetExists( $offset ) {
- return in_array( $offset, array_merge( array( 'is_variation', 'is_visible', 'is_taxonomy', 'value' ), array_keys( $this->data ) ), true );
+ return in_array( $offset, array_merge( array( 'is_variation', 'is_visible', 'is_taxonomy', 'value' ), array_keys( $this->data ), array_keys( $this->extra_data ) ), true );
}
}
diff --git a/plugins/woocommerce/includes/class-wc-product-download.php b/plugins/woocommerce/includes/class-wc-product-download.php
index 261c727015..6f52ff7aff 100644
--- a/plugins/woocommerce/includes/class-wc-product-download.php
+++ b/plugins/woocommerce/includes/class-wc-product-download.php
@@ -31,13 +31,21 @@ class WC_Product_Download implements ArrayAccess {
'enabled' => true,
);
+ /**
+ * Extra data array.
+ *
+ * @since 10.6.0
+ * @var array
+ */
+ protected $extra_data = array();
+
/**
* Returns all data for this object.
*
* @return array
*/
public function get_data() {
- return $this->data;
+ return array_merge( $this->extra_data, $this->data );
}
/**
@@ -267,6 +275,17 @@ class WC_Product_Download implements ArrayAccess {
|--------------------------------------------------------------------------
*/
+ /**
+ * Set extra data by key.
+ *
+ * @since 10.6.0
+ * @param string $key Extra data key.
+ * @param mixed $value Extra data value.
+ */
+ public function set_extra_data( string $key, $value ): void {
+ $this->extra_data[ $key ] = $value;
+ }
+
/**
* Set ID.
*
@@ -332,6 +351,27 @@ class WC_Product_Download implements ArrayAccess {
|--------------------------------------------------------------------------
*/
+ /**
+ * Get all extra data.
+ *
+ * @since 10.6.0
+ * @return array
+ */
+ public function get_all_extra_data() {
+ return $this->extra_data;
+ }
+
+ /**
+ * Get extra data by key.
+ *
+ * @since 10.6.0
+ * @param string $key Extra data key.
+ * @return mixed
+ */
+ public function get_extra_data( string $key ) {
+ return $this->extra_data[ $key ] ?? null;
+ }
+
/**
* Get id.
*
@@ -398,6 +438,9 @@ class WC_Product_Download implements ArrayAccess {
if ( is_callable( array( $this, "get_$offset" ) ) ) {
return $this->{"get_$offset"}();
}
+ if ( isset( $this->extra_data[ $offset ] ) ) {
+ return $this->extra_data[ $offset ];
+ }
break;
}
return '';
@@ -415,7 +458,9 @@ class WC_Product_Download implements ArrayAccess {
default:
if ( is_callable( array( $this, "set_$offset" ) ) ) {
$this->{"set_$offset"}( $value );
+ break;
}
+ $this->extra_data[ $offset ] = $value;
break;
}
}
@@ -436,6 +481,6 @@ class WC_Product_Download implements ArrayAccess {
*/
#[\ReturnTypeWillChange]
public function offsetExists( $offset ) {
- return in_array( $offset, array_keys( $this->data ), true );
+ return in_array( $offset, array_merge( array_keys( $this->data ), array_keys( $this->extra_data ) ), true );
}
}
diff --git a/plugins/woocommerce/includes/data-stores/class-wc-product-data-store-cpt.php b/plugins/woocommerce/includes/data-stores/class-wc-product-data-store-cpt.php
index bc15fb8cb0..ce700d632d 100644
--- a/plugins/woocommerce/includes/data-stores/class-wc-product-data-store-cpt.php
+++ b/plugins/woocommerce/includes/data-stores/class-wc-product-data-store-cpt.php
@@ -622,7 +622,17 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
$attribute->set_position( $meta_value['position'] );
$attribute->set_visible( $meta_value['is_visible'] );
$attribute->set_variation( $meta_value['is_variation'] );
- $attributes[] = $attribute;
+
+ /**
+ * Filter product attribute after initialization.
+ *
+ * @since 10.6.0
+ *
+ * @param WC_Product_Attribute $attribute The attribute object.
+ * @param array $meta_value The meta value.
+ * @param WC_Product $product The product object.
+ */
+ $attributes[] = apply_filters( 'woocommerce_product_read_attribute', $attribute, $meta_value, $product );
}
$product->set_attributes( $attributes );
}
@@ -639,15 +649,35 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
if ( $meta_values ) {
$downloads = array();
- foreach ( $meta_values as $key => $value ) {
- if ( ! isset( $value['name'], $value['file'] ) ) {
+ foreach ( $meta_values as $key => $meta_value ) {
+ if ( ! isset( $meta_value['name'], $meta_value['file'] ) ) {
continue;
}
$download = new WC_Product_Download();
$download->set_id( $key );
- $download->set_name( $value['name'] ? $value['name'] : wc_get_filename_from_url( $value['file'] ) );
- $download->set_file( apply_filters( 'woocommerce_file_download_path', $value['file'], $product, $key ) );
- $downloads[] = $download;
+ $download->set_name( $meta_value['name'] ? $meta_value['name'] : wc_get_filename_from_url( $meta_value['file'] ) );
+
+ /**
+ * Filter for the path of the downloadable file.
+ *
+ * @since 2.1.0
+ *
+ * @param string $file The file path.
+ * @param WC_Product $product The product object.
+ * @param string $key The download key.
+ */
+ $download->set_file( apply_filters( 'woocommerce_file_download_path', $meta_value['file'], $product, $key ) );
+
+ /**
+ * Filter product download after initialization.
+ *
+ * @since 10.6.0
+ *
+ * @param WC_Product_Download $download The attribute object.
+ * @param array $meta_value The meta value.
+ * @param WC_Product $product The product object.
+ */
+ $downloads[] = apply_filters( 'woocommerce_product_read_download', $download, $meta_value, $product );
}
$product->set_downloads( $downloads );
}
@@ -1011,13 +1041,16 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
}
// Store in format WC uses in meta.
- $meta_values[ $attribute_key ] = array(
- 'name' => $attribute->get_name(),
- 'value' => $value,
- 'position' => $attribute->get_position(),
- 'is_visible' => $attribute->get_visible() ? 1 : 0,
- 'is_variation' => $attribute->get_variation() ? 1 : 0,
- 'is_taxonomy' => $attribute->is_taxonomy() ? 1 : 0,
+ $meta_values[ $attribute_key ] = array_merge(
+ $attribute->get_all_extra_data(),
+ array(
+ 'name' => $attribute->get_name(),
+ 'value' => $value,
+ 'position' => $attribute->get_position(),
+ 'is_visible' => $attribute->get_visible() ? 1 : 0,
+ 'is_variation' => $attribute->get_variation() ? 1 : 0,
+ 'is_taxonomy' => $attribute->is_taxonomy() ? 1 : 0,
+ ),
);
}
}
diff --git a/plugins/woocommerce/includes/data-stores/class-wc-product-variable-data-store-cpt.php b/plugins/woocommerce/includes/data-stores/class-wc-product-variable-data-store-cpt.php
index 3f88f99949..23b5bebcef 100644
--- a/plugins/woocommerce/includes/data-stores/class-wc-product-variable-data-store-cpt.php
+++ b/plugins/woocommerce/includes/data-stores/class-wc-product-variable-data-store-cpt.php
@@ -88,7 +88,17 @@ class WC_Product_Variable_Data_Store_CPT extends WC_Product_Data_Store_CPT imple
$attribute->set_position( $meta_value['position'] );
$attribute->set_visible( $meta_value['is_visible'] );
$attribute->set_variation( $meta_value['is_variation'] );
- $attributes[] = $attribute;
+
+ /**
+ * Filter product attribute after initialization.
+ *
+ * @since 10.6.0
+ *
+ * @param WC_Product_Attribute $attribute The attribute object.
+ * @param array $meta_value The meta value.
+ * @param WC_Product $product The product object.
+ */
+ $attributes[] = apply_filters( 'woocommerce_product_read_attribute', $attribute, $meta_value, $product );
}
$product->set_attributes( $attributes );
diff --git a/plugins/woocommerce/includes/import/abstract-wc-product-importer.php b/plugins/woocommerce/includes/import/abstract-wc-product-importer.php
index c0192a040d..aa1d3cefac 100644
--- a/plugins/woocommerce/includes/import/abstract-wc-product-importer.php
+++ b/plugins/woocommerce/includes/import/abstract-wc-product-importer.php
@@ -414,7 +414,17 @@ abstract class WC_Product_Importer implements WC_Importer_Interface {
$attribute_object->set_position( $position );
$attribute_object->set_visible( $is_visible );
$attribute_object->set_variation( $is_variation );
- $attributes[] = $attribute_object;
+
+ /**
+ * Filter product attribute after initialization.
+ *
+ * @since 10.6.0
+ *
+ * @param WC_Product_Attribute $attribute_object The attribute object.
+ * @param array $attribute The attribute data.
+ * @param WC_Product $product The product object.
+ */
+ $attributes[] = apply_filters( 'woocommerce_product_importer_read_attribute', $attribute_object, $attribute, $product );
}
} elseif ( isset( $attribute['value'] ) ) {
// Check for default attributes and set "is_variation".
@@ -429,7 +439,9 @@ abstract class WC_Product_Importer implements WC_Importer_Interface {
$attribute_object->set_position( $position );
$attribute_object->set_visible( $is_visible );
$attribute_object->set_variation( $is_variation );
- $attributes[] = $attribute_object;
+
+ // phpcs:ignore WooCommerce.Commenting.CommentHooks.MissingHookComment -- see same filter in the 'if' block.
+ $attributes[] = apply_filters( 'woocommerce_product_importer_read_attribute', $attribute_object, $attribute, $product );
}
}