Woocommerce: Argumento no válido suministrado para foreach() en el archivo class-wc-product-variable.php

6 minutos de lectura

avatar de usuario
Jesús Magallón

Estoy creando un tipo de producto variable personalizado para mi tema, he logrado que aparezca en el desplegable de datos del producto y eso se puede guardar sin causar conflicto. El problema es que al ver el producto en frontend me da el siguiente error:

Advertencia: Argumento no válido proporcionado para foreach() en
/Aplicaciones/MAMP/htdocs/canopy/wp-content/plugins/Woocommerce/includes/class-wc-product-variable.php
en la línea 83

He rastreado el problema hasta el archivo. WordPress/includes/data-stores/class-wc-product-variable-data-store-cpt.php pero la verdad es que ya no se que mas hacer.

Dejo el código que escribí para esto:

WC_Producto_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';
    }
}

clase-woocommerce-producto-personalizado.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;
    }
}

funciones.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') );

Espero que alguien pueda ayudarme a entender lo que sucede 🙁

¡Gracias!

  • ¿No tienes precios para este tipo de producto personalizado?

    – Subcontratar WordPress

    10 de octubre de 2018 a las 9:06

  • Si, los he configurado y sigue saliendo el mismo error

    – Jesús Magallón

    10 oct 2018 a las 15:49

  • ¿Está anulando algún archivo de plantilla de WooCommerce en su tema? ¿Puedes cambiar al tema predeterminado de WordPress y comprobar que sigue apareciendo el mismo error?

    – Subcontratar WordPress

    10 oct 2018 a las 16:14

avatar de usuario
Sally C.J.

El problema

Recibiste esa advertencia porque el read_price_data() el método es (al momento de escribir) solamente disponible en el WC_Product_Variable_Data_Store_CPT clase y no la predeterminada que se usa para el tipo de producto personalizado, que es WC_Product_Data_Store_CPT.

Sin embargo, a pesar de que la clase predeterminada no tiene la read_price_data() método, llamarlo desde la instancia de la clase no da como resultado una excepción/error porque esa clase se instancia a través del WC_Data_Store clase, que tiene el método mágico __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

Pero desde el read_price_data() Se espera que el método devuelva un array y sin embargo no (o que vuelve null), es por eso que PHP lanza el “Invalid argument supplied for foreach() …” advertencia:

// The following code throws a warning.
foreach ( null as $key => $value ) {
    ...
}

La solución

Necesitas utilizar el almacén de datos adecuado clase para su tipo de producto personalizado (variable).

Es decir, agregar un elemento a la WC_Data_Store::$stores arraydonde la clave es el tipo de producto (variable) con el prefijo product- (así que en tu caso, sería product-variable_canopytour), y el valor es el class que maneja el almacén de datos (por ejemplo, WC_Product_Variable_Data_Store_CPT como en el siguiente ejemplo).

Puede hacerlo a través de la woocommerce_data_stores filtrar, así: (agregar al tema activo functions.php expediente)

add_filter( 'woocommerce_data_stores', function( $stores ){
    $stores['product-variable_canopytour'] = 'WC_Product_Variable_Data_Store_CPT';
    return $stores;
} );

Nota adicional

El constructor para WC_Product_Variable_CanopyTour debe definirse la mismo camino el padre class lo define, donde el $product es opcional y que por defecto es cero (0), al igual que:

class WC_Product_Variable_CanopyTour extends WC_Product_Variable {
    public function __construct( $product = 0 ) {
        $this->product_type="variable_canopytour";
        parent::__construct( $product );
    }

    ...
}

  • PD: en el functions.php archivo, tienes add_action( 'admin_head', array($woo_ct, 'wcb_admin_head') );pero no veo un método llamado wcb_admin_head definido en el WCB_Woocommerce_CanopyTour_Product_Type clase. Querías decir add_action( 'admin_footer', array($woo_ct, 'wcb_admin_footer') );?

    – Sally C.J.

    10 de octubre de 2018 a las 4:59

  • Wow, muchas gracias! Era justo esto lo que me necesitaba. Solo necesito saber cómo agregar la plantilla a mi tipo de producto personalizado. Ahora, sobre tu comentario de “admin_head”, me equivoque al copiar, lo que pasa es que solo pasan las funciones que hacían referencia al tipo de producto “variable_canopytour”. Espero que no haya sido un problema, saludos!

    – Jesús Magallón

    10 oct 2018 a las 16:19

  • De nada @JesúsMagallón. Actualicé la respuesta y espero que sea más útil. 😉 Por favor, hágamelo saber si necesita más ayuda.

    – Sally C.J.

    11 oct 2018 a las 11:32

  • Respuesta increíblemente reflexiva y útil. Gracias @SallyCJ… A riesgo de agregar más ruido pedante sin sentido a Internet, ¿no podría simplemente configurar la propiedad product_type directamente en la clase y deshacerse del constructor por completo? public $product_type = 'variable_canopytour'

    –Kerry Randolph

    17 mayo 2019 a las 19:19


  • Sí, de hecho, @KerryRandolph. 🙂 Pero ya sabes, yo estaba más centrado en el foreach error en ese entonces y me perdí esa parte que has señalado. :pags

    – Sally C.J.

    17 mayo 2019 a las 19:52

El error se origina en aquí. Lo que simplemente te dice es que el $prices variable utilizada en el foreach loop no es de un tipo sobre el que pueda iterar. Los precios se obtienen usando

$prices = $this->data_store->read_price_data( $this, $for_display );

Entonces, lo que sea que se devuelva de eso read_price_data llamada no es lo que el resto de los códigos esperan que sea. No estoy seguro exactamente de cómo funciona este sistema y qué se necesita cuando se extiende WC_Product_Variable etc. y no puedo configurar un sistema para depurarlo. Pero si rastrea la pila de llamadas hacia atrás desde este punto hacia atrás, es probable que descubra por qué esta función devuelve estos datos inesperados.

La intuición dice que podría ser una parte importante que olvidaste agregar cuando extendiste la clase o algo similar.

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad