Imágenes en WooCommerce

imágenes en woocommerce wordpress

Enlazar imágenes en WooCommerce es un proceso que no están intuitivo pero se puede hacer de manera muy efectiva.

Había una vez, un cliente que tenía un problema el viernes a las 8:00 a. m.

–Cliente: Sé que son las 8 de la mañana, en viernes, pero… tengo un problema, en mi sitio de eCommerce tengo más de 46 mil productos ya cargados, pero ninguno tiene imagen y a mi gente le llevaría meses entrar producto por producto y cargar la imagen, ¿puedes hacer algo para que sea más automático?

–Yo: Por supuesto que no sé, pero déjame investigar qué se puede hacer. ¿tienes algo que pueda ayudarme a empezar?

–Cliente: Solo tengo un Excel con el SKU de cada producto y una carpeta con las imágenes.

–Yo: Envíame eso y ya veré.

–Cliente: ¿Puedes tenerlo para hoy?

–Yo: No.

–Cliente: Bueno, te envío lo que tengo.

Ni las gracias.

¿Y ahora qué hago?

Así que empecé a investigar.

Lo primero que hice fue buscar en Google y por supuesto Stackoverflow y me dio norte sobre la solución, aunque me parecían demasiado rebuscadas.

Mejor me monté un docker con WordPress y WooCommerce, agregué algunos productos e hice un dump de la base de datos. Esa base de datos la metí a una carpeta y le puse git. Esto me ayudaría a detectar los cambios para cuando agregara una imagen, tener las diferencias de las tablas que habían cambiado y con los valores nuevos.

Agregué una imagen de la manera tradicional, hice el dump de nuevo y comparé la versión nueva (la que tiene la imagen agregada) con la anterior (la que no tiene la imagen).

A partir de acá, en realidad fue sencillo escribir el script para lograr el resultado.

Preparando el escenario para enlazar imágenes en WooCommerce

Antes de empezar a enlazar imágenes en WooCommerce me hice una carpeta en wp-content/uploads que se llamaba imagensku y metí algunas imágenes ahí.

Como para estas alturas ya tenía claro lo que se tenía que cambiar, hice una tabla intermedia, donde se relacionaba el SKU del producto y la URL de la imagen.

Obtener la lista de productos y su SKU en WooCommerce

Con la siguiente consulta obtienes el ID del producto en la tabla de wp_posts, el título del producto, SKU, la url de la imagen y el ID de la tabla wp_postmeta, que correspondería a los campos de las imágenes. Digamos que la primera tabla es la principal y la segunda es el detalle.

SELECT
    products.id,
    products.post_title as title,
    meta3.meta_value as sku,
    meta2.meta_value as image_url,
    meta2.meta_id
FROM 
    wp_posts products
LEFT JOIN 
    wp_postmeta meta1
    ON (
        meta1.post_id = products.id 
        AND meta1.meta_value IS NOT NULL
        AND meta1.meta_key = "_thumbnail_id"              
    )
LEFT JOIN 
    wp_postmeta meta2
    ON (
        meta1.meta_value = meta2.post_id
        AND meta2.meta_key = "_wp_attached_file"
        AND meta2.meta_value IS NOT NULL  
    )
LEFT JOIN 
    wp_postmeta meta3
    ON (
        meta3.post_id = products.id
        AND meta3.meta_key = "_sku"
        AND meta3.meta_value IS NOT NULL  
    )
WHERE
    products.post_status="publish" 
    AND (products.post_type="product" OR products.post_type="product_variation")

Con esto nos regresa una lista de los SKU y su imagen, en caso de que estén asignadas. Al principio, esta consulta la quiero para tener la lista de SKU que luego voy a comparar con la tabla intermedia que he mencionado, y también para conocer el ID del producto en la base de datos en wp_posts.

Funciones previas

Como he dicho, necesitamos insertar datos en dos tablas. Para ello creamos dos funciones:

Para insertar las imágenes en wp_posts. Las imágenes también son entidades, por lo que deben estar registradas en la tabla de posts.

