¿Cómo usar un archivo de plantilla para crear un tema?

50

Si bien los nodos, los comentarios, los bloques y muchas otras cosas en Drupal tienen como tema el uso de archivos de plantilla de tema (como node.tpl.php), los formularios son una historia diferente. No hay archivos de plantilla de tema para formularios. ¿Cómo puedo obtener un formulario particular para usar una plantilla de tema personalizado?

Chaulky
fuente

Respuestas:

73

Es completamente razonable querer usar un archivo tpl para mostrar un formulario. Puede usar un montón de CSS y #prefix/ #suffixpropiedades extrañas para lograr resultados similares, pero al usar tpl's no tiene que abarrotar la separación de sus capas de lógica y presentación y no tiene que apuntar a selectores CSS desagradables #user-login label. Aquí hay un ejemplo en Drupal 7 ...

mytheme / template.php:

function mytheme_theme($existing, $type, $theme, $path) {
    // Ex 1: the "story" node edit form.
    $items['story_node_form'] = array(
        'render element' => 'form',
        'template' => 'node-edit--story',
        'path' => drupal_get_path('theme', 'mytheme') . '/template/form',
    );

    // Ex 2: a custom form that comes from a custom module's "custom_donate_form()" function.
    $items['custom_donate_form'] = array(
        'render element' => 'form',
        'template' => 'donate',
        'path' => drupal_get_path('theme', 'mytheme') . '/template/form',
    );

    return $items;
}

custom_donate_form ():

function custom_donate_form($form, &$form_state) {
    $form['first_name'] = array(
        '#type' => 'textfield',
        '#attributes' => array('placeholder' => t('First name')),
    );
    $form['last_name'] = array(
        '#type' => 'textfield',
        '#attributes' => array('placeholder' => t('Last name')),
    );
    $form['address'] = array(
        '#type' => 'textfield',
        '#attributes' => array('placeholder' => t('Address')),
    );
    $form['city'] = array(
        '#type' => 'textfield',
        '#attributes' => array('placeholder' => t('City')),
    );
    $form['state'] = array(
        '#type' => 'select',
        '#options' => array(
            'default' => 'State',
            '...' => '...',
        ),
    );
    $form['zip'] = array(
        '#type' => 'textfield',
        '#attributes' => array('placeholder' => t('Zip')),
    );
    $form['email'] = array(
        '#type' => 'textfield',
        '#attributes' => array('placeholder' => t('Email')),
    );
    $form['phone'] = array(
        '#type' => 'textfield',
        '#attributes' => array('placeholder' => t('Phone')),
    );
    $form['submit'] = array(
        '#type' => 'submit',
        '#value' => 'Submit',
    );

    return $form;
}

mytheme / template / form / donate.tpl.php:

<div class="row">
    <div class="small-12 medium-12 large-8 columns">

        <div class="row">
            <div class="small-12 columns">
                <h5>Contact Information</h5>
            </div>
        </div>

        <div class="row">
            <div class="small-12 large-6 medium-6 columns">
                <?php print render($form['first_name']); ?>
            </div>
            <div class="small-12 large-6 medium-6 columns">
                <?php print render($form['last_name']); ?>
            </div>
        </div>

        <div class="row">
            <div class="small-12 medium-6 large-6 columns">
                <?php print render($form['address']); ?>
            </div>

            <div class="small-12 medium-6 large-6 columns">
                <?php print render($form['city']); ?>
            </div>
        </div>

        <div class="row">
            <div class="small-12 medium-3 large-3 columns">
                <?php print render($form['state']); ?>
            </div>

            <div class="small-12 medium-3 large-3 columns">
                <?php print render($form['zip']); ?>
            </div>

            <div class="medium-6 large-6 columns"></div>
        </div>

        <div class="row">
            <div class="small-12 medium-6 large-6 columns">
                <?php print render($form['email']); ?>
            </div>

            <div class="small-12 medium-6 large-6 columns">
                <?php print render($form['phone']); ?>
            </div>
        </div>
    </div>

    <div class="row">
        <div class="small-12 medium-12 large-8 large-offset-2 columns">
            <?php print render($form['submit']); ?>
        </div>
    </div>
