✅Convierte tu WooCommerce en una Plataforma de Sorteos con Papeletas

¿Alguna vez has pensado en llevar la emoción de los sorteos a tu tienda WooCommerce? Ahora puedes hacerlo gracias a un código personalizado que transforma tu tienda en una completa solución para gestionar sorteos con papeletas numeradas. Esta funcionalidad te permite vender boletos de forma sencilla, gestionar los números ya comprados y garantizar una experiencia profesional tanto para ti como para tus clientes.

Este código es ideal para negocios que desean organizar rifas de productos como gadgets, experiencias, alimentos premium (como el clásico jamón navideño) o cualquier otro premio. La solución no solo permite a los usuarios seleccionar los números que desean participar, sino que también incluye validaciones para evitar la compra de números duplicados y garantiza que todo el proceso sea transparente y ordenado.

¿Qué hace este código personalizado?

  1. Activa la opción de sorteo para productos individuales:
    Desde el panel de administración de WooCommerce, puedes marcar cualquier producto como un sorteo y definir un rango de números (por ejemplo, del 001 al 100). Esto permite gestionar qué productos serán sorteos sin interferir con el resto de los artículos de la tienda.
  2. Selección de números mediante un popup interactivo:
    En la página del producto, los clientes pueden seleccionar sus números disponibles a través de un popup visual, que hace que el proceso sea más claro y fácil de usar. Si un número ya ha sido comprado en pedidos anteriores, aparecerá como no disponible, garantizando que no haya duplicados.
  3. Validación antes de añadir al carrito:
    El código se asegura de que los clientes no puedan añadir al carrito productos tipo sorteo sin haber seleccionado al menos un número. Esto evita confusiones y mantiene el flujo de compra en orden.
  4. Cálculo automático del precio según la cantidad de números seleccionados:
    Si un cliente selecciona tres números, el precio total del producto se multiplicará automáticamente por tres. Este ajuste dinámico se refleja en el carrito, el checkout y los correos de confirmación del pedido.
  5. Gestión avanzada de números comprados:
    Cuando un pedido se marca como completado, los números seleccionados en ese pedido se bloquean automáticamente para futuras compras. Esto asegura que ningún cliente pueda comprar números que ya estén reservados o adquiridos por otros.
  6. Personalización para la tienda:
    En la página de tienda, el botón «Añadir al carrito» se reemplaza con un botón que redirige al cliente a la página del producto, donde podrá seleccionar sus números antes de completar la compra.
sorteos papeletas woocommerce

El siguiente código tienes que agregarlo en el functions.php de tu tema hijo o utilizar un plugin como CODE SNIPPETS.


// 1. Agregar una casilla para indicar que el producto es un sorteo
add_action('woocommerce_product_options_general_product_data', 'agregar_casilla_sorteo');
function agregar_casilla_sorteo() {
    echo '<div class="options_group">';
    
    // Casilla para activar "Es un sorteo"
    woocommerce_wp_checkbox([
        'id'          => '_es_sorteo',
        'label'       => __('¿Es un sorteo?', 'woocommerce'),
        'desc_tip'    => true,
        'description' => __('Marca esta casilla si el producto es un sorteo.', 'woocommerce'),
    ]);

    // Campo para el rango de números
    woocommerce_wp_text_input([
        'id'          => '_rango_numeros',
        'label'       => __('Rango de números (ej: 001-100)', 'woocommerce'),
        'placeholder' => '001-100',
        'desc_tip'    => true,
        'description' => __('Define el rango de números disponibles para este sorteo.', 'woocommerce'),
        'type'        => 'text',
    ]);

    echo '</div>';
}

// 2. Guardar los campos adicionales del producto
add_action('woocommerce_process_product_meta', 'guardar_campos_sorteo');
function guardar_campos_sorteo($post_id) {
    // Guardar si es un sorteo
    $es_sorteo = isset($_POST['_es_sorteo']) ? 'yes' : 'no';
    update_post_meta($post_id, '_es_sorteo', $es_sorteo);

    // Guardar el rango de números
    if (isset($_POST['_rango_numeros'])) {
        update_post_meta($post_id, '_rango_numeros', sanitize_text_field($_POST['_rango_numeros']));
    }
}