// $link es la conexión de mysqli_connect
function InsertarPostImagen($link, $productoID, $productoNombre, $imagenName)
{
  $idAdmin = 1;
  $urlBase = "https://midominio.com/wp-content/uploads/";

  $sql = "
  INSERT INTO
    `wp_posts`(`post_author`,
    `post_date`,
    `post_date_gmt`,
    `post_content`,
    `post_title`,
    `post_excerpt`,
    `post_status`,
    `comment_status`,
    `ping_status`,
    `post_name`,
    `post_modified`,
    `post_modified_gmt`,
    `post_parent`,
    `guid`,
    `post_type`,
    `post_mime_type`, 
		`to_ping`,
		`pinged`,
		`post_content_filtered`)
  VALUES ($idAdmin,
    '2022-01-01 12:12:12',
    '2022-01-01 12:12:12',
    '$productoNombre',
    '$productoNombre',
    '',
    'publish',
    'closed',
    'closed',
    '$productoNombre',
    '2022-09-20 12:12:12',
    '2022-09-20 12:12:12',
    $productoID,
    '$urlBase$imagenName',
    'attachment',
    'image/jpeg', '', '', '')
";
  mysqli_query($link, $sql);
  return mysqli_insert_id($link);
}

Ahora, para registrar la relación entre el producto y sus propiedades en wp_postmeta.

// $link es la conexión de mysqli_connect
function InsertarPostMeta($link, $postId, $key, $value)
{
  $sql = "
    INSERT INTO `wp_postmeta`
      (`post_id`, `meta_key`, `meta_value`) 
    VALUES 
      ('$postId', '$key', '$value');
  ";
  mysqli_query($link, $sql);
  return mysqli_insert_id($link);
}

Resultado

Entonces, con la tabla intermedia y la consulta anterior ya puedo iniciar con el script. Me voy a ahorrar algunas líneas y me centraré en lo primordial.

// conectar a la base de datos antes con mysqli_connect

// hago el ciclo sobre el resultado de la consulta principal
if ($result = mysqli_query($link, $query)) {
	while ($row = mysqli_fetch_row($result)) {
		$productoID = $row[0];
    $productoNombre = $row[1];
    $productoSku = $row[2];

		// 1. Hacer una consulta que me traiga el nombre del imagen de acuerdo a la tabla intermedia
    $qImage = "select * from image_sku ris where ris.sku = '$productoSku' AND images is not null;";
    $rImage = mysqli_query($link, $qImage);
    $image = mysqli_fetch_row($rImage);

		// validaciones que necesites hacer para verificar que existe el 
		// sku en la tabla intermedia

		// 2. Insertar el registro de la imagen y obtener el ID
		$imageName = "imagensku/" . basename($image[1]);
    $imageID = InsertarPostImagen($link, $productoID, $productoNombre, $imageName);
		
		// 3. Calcular el serialize de la imagen
		// estos valores los puse fijos, pero los puedes obtener de otra manera con PHP
		// igual funciona
		$serialized = serialize(
        array(
          "width" => 357,
          "height" => 335,
          "file" => $imageName,
          "filesize" => 10655,
          "sizes" => array()
        )
     );

		// 4. Agregar el detalle de la imagen en post_meta (_wp_attachment_metadata y _wp_attached_file)
    InsertarPostMeta($link, $imageID, '_wp_attachment_metadata', $serialized);
    InsertarPostMeta($link, $imageID, '_wp_attached_file', $imageName);

    // 5. Agregar la relación del ID del producto con el ID de la imagen (_thumbnail_id y _product_image_gallery)
    InsertarPostMeta($link, $productoID, '_thumbnail_id', $imageID);
    InsertarPostMeta($link, $productoID, '_product_image_gallery', $imageID);
	}
}
mysqli_free_result($result);

Y listo. Una vez que entres verás las imágenes relacionadas y en la galería.

Detallitos que pasan

NOTA: por alguna razón, en algunos ambientes, me la muestra dos veces cuando entras al detalle del producto. En este caso específico no fue así (seguramente por alguna modificación anterior del cliente), pero puedes jugar con los valores de wp_postmeta para identificar cuál valor puedes omitir.

P.S. Sí lo tuve listo ese mismo día, lo pasé a su sysadmin y el cliente tuvo un fin de semana con una preocupación menos.

Saludos.


Posted

in

, , ,

by