</div>

<!-- Render any remaining elements, such as hidden inputs (token, form_id, etc). -->
<?php print drupal_render_children($form); ?>

Esto está usando Foundation , que nos da una forma como esta:

ingrese la descripción de la imagen aquí

Charlie Schliesser
fuente
parece que olvidó un estado de retorno en la función mytheme_theme ()
sel_space
Tienes razón, lo he añadido.
Charlie Schliesser
55
Una nota muy importante es que, en la parte inferior del fragmento de código, es lo print drupal_render_children($form)que hace que el formulario realmente haga cosas :).
Chris Rockwell
Buena respuesta. Puedo agregar que necesita especificar adicionalmente engine, si está usando algo no predeterminado. Por ej 'engine' => 'twig'.
milkovsky
1
Buena respuesta. Tenga en cuenta si desea crear un tema para un formulario de administrador como user_profile_formo user_register_form. En ese escenario, necesitará a) hacer su tema en el tema de administración (o subtema de él si no puede cambiar el tema de administrador base) ob) poner su tema en un módulo personalizado. De lo contrario, no se verá su tema.
therobyouknow
18

Debe implementar hook_form_alter () en un módulo o template.php y establecer la propiedad #theme del formulario :

/**
 * Implements hook_form_alter().
 */
function hook_form_alter(&$form, &$form_state, $form_id) {
  if ($form_id == 'user_login') {
    $form['#theme'] = array('overwrite_user_login');
  }
}

Luego implemente un nuevo tema:

/**
 * Implements hook_theme().
 */
function hook_theme($existing, $type, $theme, $path){
  return array(
    'overwrite_user_login' => array(
      'render element' => 'form',
      'template' => 'form--user_login',
      'path' => $path . '/templates',
    ),
  );
}

Y luego agregue el formulario: plantilla user_login.tpl.php con el siguiente código para representar el formulario:

<?php print drupal_render_children($form) ?> 
mrded
fuente
1
La #themepropiedad es muy simple y se menciona por primera vez realmente bajo en las respuestas, super raro. Este es definitivamente mi método favorito.
Matt Fletcher
1
Probé este código y funciona como se esperaba.
VladSavitsky
14

Aunque es posible que pueda usar la solución de kiamlaluno, yo personalmente no lo haría.

¿Cuál es su razón para necesitar un archivo de plantilla para un formulario? Si es porque quieres un marcado ligeramente diferente para un formulario existente? Si es así, puede usar hook_form_alter()para modificar el formulario antes de que se procese. Usando la API de formulario, puede modificar todos los campos de formulario, inyectar elementos html, etc.

Aquí hay un ejemplo de lo hook_form_alter()que he creado que modifica el bloque estándar del formulario de inicio de sesión de drupal:

/**
 * Implements hook_form_alter().
 */
function MYMODULE_form_alter(&$form, &$form_state, $form_id) {

  switch ($form_id) {
    case 'user_login_block':

      // Form modification code goes here.
            $form['divstart'] = array(
                '#value' => '<div style="background-color: red;">',
                '#weight' => -1,
            );

            $form['instruct'] = array(
                '#value' => '<p>Enter your username and password to login</p>',
                '#weight' => 0,
            );          

            $form['divend'] = array(
                '#value' => '</div>',
                '#weight' => 4,             
            );
      break;
  }
}

El ejemplo anterior envuelve todo el formulario dentro de un DIV que tiene un estilo en línea para convertir el color de fondo en rojo. También agrega un párrafo de texto de ayuda al comienzo del formulario.

Así es como se ve mi formulario de inicio de sesión de usuario ahora una vez que se carga el código anterior:

Formulario de inicio de sesión personalizado

Consulte la referencia de API de formulario para obtener más información: Referencia de API de formulario

