Comment utiliser un fichier modèle pour thématiser un formulaire?

50

Alors que les nœuds, commentaires, blocs et bien d’autres choses dans Drupal sont thématiques à l’aide de fichiers de modèles de thèmes (tels que node.tpl.php), les formulaires sont une histoire différente. Il n'y a pas de fichier de modèle de thème pour les formulaires. Comment puis-je obtenir un formulaire particulier pour utiliser un modèle de thème personnalisé?

Chaulky
la source

Réponses:

73

Il est tout à fait raisonnable de vouloir utiliser un fichier tpl pour afficher un formulaire. Vous pouvez utiliser beaucoup de CSS et #prefix/ #suffixpropriétés superflus pour obtenir des résultats similaires, mais en utilisant tpl, vous n'avez pas à encombrer la séparation de vos couches logique et de présentation et à ne pas cibler des sélecteurs CSS déplaisants #user-login label. Voici un exemple dans 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); ?>

Ceci utilise Foundation , qui nous donne un formulaire comme celui-ci:

entrez la description de l'image ici

Charlie Schliesser
la source
il semblerait que vous ayez oublié un état de retour dans la fonction mytheme_theme ()
sel_space
Vous avez raison, je l'ai ajouté.
Charlie Schliesser
5
La note la plus importante est que, au bas de l’extrait de code, c’est print drupal_render_children($form)ce qui fait que le formulaire se comporte réellement :).
Chris Rockwell
Bonne réponse. Je peux ajouter que vous devez spécifier en plus engine, si vous utilisez quelque chose qui n'est pas par défaut. Par exemple 'engine' => 'twig'.
milkovsky
1
Bonne réponse. Gardez à l'esprit si vous souhaitez créer un thème pour un formulaire d'administration tel que user_profile_formou user_register_form. Dans ce scénario, vous devrez soit a) faire votre thème dans le thème administrateur (ou un sous-thème de celui-ci si vous ne pouvez pas changer le thème administrateur de base), ou b) placer votre thème dans un module personnalisé. Sinon, votre thématisation ne sera pas vue.
therobyouknow
18

Vous devez implémenter hook_form_alter () dans un module ou template.php et définir la propriété #theme du formulaire :

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

Puis implémentez le nouveau thème:

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

Et ajoutez ensuite le formulaire - user_login.tpl.php template avec le code suivant pour rendre le formulaire:

<?php print drupal_render_children($form) ?> 
mrded
la source
1
La #themepropriété est tellement simple et est mentionnée pour la première fois dans les réponses, très bizarre. C'est définitivement ma méthode préférée.
Matt Fletcher
1
J'ai testé ce code et cela fonctionne comme prévu.
VladSavitsky
14

Même si vous pouvez utiliser la solution de kiamlaluno, je ne le ferais pas personnellement.

Quelle est la raison pour laquelle vous avez besoin d'un fichier modèle pour un formulaire? Si c'est parce que vous voulez un balisage légèrement différent pour un formulaire existant? Si c'est le cas, vous pouvez utiliser hook_form_alter()pour modifier le formulaire avant son rendu. En utilisant l'API de formulaire, vous pouvez modifier tous les champs de formulaire, y injecter des éléments HTML, etc.

Voici un exemple de hook_form_alter()ce que j'ai créé qui modifie le bloc de formulaire de connexion drupal standard:

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

L'exemple ci-dessus englobe la totalité du formulaire dans une DIV, qui possède un style en ligne pour transformer la couleur d'arrière-plan en rouge. Il ajoute également un paragraphe de texte d'aide au début du formulaire.

Voici à quoi ressemble mon formulaire de connexion utilisateur une fois que le code ci-dessus est chargé:

Formulaire de connexion personnalisé

Voir la référence de l'API de formulaire pour plus d'informations: Référence de l'API de formulaire