// 3. Mostrar el botón para abrir el popup
add_action('woocommerce_before_add_to_cart_button', 'mostrar_boton_popup_sorteos');
function mostrar_boton_popup_sorteos() {
    global $product;

    // Verificar si el producto es un sorteo
    $es_sorteo = get_post_meta($product->get_id(), '_es_sorteo', true);
    if ($es_sorteo !== 'yes') {
        return;
    }

    // Botón para abrir el popup
    echo '<button type="button" id="abrir-popup-numeros" class="button" style="margin-bottom:20px;">Seleccionar números</button>';

    // Contenedor del popup
    echo '<div id="popup-numeros" style="display:none; position:fixed; top:50%; left:50%; transform:translate(-50%, -50%); width:90%; max-width:600px; background:white; padding:20px; border:1px solid #ccc; box-shadow:0 5px 15px rgba(0,0,0,0.5); z-index:1000;">';
    echo '<h3>Selecciona tus números</h3>';
    echo '<div id="numeros-container" style="max-height:400px; overflow-y:auto; display: grid; grid-template-columns: repeat(auto-fit, minmax(50px, 1fr)); gap: 10px; padding: 10px;">';

    // Obtener y listar los números en el popup
    $rango = get_post_meta($product->get_id(), '_rango_numeros', true);
    if (!$rango || strpos($rango, '-') === false) {
        echo '<p>No hay números disponibles para este sorteo.</p>';
    } else {
        list($inicio, $fin) = explode('-', $rango);
        $inicio = intval($inicio);
        $fin = intval($fin);

        $comprados = get_post_meta($product->get_id(), '_numeros_comprados', true) ?: [];

        for ($i = $inicio; $i <= $fin; $i++) {
            $numero = str_pad($i, strlen($fin), '0', STR_PAD_LEFT);
            $disabled = in_array($numero, $comprados) ? 'disabled' : '';
            $tachado = $disabled ? 'text-decoration: line-through; color: red;' : '';
            echo '<label style="cursor: pointer;">';
            echo '<input type="checkbox" name="numeros_sorteo[]" value="' . esc_attr($numero) . '" ' . $disabled . ' style="margin-right: 5px;">';
            echo '<span style="' . $tachado . '">' . esc_html($numero) . '</span>';
            echo '</label>';
        }
    }

    echo '</div>';
    echo '<button type="button" id="cerrar-popup-numeros" class="button" style="margin-top:10px; margin-right:10px;">Cerrar</button>';
    echo '<button type="button" id="confirmar-numeros" class="button button-primary" style="margin-top:10px;">Añadir números</button>';
    echo '</div>';

    // Fondo oscuro del popup
    echo '<div id="fondo-popup-numeros" style="display:none; position:fixed; top:0; left:0; width:100%; height:100%; background:rgba(0,0,0,0.5); z-index:999;"></div>';
}

// 4. Scripts para manejar el popup
add_action('wp_footer', 'popup_sorteos_scripts');
function popup_sorteos_scripts() {
    ?>
    <script>
        document.addEventListener('DOMContentLoaded', function () {
            const abrirPopup = document.getElementById('abrir-popup-numeros');
            const cerrarPopup = document.getElementById('cerrar-popup-numeros');
            const confirmarNumeros = document.getElementById('confirmar-numeros');
            const popup = document.getElementById('popup-numeros');
            const fondo = document.getElementById('fondo-popup-numeros');
            const numerosContainer = document.getElementById('numeros-container');

            // Mostrar el popup
            if (abrirPopup) {
                abrirPopup.addEventListener('click', function () {
                    popup.style.display = 'block';
                    fondo.style.display = 'block';
                });
            }

            // Cerrar el popup
            if (cerrarPopup) {
                cerrarPopup.addEventListener('click', function () {
                    popup.style.display = 'none';
                    fondo.style.display = 'none';
                });
            }

            // Cerrar el popup al hacer clic fuera
            if (fondo) {
                fondo.addEventListener('click', function () {
                    popup.style.display = 'none';
                    fondo.style.display = 'none';
                });
            }

            // Confirmar selección de números
            if (confirmarNumeros) {
                confirmarNumeros.addEventListener('click', function () {
                    const checkboxes = numerosContainer.querySelectorAll('input[name="numeros_sorteo[]"]:checked');
                    const seleccionados = Array.from(checkboxes).map(cb => cb.value);

                    if (seleccionados.length > 0) {
                        alert('Has seleccionado los números: ' + seleccionados.join(', '));

                        // Crear un campo oculto para enviar los números seleccionados al formulario
                        let inputSeleccionados = document.querySelector('input[name="numeros_sorteo_seleccionados"]');
                        if (!inputSeleccionados) {
                            inputSeleccionados = document.createElement('input');
                            inputSeleccionados.type = 'hidden';
                            inputSeleccionados.name = 'numeros_sorteo_seleccionados';
                            document.querySelector('form.cart').appendChild(inputSeleccionados);
                        }
                        inputSeleccionados.value = seleccionados.join(',');

                        // Cerrar el popup
                        popup.style.display = 'none';
                        fondo.style.display = 'none';
                    } else {
                        alert('Por favor selecciona al menos un número.');
                    }
                });
            }
        });
    </script>
    <?php
}