Camsoft
fuente
1
Solo para aclarar el uso de estilos en línea en este ejemplo es solo para simplificar el ejemplo. No recomiendo usar estilos en línea y debería usar clases.
Camsoft
No estoy apoyando el uso de un archivo de plantilla para representar un formulario; De hecho, también dije que nunca he usado un archivo de plantilla para representar un formulario (en realidad he cambiado el código de un módulo que estaba usando un archivo de plantilla para un formulario), y que Drupal no usa plantilla archivos para renderizar formularios.
kiamlaluno
55
¿Qué pasa si quieres alterar radicalmente el marcado? A veces, un archivo de plantilla es una mejor opción.
cossovich
66
El marcado en un generador de lógica de formulario huele.
Charlie Schliesser
1
Aunque esta solución funciona en la mayoría de los casos, en realidad puede romperse cuando la representación del formulario se actualiza en una devolución de llamada ajax
PatrickS
13

En realidad nunca he necesitado usar un archivo de plantilla para un formulario.
Por lo que puedo ver, el código central de Drupal utiliza funciones de tema, cuando un formulario o parte de un formulario debe representarse de una manera particular; Una función de tema que llama a drupal_render () normalmente es suficiente para cualquier propósito.

Para responder a la pregunta, crear un archivo de plantilla para un formulario no es diferente de crear un archivo de plantilla que no sea para un formulario.

Defina una función de tema, utilizando como función de tema el nombre de la devolución de llamada del generador de formularios. El código debe ser similar al siguiente:

/**
 * Implementation of hook_theme().
 */

 function mymodule_theme() {
   return array(
     'mymodule_form' => array(
       'template' => 'mymodule-form',
       'file' => 'mymodule.admin.inc',
       'arguments' => array('form' => NULL),
     ),
   );
 }

Si el formulario contiene el valor $form['field_1'], su valor estará disponible en el archivo de plantilla como $field_1. El archivo de plantilla también podrá usar cualquier valor pasado template_preprocess_mymodule_form().

kiamlaluno
fuente
¿Cómo sugiero un formulario definido por otros módulos, posiblemente módulos centrales para usar mi función / plantilla de tema?
Shafiul
Conjunto $form['#theme'].
kiamlaluno
1
No funciona, cuando envío el formulario, no irá a la función
form_submit
1

Siempre diseñaría agregando a mi archivo CSS usando selectores para identificar el elemento que se diseñará de la siguiente manera para el formulario de inicio de sesión principal

#user-login
{
   border:1px solid #888;
   padding-left:10px;
   padding-right:10px;
   background-image: url(http://www.zaretto.com/images/zlogo_s.png);
   background-repeat:no-repeat;
   background-position:right;
}

#user-login label
{
    display: inline-block;
}

Lo anterior simplemente lo agrego a sites/all/themes/theme-name/css/theme-name.css

Si lo que necesita para diseñar no tiene una ID o un selector suficientemente preciso, entonces es necesario utilizar el hookenfoque para modificar el HTML y agregar identificadores.

La OMI que usa el estilo en línea en los elementos es una práctica muy mala que debe ser desaprobada y reemplazada por el uso de classyid

Richard Harrison
fuente
0

Para crear un tema en un formulario, puede usar un CSS personalizado, como se explica en Themeing Drupal 7 Forms (Incluyendo CSS y JS) .

Básicamente, debe realizar estos pasos:

  1. Registre una ruta al formulario usando hook_menu ()
  2. Define el formulario
  3. Registre una función de tema con hook_theme ()
  4. Escribe la función del tema
  5. Crea los archivos CSS y JavaScript
shasi kanth
fuente
-2

Estoy bastante seguro de que puede usar una plantilla para formularios, pero debe usar hook_theme para registrar la plantilla en primer lugar. Tuve una situación en la que el formulario realmente necesitaba estar basado en tablas en lugar de div y los simples cambios de #prefijo y #suffix realmente no lo cortaron. Si estoy interesado, probablemente podría intentar encontrar un ejemplo.

Malks
fuente