Camsoft
la source
1
Juste pour clarifier l'utilisation de styles en ligne dans cet exemple, c'est simplement pour simplifier l'exemple. Je ne recommande pas d'utiliser des styles en ligne et vous devriez utiliser des classes.
Camsoft
Je ne prends pas en charge l'utilisation d'un fichier de modèle pour le rendu d'un formulaire; en fait, j'ai également dit que je n'ai jamais utilisé de fichier de modèle pour rendre un formulaire (j'ai en fait changé le code d'un module qui utilisait un fichier de modèle pour un formulaire), et que Drupal n'utilise pas de modèle fichiers pour rendre les formulaires.
kiamlaluno
5
Que faire si vous souhaitez modifier radicalement le balisage? Parfois, un fichier de modèle est une meilleure option.
Cossovich
6
Le balisage dans un générateur de logique de formulaire dégage une odeur.
Charlie Schliesser le
1
Bien que cette solution fonctionne dans la plupart des cas, elle peut en réalité se rompre lorsque le rendu du formulaire est actualisé dans un rappel ajax
PatrickS
13

En réalité, je n'ai jamais eu besoin d'utiliser un fichier de modèle pour un formulaire.
Autant que je sache, le code principal de Drupal utilise des fonctions de thème, lorsqu'un formulaire ou une partie d'un formulaire doit être restitué de manière particulière. une fonction de thème qui appelle drupal_render () suffit normalement à quelque fin que ce soit.

Pour répondre à la question, la création d'un fichier de modèle pour un formulaire ne diffère pas de la création d'un fichier de modèle non destiné à un formulaire.

Définissez une fonction de thème en utilisant comme fonction de thème le nom du rappel du générateur de formulaire. Le code devrait ressembler à ceci:

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

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

Si le formulaire contient la valeur $form['field_1'], sa valeur sera disponible dans le fichier modèle en tant que $field_1. Le fichier modèle pourra également utiliser toutes les valeurs transmises template_preprocess_mymodule_form().

kiamlaluno
la source
Comment suggérer un formulaire défini par d'autres modules, éventuellement des modules de base pour utiliser ma fonction / modèle de thème?
Shafiul
Ensemble $form['#theme'].
kiamlaluno
1
Ne fonctionne pas, lorsque je soumets le formulaire, il ne passe pas à la fonction
form_submit
1

Je stylerais toujours en ajoutant à mon fichier CSS à l'aide de sélecteurs pour identifier l'élément à styler comme suit pour le formulaire de connexion 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;
}

Ce que j'ajoute simplement à sites/all/themes/theme-name/css/theme-name.css

Si ce que vous devez styler n'a pas d'identifiant ou de sélecteur suffisamment précis, il est nécessaire d'utiliser l' hookapproche pour modifier le code HTML et ajouter des identifiants.

OMI en ligne en utilisant le style des éléments est une très mauvaise pratique qui devrait être dépréciée et remplacé par l' utilisation de classetid

Richard Harrison
la source
0

Pour thématiser un formulaire, vous pouvez utiliser un fichier CSS personnalisé, comme expliqué dans la section Traitement de formulaires Drupal 7 (y compris CSS et JS) .

Fondamentalement, vous devez effectuer ces étapes:

  1. Enregistrez un chemin d'accès au formulaire en utilisant hook_menu ()
  2. Définir le formulaire
  3. Enregistrez une fonction de thème avec hook_theme ()
  4. Écrire la fonction thème
  5. Créer les fichiers CSS et JavaScript
Shasi Kanth
la source
-2

Je suis presque sûr que vous pouvez utiliser un modèle pour les formulaires, mais vous devez utiliser hook_theme pour enregistrer le modèle en premier lieu. J'ai eu une situation où le formulaire devait vraiment être basé sur une table plutôt que sur une div et où les changements simples de préfixe # et préfixe # ne suffiraient pas vraiment. Si cela m'intéresse, je pourrais probablement essayer de trouver un exemple.

Malks
la source