// 5. Guardar los números seleccionados en el carrito
add_filter('woocommerce_add_cart_item_data', 'guardar_numeros_en_carrito', 10, 2);
function guardar_numeros_en_carrito($cart_item_data, $product_id) {
    if (isset($_POST['numeros_sorteo_seleccionados'])) {
        $cart_item_data['numeros_sorteo'] = array_map('sanitize_text_field', explode(',', $_POST['numeros_sorteo_seleccionados']));
        $cart_item_data['unique_key'] = md5(uniqid()); // Asegura que cada ítem sea único en el carrito
    }

    return $cart_item_data;
}

// 6. Ajustar el precio del producto en función de los números seleccionados
add_filter('woocommerce_before_calculate_totals', 'ajustar_precio_por_numeros', 10, 1);
function ajustar_precio_por_numeros($cart) {
    if (is_admin() && !defined('DOING_AJAX')) {
        return;
    }

    foreach ($cart->get_cart() as $cart_item) {
        if (isset($cart_item['numeros_sorteo']) && is_array($cart_item['numeros_sorteo'])) {
            $cantidad_numeros = count($cart_item['numeros_sorteo']);
            $precio_original = $cart_item['data']->get_price(); // Precio base del producto
            $nuevo_precio = $precio_original * $cantidad_numeros; // Multiplica por la cantidad de números
            $cart_item['data']->set_price($nuevo_precio);
        }
    }
}

// 7. Mostrar los números seleccionados en el carrito y checkout
add_filter('woocommerce_get_item_data', 'mostrar_numeros_en_carrito', 10, 2);
function mostrar_numeros_en_carrito($item_data, $cart_item) {
    if (isset($cart_item['numeros_sorteo'])) {
        $item_data[] = [
            'name' => __('Números seleccionados', 'woocommerce'),
            'value' => implode(', ', $cart_item['numeros_sorteo']),
        ];
    }

    return $item_data;
}

// 8. Guardar los números en los metadatos del pedido
add_action('woocommerce_checkout_create_order_line_item', 'guardar_numeros_en_pedido', 10, 4);
function guardar_numeros_en_pedido($item, $cart_item_key, $values, $order) {
    if (isset($values['numeros_sorteo'])) {
        $item->add_meta_data('Números seleccionados', implode(', ', $values['numeros_sorteo']));
    }
}

// Actualizar los números comprados al completar un pedido
add_action('woocommerce_order_status_completed', 'actualizar_numeros_comprados');
function actualizar_numeros_comprados($order_id) {
    // Obtener el pedido
    $order = wc_get_order($order_id);

    // Recorrer los productos del pedido
    foreach ($order->get_items() as $item) {
        $product_id = $item->get_product_id();
        $numeros_comprados = get_post_meta($product_id, '_numeros_comprados', true) ?: [];

        // Obtener los números seleccionados en el pedido
        $numeros_seleccionados = $item->get_meta('Números seleccionados', true);
        if (!empty($numeros_seleccionados)) {
            $numeros_seleccionados_array = explode(', ', $numeros_seleccionados);

            // Agregar los números seleccionados a la lista de números comprados
            $numeros_comprados = array_merge($numeros_comprados, $numeros_seleccionados_array);
            $numeros_comprados = array_unique($numeros_comprados); // Asegurar que no haya duplicados

            // Guardar la lista actualizada de números comprados
            update_post_meta($product_id, '_numeros_comprados', $numeros_comprados);
        }
    }
}

// Reemplazar el botón "Añadir al carrito" en la tienda para productos de sorteo
add_filter('woocommerce_loop_add_to_cart_link', 'reemplazar_boton_tienda_para_sorteos', 10, 2);
function reemplazar_boton_tienda_para_sorteos($button, $product) {
    // Verificar si el producto es un sorteo
    $es_sorteo = get_post_meta($product->get_id(), '_es_sorteo', true);
    if ($es_sorteo === 'yes') {
        // Crear un botón que redirija a la página del producto
        $url = get_permalink($product->get_id());
        $button = '<a href="' . esc_url($url) . '" class="button select-numbers">' . __('Seleccionar números', 'woocommerce') . '</a>';
    }

    return $button;
}

