El problema mas común a la hora de querer hacer que un formulario se repita mas de una vez en una misma pagina, es que cada uno de los formularios que se vayan creando van a ser solamente una fiel copia del anterior. Dicho de otra forma, estamos usando un solo formulario pero copiandolo en varios lados de la pagina.

Tuve este problema hace ya mas de un año pero no me olvido lo JODIDA-MENTE DIFÍCIL que me fue encontrar una solución, hasta que me di con esta pagina. Cuestión, que me salvó la vida (exagerado yo?). Por supuesto que les recomiendo que lean el articulo original, pero mas les recomiendo que lean mi interpretación de los hechos que esta mas buena :) .

Para este ejemplo primero vamos a crear una url donde poder poner nuestras múltiples instancias:

/**
 * Implementation of hook_menu()
 *
 * Solo esta implementada una URL para poder hacer este ejemplo.
 */
function form_multi_instancias_menu() {
    $items['form-multiples-instancias'] = array(
        'title' => t('Formulario multi instanciado'),
        'page callback' => 'form_multiples_instancias',
        'type' => MENU_NORMAL_ITEM,
        'access callback' => TRUE,
    );
    return $items;
}

Y la respectiva función:

/**
 * En este callback de la url queremos crear varias instancias
 * del mismo formulario.
 */
function form_multiples_instancias() {
    $salida = 'Si le hechas una mirada al codigo fuente vas a poder ver que el "form_id" de cada formulario es distinto, asi como el "form_build_id".';

    //en este ejemplo simplemente usamos un contador para crear los
    //formularios, pero podriamos estar procesando nodos tranquilamente.
    for ($i = 0; $i < 5; $i++) {
        /*
          * Noten que estoy armando dinamicamente el
          * drupal_get_form(). Lo siguiente equivaldria a hacer:
          * $salida .= drupal_get_form ( "form_ejemplo_0" , 0);
          * $salida .= drupal_get_form ( "form_ejemplo_1" , 1);
          * $salida .= drupal_get_form ( "form_ejemplo_2" , 2);
          * etc...
          */
        $salida .= drupal_get_form("form_ejemplo_" . $i, $i);
    }

    return $salida;
}

Si van leyendo los comentarios del código se va a ir entendiendo. Definamos el formulario que queremos instanciar:

//Este es un FAPI comun de toda la vida
function form_ejemplo($form_state, $i) {
    $form['un_campo_de_texto'] = array(
        '#type' => 'textfield',
        '#title' => t('Un campo de texto de ejemplo'),
        '#default_value' => $i,
    );
    $form['submit'] = array(
        '#type' => 'submit',
        '#value' => "enviame",
    );

    $form['#validate'] = array("form_ejemplo_validate");
    $form['#submit'] = array("form_ejemplo_submit");
    return $form;
}

function form_ejemplo_validate($form_state, $form) {
    drupal_set_message("He validado.");
}

function form_ejemplo_submit($form_state, $form) {
    drupal_set_message(
        t('Y el formulario enviado fue el Nº @form_number.',
            array(
                '@form_number' => $form_state ["un_campo_de_texto"] ["#value"])
        )
    );
}

//Este es el fin del FAPI comun de toda la vida

Bueno bueno bueno… hasta acá, si ejecutas el script lo que pasaría es que te saldrían tantos warning como formularios se invoquen. Y eso es debido a que no tenemos ningún formulario definido que se llame form_ejemplo_0, ni form_ejemplo_1, etc.

¿Soluciones?: Crear de la función form_ejemplo_0() para delante jajaja. No enserio, la solución es implementar el hook_forms(), que básicamente va a entender que se esta invocando un formulario inexistente y va a redireccionarlo a la definición ÚNICA que tenemos: form_ejemplo().

/**
 * Acá es donde se va a hacer la magia:
 * Resulta que por cada formulario que se invoca, el
 * hook_forms() es capaz de actuar como si de un hook_form_alter()
 * se tratara pero lo hace antes que se termine de armar
 * el array FAPI mas basico que crea Drupal.
 * O sea que intercede antes de que se le genere a cada
 * formulario sus #form_build_id, lo que nos permite
 * sobreescribir ciertos aspectos como ser la funcion
 * que alimentará el futuro formulario.
 */
function form_multi_instancias_forms($form_id, $args) {
    $forms = array();
    //para no cambiarle el callback a todos los formularios
    //que se creen hacemos un pequeño if. caso contrario
    //tendriamos un problema GORDO.
    if (strpos($form_id, 'form_ejemplo_') === 0) {
        //hemos dado con una de las variantes del formulario que
        //estamos instanciando, solamente tenemos que apuntar
        //su callback al formulario que hemos definido.
        $forms[$form_id] = array('callback' => 'form_ejemplo');
    }

    return $forms;
}

Bueno. ya está. este código así, funciona. Les dejo un mini-modulo con lo anterior para que lo vean funcionar. Instalenlo y miren en la URL “/form-multiples-instancias

DESCARGAR