I'm creating a type of variable product customized for my theme, I've managed to appear in the dropdown of product data and that can be saved without causing conflict. The problem is that seeing the product in frontend gives me the following error:
Warning: Invalid argument supplied for foreach() in /Applications/MAMP/htdocs/canopy/wp-content/plugins/Woocommerce/includes/class-wc-product-variable.php on line 83
I have traced the problem to the file Wordpress/includes/data-stores/class-wc-product-variable-data-store-cpt.php
but the truth is that I do not know what else to do.
I leave the code that I wrote for this:
WC_Product_variable_canopytour.php
class WC_Product_Variable_CanopyTour extends WC_Product_Variable {
public function __construct( $product ) {
$this->product_type = 'variable_canopytour';
parent::__construct( $product );
}
public function get_type() {
return 'variable_canopytour';
}
}
class-woocommerce-custom-product.php
class WCB_Woocommerce_CanopyTour_Product_Type {
private $wcb;
private $version;
public function __construct( $wcb, $version ) {
$this->wcb = $wcb;
$this->version = $version;
}
public function register_canopytour_product_type() {
remove_action( 'woocommerce_single_product_summary', 'woocommerce_template_single_price', 10 );
include_once(get_template_directory() . 'woocommerce/WC_Product_variable_canopytour.php');
}
public function add_canopytour_product( $types ) {
$types[ 'variable_canopytour' ] = __( 'Variable Canopy Tour', $this->wcb );
return $types;
}
public function get_tour_product_class($classname, $product_type) {
if ( $product_type === "variable_canopytour" ) {
$classname = 'WC_Product_Variable_CanopyTour';
}
return $classname;
}
public function wcb_admin_footer() {
if ( 'product' != get_post_type() ) :
return;
endif;
?><script type='text/javascript'>
jQuery( document ).ready( function() {
jQuery( '.options_group.pricing' ).addClass( 'show_if_variable_canopytour show_if_simple show_if_external' ).show();
jQuery( 'li.general_options.general_tab' ).addClass( 'show_if_variable_canopytour show_if_simple show_if_external' ).show();
jQuery( '.variations_options.variations_tab' ).addClass( 'show_if_variable_canopytour' ).show();
jQuery( '.enable_variation' ).addClass( 'show_if_variable_canopytour' ).show();
});
</script><?php
}
function hide_wcb_data_panel( $tabs) {
// Other default values for 'attribute' are; general, inventory, shipping, linked_product, variations, advanced
$tabs['shipping']['class'][] = 'hide_if_variable_canopytour';
return $tabs;
}
}
functions.php
include_once get_template_directory() . 'includes/woocommerce/class-woocommerce-custom-product.php';
$woo_ct = new WCB_Woocommerce_CanopyTour_Product_Type( "wcb", "1.0" );
add_action( 'init', array($woo_ct, 'register_canopytour_product_type') );
add_filter( 'product_type_selector', array($woo_ct, 'add_canopytour_product') );
add_filter( 'woocommerce_product_class', array($woo_ct, 'get_tour_product_class'), 10, 2 );
add_action( 'admin_head', array($woo_ct, 'wcb_admin_head') );
add_filter( 'woocommerce_product_data_tabs', array($woo_ct, 'hide_wcb_data_panel') );
I hope someone can help me understand what happens :(
Thank you!
You got that warning because the read_price_data()
method is (as of writing) only available in the WC_Product_Variable_Data_Store_CPT
class and not the default one that's used for custom product type, which is WC_Product_Data_Store_CPT
.
However, despite the default class doesn't have the read_price_data()
method, calling it from the class's instance doesn't result in an exception/error because that class is instantiated through the WC_Data_Store
class, which has the magic method __call()
.
// Case 1: In WC_Product_Variable::get_variation_prices().
// $this->data_store is an instance of WC_Product_Variable_Data_Store_CPT
$prices = $this->data_store->read_price_data( $this, $for_display ); // array
// Case 2: In WC_Product_Variable_CanopyTour::get_variation_prices().
// $this->data_store is an instance of WC_Product_Data_Store_CPT
$prices = $this->data_store->read_price_data( $this, $for_display ); // null
But since the read_price_data()
method is expected to return an array
and yet it doesn't (or that it returns null
), that's why PHP throws the "Invalid argument supplied for foreach() ..." warning:
// The following code throws a warning.
foreach ( null as $key => $value ) {
...
}
You need to use the proper data store class for your custom (variable) product type.
I.e. Add an item to the WC_Data_Store::$stores
array
, where the key is the (variable) product type prefixed with product-
(so in your case, it would be product-variable_canopytour
), and the value is the class
that handles the data store (e.g. WC_Product_Variable_Data_Store_CPT
as in the below example).
You can do so via the woocommerce_data_stores
filter, like so: (add to the active theme's functions.php
file)
add_filter( 'woocommerce_data_stores', function( $stores ){
$stores['product-variable_canopytour'] = 'WC_Product_Variable_Data_Store_CPT';
return $stores;
} );
The constructor for WC_Product_Variable_CanopyTour
should be defined the same way the parent class
defines it, where the $product
is optional and that it defaults to zero (0
), like so:
class WC_Product_Variable_CanopyTour extends WC_Product_Variable {
public function __construct( $product = 0 ) {
$this->product_type = 'variable_canopytour';
parent::__construct( $product );
}
...
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With