// Validar que se hayan seleccionado números antes de añadir al carrito
add_filter('woocommerce_add_to_cart_validation', 'validar_seleccion_de_numeros', 10, 3);
function validar_seleccion_de_numeros($passed, $product_id, $quantity) {
    // Verificar si el producto es un sorteo
    $es_sorteo = get_post_meta($product_id, '_es_sorteo', true);
    if ($es_sorteo === 'yes') {
        // Comprobar si se seleccionaron números
        if (empty($_POST['numeros_sorteo_seleccionados'])) {
            wc_add_notice(__('Por favor, selecciona al menos un número para este sorteo antes de añadir al carrito.', 'woocommerce'), 'error');
            $passed = false;
        }
    }

    return $passed;
}

Lenguaje del código: PHP (php)

Entendiendo el Código

1. Agregar una casilla para indicar que el producto es un sorteo

  • Qué hace:
    Esta sección permite al administrador marcar un producto como un sorteo desde el editor de productos en WooCommerce. Además, agrega un campo para definir el rango de números disponibles para el sorteo (por ejemplo, del 001 al 100).
  • Cómo funciona:
    • Usa woocommerce_wp_checkbox para crear una casilla de verificación que activa el sorteo.
    • Usa woocommerce_wp_text_input para permitir la entrada del rango de números.
    • Los datos se guardan como metadatos personalizados (_es_sorteo y _rango_numeros) con la acción woocommerce_process_product_meta.

2. Mostrar el botón «Seleccionar números» en la página del producto

  • Qué hace:
    En lugar de mostrar los números directamente, se incluye un botón que abre un popup interactivo donde los clientes pueden seleccionar los números disponibles.
  • Cómo funciona:
    • Comprueba si el producto es un sorteo mediante el meta _es_sorteo.
    • Crea un botón con el ID abrir-popup-numeros que abrirá el popup.
    • Dentro del popup, se genera una cuadrícula que muestra todos los números del rango especificado (_rango_numeros).
    • Los números ya comprados (almacenados en el meta _numeros_comprados) aparecen deshabilitados con un estilo visual tachado.

3. Scripts del popup

  • Qué hace:
    Agrega funcionalidades JavaScript para manejar la apertura, cierre y selección de números en el popup.
  • Cómo funciona:
    • Se detecta el clic en el botón «Seleccionar números» para mostrar el popup.
    • Los números seleccionados se recopilan y se guardan en un campo oculto (numeros_sorteo_seleccionados), que será enviado al formulario de WooCommerce.
    • Validaciones básicas, como asegurarse de que al menos un número esté seleccionado, también se realizan aquí.

4. Validar la selección de números antes de añadir al carrito

  • Qué hace:
    Evita que los clientes añadan un producto al carrito sin seleccionar al menos un número.
  • Cómo funciona:
    • Usa el filtro woocommerce_add_to_cart_validation.
    • Si el producto es un sorteo y no se encuentra ningún número en el campo oculto numeros_sorteo_seleccionados, muestra un mensaje de error con wc_add_notice y bloquea la acción de añadir al carrito.

5. Guardar los números seleccionados en el carrito

  • Qué hace:
    Al añadir un producto al carrito, los números seleccionados se guardan como datos personalizados del artículo.
  • Cómo funciona:
    • Usa el filtro woocommerce_add_cart_item_data para guardar los números seleccionados (numeros_sorteo_seleccionados) en el carrito.
    • Se genera una clave única (unique_key) para que los productos con diferentes números seleccionados se traten como ítems separados.

6. Mostrar los números seleccionados en el carrito y checkout

  • Qué hace:
    Los números seleccionados aparecen en el carrito y el checkout para que el cliente los visualice.
  • Cómo funciona:
    • Usa el filtro woocommerce_get_item_data para mostrar los números como parte de los datos del producto.
    • Los números se muestran en una lista bajo el nombre del producto.

7. Ajustar el precio según los números seleccionados

  • Qué hace:
    Calcula el precio total del producto multiplicando el precio base por la cantidad de números seleccionados.
  • Cómo funciona:
    • Usa el filtro woocommerce_before_calculate_totals.
    • Por cada ítem del carrito, verifica si tiene números seleccionados (numeros_sorteo).
    • Multiplica el precio base del producto por la cantidad de números seleccionados y actualiza el precio del ítem en el carrito.

