Como usar um arquivo de modelo para tema de um formulário?

50

Enquanto nós, comentários, blocos e muitas outras coisas no Drupal são temáticos usando arquivos de modelo de tema (como node.tpl.php), os formulários são uma história diferente. Não há arquivos de modelo de tema para formulários. Como posso obter um formulário específico para usar um modelo de tema personalizado?

Chaulky
fonte

Respostas:

73

É completamente razoável querer usar um arquivo tpl para exibir um formulário. Você pode usar muitas propriedades e #prefix/ ou CSS estranhas #suffixpara obter resultados semelhantes, mas usando o tpl's, você não precisa desorganizar a separação de suas camadas de lógica e apresentação e não precisa direcionar seletores de CSS feios como #user-login label. Aqui está um exemplo no 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); ?>

Isso está usando o Foundation , que nos fornece um formulário como este:

insira a descrição da imagem aqui

Charlie Schliesser
fonte
parece que você esqueceu um estado retorno sobre o mytheme_theme () função
sel_space
Você está certo, eu adicionei.
precisa
5
Nota muito importante é que, na parte inferior do trecho de código, é o print drupal_render_children($form)que faz com que o formulário realmente faça coisas :).
Chris Rockwell
Boa resposta. Posso acrescentar que você precisa especificar adicionalmente engine, se você estiver usando algo não padrão. Por exemplo 'engine' => 'twig'.
milkovsky
11
Boa resposta. Tenha em mente se você deseja criar um formulário de administração como user_profile_formou user_register_form. Nesse cenário, você precisará: a) fazer o seu tema no tema do administrador (ou subtema dele, se não puder alterar o tema do administrador de base); ou b) colocar o seu tema em um módulo personalizado. Caso contrário, seu tema não será visto.
Therobyouknow
18

Você precisa implementar hook_form_alter () em um módulo ou template.php e definir a propriedade #theme do formulário :

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

Em seguida, implemente um novo 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',
    ),
  );
}

E então adicione o formulário - modelo user_login.tpl.php com o código a seguir para renderizar o formulário:

<?php print drupal_render_children($form) ?> 
mrded
fonte
11
A #themepropriedade é muito simples e é mencionada pela primeira vez muito abaixo nas respostas, super esquisita. Esse é definitivamente o meu método favorito.
Matt Fletcher
11
Eu testei esse código e funciona como esperado.
21418 VladSavitsky #
14

Mesmo que você possa usar a solução de kiamlaluno, eu pessoalmente não usaria.

Qual é o motivo para precisar de um arquivo de modelo para um formulário? Se é porque você deseja uma marcação ligeiramente diferente para um formulário existente? Nesse caso, você pode hook_form_alter()modificar o formulário antes de ser renderizado. Usando a API do formulário, você pode modificar todos os campos do formulário, injetar elementos html etc.

Aqui está um exemplo do hook_form_alter()que eu criei que modifica o bloco de formulário padrão de login do 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;
  }
}

O exemplo acima envolve o formulário inteiro em um DIV que possui um estilo embutido para transformar a cor do plano de fundo em vermelho. Ele também adiciona um parágrafo do texto de ajuda ao início do formulário.

É assim que meu formulário de login do usuário se parece agora depois que o código acima é carregado:

Formulário de login personalizado

Consulte a referência da API do formulário para obter mais informações: Referência da API do formulário

Camsoft
fonte
11
Apenas para esclarecer o uso de estilos embutidos neste exemplo, é apenas para simplificar o exemplo. Eu não recomendo usar estilos embutidos e você deve usar classes.
Camsoft 4/03/11
Não apoio o uso de um arquivo de modelo para renderizar um formulário; de fato, eu também disse que nunca usei um arquivo de modelo para renderizar um formulário (na verdade, alterei o código de um módulo que estava usando um arquivo de modelo para um formulário) e que o Drupal não usa o modelo arquivos para renderizar formulários.
Kievlaluno
5
E se você quiser alterar radicalmente a marcação? Às vezes, um arquivo de modelo é uma opção melhor.
Cossovich 16/10/2013
6
A marcação em um construtor de lógica de formulário cheira.
Charlie Schliesser
11
Embora esta solução funciona na maioria dos casos, pode realmente quebrar quando a prestação formulário é atualizado em um ajax chamada de retorno
Patricks
13

Na verdade, nunca precisei usar um arquivo de modelo para um formulário.
Tanto quanto posso ver, o código principal do Drupal usa funções temáticas, quando um formulário ou parte de um formulário precisa ser renderizado de uma maneira específica; uma função de tema que chama drupal_render () normalmente é suficiente para qualquer finalidade.

Para responder à pergunta, criar um arquivo de modelo para um formulário não é diferente de criar um arquivo de modelo que não seja para um formulário.

Defina uma função de tema, usando como função de tema o nome do retorno de chamada do construtor de formulários. O código deve ser semelhante ao seguinte:

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

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

Se o formulário contiver o valor $form['field_1'], ele estará disponível no arquivo de modelo como $field_1. O arquivo de modelo também poderá usar quaisquer valores passados template_preprocess_mymodule_form().

kiamlaluno
fonte
Como sugiro um formulário definido por alguns outros módulos, possivelmente módulos principais para usar minha função / modelo de tema?
Shafiul 21/03/12
Set $form['#theme'].
kiamlaluno
11
Não funciona, quando eu enviar o formulário, ele não ir para a função form_submit
gbstack
1

Eu sempre estilizaria adicionando ao meu arquivo CSS usando seletores para identificar o elemento a ser estilizado da seguinte forma para o formulário de login 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;
}

Acima, simplesmente adiciono ao sites/all/themes/theme-name/css/theme-name.css

Se o que você precisa estilizar não possui um ID ou um seletor suficientemente preciso, é necessário usar a hookabordagem para modificar o HTML e adicionar identificadores.

A IMO usando o estilo embutido nos elementos é uma prática muito ruim que deve ser preterida e substituída pelo uso classeid

Richard Harrison
fonte
0

Para criar um tema de um formulário, você pode usar um css personalizado, conforme explicado em Themeing Drupal 7 Forms (incluindo CSS e JS) .

Basicamente, você precisa executar estas etapas:

  1. Registre um caminho para o formulário usando hook_menu ()
  2. Definir o formulário
  3. Registrar uma função de tema com hook_theme ()
  4. Escreva a função do tema
  5. Crie os arquivos CSS e JavaScript
shasi kanth
fonte
-2

Tenho certeza de que você pode usar um modelo para formulários, mas você precisa usar hook_theme para registrar o modelo em primeiro lugar. Eu tive uma situação em que o formulário realmente precisava ser baseado em tabela, e não em div, e as simples alterações #prefix e #suffix não foram suficientes. Se estiver interessado, provavelmente poderia tentar descobrir um exemplo.

Malks
fonte