Jak użyć pliku szablonu do stworzenia formularza?

50

Podczas gdy węzły, komentarze, bloki i wiele innych rzeczy w Drupal są tematyczne przy użyciu plików szablonów motywów (takich jak node.tpl.php), formy są inną historią. Brak plików szablonów motywów dla formularzy. Jak uzyskać konkretny formularz do korzystania z niestandardowego szablonu motywu?

Chaulky
źródło

Odpowiedzi:

73

Całkowicie uzasadnione jest użycie pliku tpl do wyświetlenia formularza. Możesz użyć wielu obcych CSS i #prefix/ #suffixwłaściwości, aby osiągnąć podobne wyniki, ale używając tpl, nie musisz zaśmiecać separacji warstw logiki i prezentacji i nie musisz celować w brzydkie selektory CSS, takie jak #user-login label. Oto przykład w 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); ?>

To używa Fundacji , która daje nam taki formularz:

wprowadź opis zdjęcia tutaj

Charlie Schliesser
źródło
wygląda na to, że zapomniałeś stanu zwrotnego funkcji mytheme_theme ()
sel_space
Masz rację, dodałem to.
Charlie Schliesser
5
Bardzo ważna uwaga jest taka, że ​​na dole fragmentu kodu jest to, print drupal_render_children($form)co sprawia, że ​​formularz robi rzeczy :)
Chris Rockwell,
Dobra odpowiedź. Mogę dodać, że musisz dodatkowo określić engine, jeśli używasz czegoś innego niż domyślny. Np 'engine' => 'twig'.
milkovsky
1
Niezła odpowiedź. Pamiętaj, jeśli chcesz utworzyć motyw formularza administracyjnego, takiego jak user_profile_formlub user_register_form. W tym scenariuszu musisz albo: a) wykonać temat w motywie administratora (lub wyłączyć go, jeśli nie możesz zmienić podstawowego motywu administratora) lub b) umieścić motyw w niestandardowym module. W przeciwnym razie Twoje motywy nie będą widoczne.
therobyouknow
18

Musisz zaimplementować hook_form_alter () w module lub template.php i ustawić właściwość #theme formularza :

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

Następnie zaimplementuj nowy motyw:

/**
 * 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',
    ),
  );
}

A następnie dodaj formularz - szablon user_login.tpl.php z kodem śledzenia, aby wyświetlić formularz:

<?php print drupal_render_children($form) ?> 
mrded
źródło
1
Ta #themewłaściwość jest bardzo prosta i jest wymieniona po raz pierwszy bardzo nisko w odpowiedziach, bardzo dziwna. To zdecydowanie moja ulubiona metoda.
Matt Fletcher
1
Przetestowałem ten kod i działa zgodnie z oczekiwaniami.
VladSavitsky,
14

Nawet jeśli możesz skorzystać z rozwiązania kiamlaluno, ja osobiście bym tego nie zrobił.

Jaki jest powód, dla którego potrzebujesz pliku szablonu formularza? Jeśli to dlatego, że chcesz nieco inny znacznik dla istniejącego formularza? Jeśli tak, możesz hook_form_alter()zmodyfikować formularz przed jego renderowaniem. Za pomocą interfejsu API formularza możesz modyfikować wszystkie pola formularza, wstawiać elementy HTML itp.

Oto przykład hook_form_alter(), który stworzyłem, który modyfikuje standardowy blok formularza logowania 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;
  }
}

Powyższy przykład otacza całą formę w DIV, który ma styl wbudowany, aby zmienić kolor tła na czerwony. Dodaje również akapit tekstu pomocy na początku formularza.

Tak wygląda teraz mój formularz logowania użytkownika po załadowaniu powyższego kodu:

Dostosowany formularz logowania

Aby uzyskać więcej informacji, zobacz Dokumentacja interfejsu API formularza : Dokumentacja interfejsu API formularza

Camsoft
źródło
1
Aby wyjaśnić użycie stylów wbudowanych w tym przykładzie, wystarczy uprościć przykład. Nie polecam używania stylów wbudowanych i powinieneś używać klas.
Camsoft,
Nie obsługuję używania pliku szablonu do renderowania formularza; w rzeczywistości powiedziałem również, że nigdy nie użyłem pliku szablonu do renderowania formularza (faktycznie zmieniłem kod modułu, który używał pliku szablonu dla formularza) i że Drupal nie używa szablonu pliki do renderowania formularzy.
kiamlaluno
5
Co jeśli chcesz radykalnie zmienić znaczniki? Czasami plik szablonu jest lepszą opcją.
kossowicz
6
Znaczniki w formie kreatora logiki pachną.
Charlie Schliesser
1
Chociaż to rozwiązanie działa w większości przypadków, może się zepsuć, gdy renderowanie formularza jest odświeżane w wywołaniu zwrotnym ajax
PatrickS
13

Tak naprawdę nigdy nie potrzebowałem używać pliku szablonu dla formularza.
O ile widzę, podstawowy kod Drupala używa funkcji motywu, gdy formularz lub część formularza musi być renderowana w określony sposób; funkcja motywu wywołująca drupal_render () zwykle wystarcza do jakichkolwiek celów.

Aby odpowiedzieć na pytanie, utworzenie pliku szablonu dla formularza nie różni się od utworzenia pliku szablonu, który nie jest dla formularza.

Zdefiniuj funkcję motywu, używając jako funkcji motywu nazwy wywołania zwrotnego konstruktora formularzy. Kod powinien być podobny do następującego:

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

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

Jeśli formularz zawiera wartość $form['field_1'], jej wartość będzie dostępna w pliku szablonu jako $field_1. Plik szablonu będzie mógł także używać dowolnych wartości przekazywanych z template_preprocess_mymodule_form().

kiamlaluno
źródło
Jak zasugerować formularz zdefiniowany przez inne moduły, być może moduły podstawowe, aby użyć mojej funkcji / szablonu kompozycji?
Shafiul
Set $form['#theme'].
kiamlaluno
1
Nie działa, gdy prześlę formularz, nie przejdzie on do funkcji
form_submit
1

Zawsze stylizowałbym, dodając do mojego pliku CSS za pomocą selektorów, aby zidentyfikować element, który ma być stylowany w następujący sposób dla podstawowego formularza logowania

#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;
}

Powyższe po prostu dodaję sites/all/themes/theme-name/css/theme-name.css

Jeśli to, czego potrzebujesz do stylu, nie ma identyfikatora ani wystarczająco dokładnego selektora, konieczne jest zastosowanie hookpodejścia do zmodyfikowania kodu HTML i dodanie identyfikatorów.

IMO używająca stylu wbudowanego w elementach jest bardzo złą praktyką, która powinna być przestarzała i zastąpiona przez użycie classiid

Richard Harrison
źródło
0

Aby utworzyć motyw formularza, możesz użyć niestandardowego css, jak wyjaśniono w Themeing Drupal 7 Forms (w tym CSS i JS) .

Zasadniczo musisz wykonać następujące kroki:

  1. Zarejestruj ścieżkę do formularza za pomocą hook_menu ()
  2. Zdefiniuj formularz
  3. Zarejestruj funkcję motywu za pomocą hook_theme ()
  4. Napisz funkcję motywu
  5. Utwórz pliki CSS i JavaScript
shasi kanth
źródło
-2

Jestem pewien, że możesz użyć szablonu do formularzy, ale musisz najpierw użyć hook_theme, aby zarejestrować szablon. Miałem sytuację, w której formularz naprawdę musiał być oparty na tabeli, a nie na div, a proste zmiany #prefix i #suffix tak naprawdę go nie wycięły. W razie zainteresowania mógłbym prawdopodobnie spróbować wykopać przykład.

Malks
źródło