8. Guardar los números seleccionados en los metadatos del pedido

  • Qué hace:
    Los números seleccionados se guardan como parte de los metadatos del pedido para referencia futura.
  • Cómo funciona:
    • Usa el hook woocommerce_checkout_create_order_line_item.
    • Por cada ítem del pedido, guarda los números seleccionados como metadatos (Números seleccionados) que estarán visibles en el backend y en los correos electrónicos.

9. Actualizar los números comprados al completar un pedido

  • Qué hace:
    Marca los números seleccionados en un pedido como no disponibles una vez que el pedido pasa al estado «completado».
  • Cómo funciona:
    • Usa el hook woocommerce_order_status_completed.
    • Por cada producto en el pedido, toma los números seleccionados y los agrega al meta _numeros_comprados.
    • Actualiza el meta _numeros_comprados con los números seleccionados, asegurándose de que no haya duplicados.

10. Reemplazar el botón «Añadir al carrito» en la página de tienda

  • Qué hace:
    En la página de tienda, reemplaza el botón «Añadir al carrito» por un botón que redirige a la página del producto para seleccionar números.
  • Cómo funciona:
    • Usa el filtro woocommerce_loop_add_to_cart_link.
    • Si el producto es un sorteo (_es_sorteo), reemplaza el enlace con un botón que redirige a la página del producto.

Mejora este código agregando boletos descargables por el cliente. Click aquí.

¿Necesitas funcionalidad de cerrar ventas y finalizar sorteo? Click aquí.

En concluión, este sistema para gestionar sorteos con WooCommerce es una solución completa y profesional. No solo facilita la venta de papeletas numeradas, sino que también automatiza procesos como la validación de números, la gestión de números comprados y la personalización del flujo de compra. Todo esto, sin necesidad de recurrir a costosos plugins o herramientas de terceros.

La implementación es flexible y se adapta a distintos tipos de proyectos: desde sorteos de productos hasta rifas benéficas o eventos exclusivos. Además, está diseñado para ofrecer una experiencia fluida tanto para el administrador como para los clientes, asegurando que los sorteos sean claros, transparentes y eficientes.

Si tienes un proyecto en mente y necesitas adaptar este código a tus necesidades específicas, o si buscas añadir nuevas funcionalidades, ¡no dudes en ponerte en contacto conmigo! Estoy aquí para ayudarte a personalizar este código o desarrollar cualquier solución a medida para tu tienda WooCommerce.

Nos vemos en el siguiente tutorial. Un saludo.

5/5 - (5 votos)
Compartir Artículo

3 comentarios

  1. Fran Salas Master WP 1 año atrás

    Deja tus opiniones o dudas en los comentarios.

  2. Usuario Anónimo No Premium Junior WP 11 meses atrás

    #Hola es muy bueno el plugin felicitaciones, hay posibilidad que allá un buscador del numero ganador cuando termina el sorteo?
    Gracias y felicitaciones nuevamente
    dariotorresrosa@gmail.com

    • Fran Salas Master WP 11 meses atrás

      Hola, los números comprados aparecen en cada pedido por lo tanto si agregas el número ganador en el buscador de pedidos del admin, debería aparecer el pedido que contiene el número. Saludos.

¿Tienes una duda o sugerencia sobre este artículo?

Puedes dejar un comentario de forma anónima, sin necesidad de registrarte ni proporcionar ningún dato personal. Tu mensaje se publicará como “Usuario Anónimo No Premium”, un perfil que agrupa a todos los visitantes no registrados.

Importante: para evitar el spam automático, todos los comentarios anónimos deben comenzar con el símbolo #. Ejemplo: # Tengo una duda sobre los shortcodes personalizados...

Este espacio está destinado exclusivamente a preguntas concretas, dudas o sugerencias relacionadas con el contenido del artículo. Por respeto a los demás lectores, no se publicarán temas sin relación.

Privacidad y normas:
  • No tienes que agregar tu nombre, correo ni ningún otro dato identificativo.
  • No se permiten enlaces en comentarios anónimos.
  • No se permiten símbolos especiales como < o > (menor y mayor que), ya que se consideran intentos de insertar código y serán bloqueados.
  • Todos los comentarios anónimos pasan por revisión antes de ser publicados y solo se aprobarán si aportan valor al contenido del artículo.
¿Quieres comentar con tu nombre y que tu mensaje se publique al instante? Inicia sesión o regístrate.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

0%