Émettre un remplacement html.tpl.php à partir d'un module?

8

Existe-t-il un moyen de remplacer la sortie d'une page d'un module contribué et d'émettre votre propre html.tpl.php, en prenant effectivement le contrôle de la sortie du thème?

Je veux le faire dans le but de créer une expérience de connexion / d'enregistrement unique, mais ne semble que remplacer le modèle de niveau de page, pas le modèle de niveau html. Je vois que le module d'impression fait cela, mais est-ce la façon de l'aborder?

Kevin
la source
Je n'ai pas le temps de l'étoffer en ce moment, mais je pense que vous pouvez utiliser hook_menu_alter()pour changer le delivery callbackchemin d'accès utilisateur / connexion à votre propre version de drupal_deliver_html_page(). Cela devrait vous donner un contrôle absolu sur ce qui est rendu à l'écran, même si cela signifie que vous devez définir vous-même les en-têtes appropriés
Clive
Oui, c'est là que j'ai commencé à me diriger, mais je ne savais pas si vous auriez besoin de faire tout ce travail de jambes.
Kevin
Je ne suis pas sûr qu'il ya un moyen de contourner ce pour être honnête, un bon exemple de base est la ajax_deliver()fonction, qui obtient la même $page_callback_resultque drupal_html_deliver_page()mais les processus différemment. Je ne sais pas si vous pouvez interrompre le processus de manière significative avant que le moteur de thème ne s'implique
Clive
Y a-t-il une raison spécifique pour modifier la sortie de html.tpl.php? Il existe de nombreuses fonctions qui modifient la sortie de ce fichier modèle.
kiamlaluno
@kiamlaluno, Ceci est une question intéressante. Je trouve également un moyen d'arrêter le rendu de la page Drupal avant que le moteur de thème ne soit impliqué. Le but est de rendre une page (une sorte de service Web) exactement comme la sortie JSON ou tout ce qui est fourni par Views Datasource lorsqu'il using_views_api_modeest désactivé.
Sithu

Réponses:

4

Selon cette réponse , vous pouvez simplement imprimer le contenu de la page dans le rappel de la page de menu plutôt que de le renvoyer.

Pour obtenir des données de la base de données Drupal et / ou produites en PHP, vous avez besoin d'un rappel de page (dans un module personnalisé) qui génère les données sans le rendu de mise en page complet. Ceci est facilement réalisable en imprimant le contenu de la page directement dans votre rappel de page au lieu de le renvoyer.

Je suppose que le module d' impression a implémenté la page imprimable de cette façon. Voici l'extrait de code du module.

function print_menu() {
  $items = array();

  $items[PRINT_PATH] = array(
    'title' => 'Printer-friendly',
    'page callback' => 'print_controller_html',
    'access arguments' => array('access print'),
    'type' => MENU_CALLBACK,
    'file' => 'print.pages.inc',
  );
  ........   
}   

/**
 * Generate an HTML version of the printer-friendly page
 *
 * @see print_controller()
 */
function print_controller_html() {
  $args = func_get_args();
  $path = filter_xss(implode('/', $args));
  $cid = isset($_GET['comment']) ? (int)$_GET['comment'] : NULL;

  // Handle the query
  $query = $_GET;
  unset($query['q']);

  $print = print_controller($path, $query, $cid, PRINT_HTML_FORMAT);
  if ($print !== FALSE) {
    $node = $print['node'];
    $html = theme('print', array('print' => $print, 'type' => PRINT_HTML_FORMAT, 'node' => $node));
    drupal_add_http_header('Content-Type', 'text/html; charset=utf-8');
    drupal_send_headers();
    print $html;
    ......
}

Selon cela, le module utilise le modèle HTML personnalisé print.tpl.php. Il s'agit d'un modèle de niveau HTML. Le module récupère ensuite le code HTML en appelant theme('print',...)et le restitue directement au navigateur à l'aide print $html;.

Voici une idée générale pour votre objectif: mymodule.module

/**
 * Implements hook_menu().
 */
function mymodule_menu() {
  $items = array();
  $items['mylogin'] = array(
    'title' => 'Custom Login Page',
    'page callback' => 'mymodule_custom_login_page',
    'type' => MENU_CALLBACK,
    'access callback' => TRUE,
  );

  return $items;
} 
/**
 * Implements hook_theme().
 */
function mymodule_theme() {
  return array(
    'mylogin' => array(
      'variables' => array('page' => array()),
      'template' => 'mylogin', // mylogin.tpl.php in your module folder
    ),
  );
}
/**
 * Generate a custom login page
 * @see more in print_controller_html() in print.pages.inc of the Print module 
 */
function mymodule_custom_login_page(){
    $page = _mymodule_login_page_prerequisite(); // get/prepare necessary variables, js, css for the page
    $page['form'] = drupal_render(drupal_get_form('user_login')); // get login form
    // prepare html in mylogin.tpl.php
    // See more in print.tpl.php() in the Print module  
    $html = theme('mylogin', array('page' => $page)); 

    drupal_add_http_header('Content-Type', 'text/html; charset=utf-8');
    drupal_send_headers();
    print $html; // cease Drupal page rendering and render directly to the browser
} 
/**
 * Prepare the array for the template with common details
 * @see more _print_var_generator() in print.pages.inc of the Print module
 */
function _mymodule_login_page_prerequisite(){
    global $base_url, $language; 
    $page = array();
    $page['language']   = $language->language;
    $page['head']       = drupal_get_html_head();
    $page['title']      = '';
    $page['scripts']    = drupal_get_js();
    $page['favicon']    = '';
    // if there is a custom css file for this page
    // drupal_add_css(drupal_get_path('module', 'mymodule') . '/css/mylogin.css');
    $page['css'] = drupal_get_css();
    $page['message'] = drupal_get_messages();
    $page['footer_scripts'] = drupal_get_js('footer');

    return $page;
} 

Modèle: mylogin.tpl.php

<?php
/**
 * @file
 * Custom login page template
 *
 * @ingroup page
 */
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="<?php print $page['language']; ?>" xml:lang="<?php print $page['language']; ?>">
  <head>
    <?php print $page['head']; ?>
    <title><?php print $page['title']; ?></title>
    <?php print $page['scripts']; ?>
    <?php print $page['favicon']; ?>
    <?php print $page['css']; ?>
  </head>
  <body>
    <h3>This is custom login page.</h3>
    <?php 
    if (!empty($page['message'])):
        foreach($page['message'] as $type => $message):
        ?>
            <div class="messages <?php print $type; ?>">
                <ul>
                <?php foreach($message as $msg): ?>
                    <li><?php print $msg; ?></li>
                <?php endforeach; ?>
                </ul>
            </div>
        <?php
        endforeach;
    endif; ?>
    <div><?php print $page['form']; ?></div>
    <?php print $page['footer_scripts']; ?>
  </body>
</html>

J'espère que cela personnalisera votre page de connexion selon vos besoins.

Sithu
la source
2

Les deux @Sithu et @Ayesh K ont fourni de grandes réponses. Dans cet exemple, je combinerai la méthode de @ Ayesh et des parties du code de @ Sithu pour une solution complète.

Les fonctions hooks_menu ou hook_menu_alter fournissent toutes deux un delivery callback, qui indique à Drupal comment vous voulez que votre code soit encapsulé . Par défaut, Drupal met delivery callbackà drupal_deliver_html_page () , qui dit à peu près Drupal pour envelopper votre page html.tpl.phpet page.tpl.php.

Pour modifier la façon dont Drupal enveloppe votre page, copiez la fonction drupal_deliver_html_page()dans votre module et modifiez-la. Appelez ensuite votre nouvelle fonction dans delivery callback. Drupal utilisera alors cette fonction pour envelopper votre page.

Exemple

Voici un module de travail. Placez le code suivant dans votre /sites/all/modules/MYMODULErépertoire et activez le module.

Facultativement, pour remplacer un chemin existant, remplacez hook_menupar hook_menu_alter.

MYMODULE.module

<?php
function MYMODULE_menu() {
  $items['login'] = array(
    'title' => 'Login',
    'page callback' => 'MYMODULE_page',
    'delivery callback' => 'MYMODULE_deliver',
    'access callback' => TRUE,
  );
  return $items;
}

function MYMODULE_page() {
  global $user;
  if (!$user->uid) return drupal_get_form('user_login'); // Show login for guests.
  else drupal_goto('user/' . $user->uid); // Redirect members to own profile.
}

// Code taken from drupal_deliver_html_page().
function MYMODULE_deliver($page_callback_result) {
  global $language, $base_path;
  // Pass variables to the template.
  $vars = array(
    'language' => $language->language,
    'title' => 'My Custom Login',
    'favicon' => '',
    'css' => $base_path . drupal_get_path('module', 'MYMODULE') . '/MYMODULE.css',
    'messages' => theme_status_messages(array('display' => NULL)),
    'content' => drupal_render($page_callback_result),
  );
  echo theme('MYMODULE_login', array('vars' => $vars)); // Uses template defined in hook_theme().
  drupal_page_footer();
}

function MYMODULE_theme() {
  $items['MYMODULE_login'] = array(
    'template' => 'MYMODULE',
    'render element' => 'page',
  );
  return $items;
}

MYMODULE.info

name = MYMODULE
description = "Module description."
package = Custom
core = 7.x

MYMODULE.tpl.php

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.0//EN" "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="<?php print $vars['language']; ?>" version="XHTML+RDFa 1.0">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <title><?php print $vars['title']; ?></title>
  <?php print $vars['favicon']; ?>
  <link rel="stylesheet" type="text/css" href="<?php print $vars['css']; ?>">
</head>
<body>
  <?php echo $vars['messages']; ?>
  <div class="content">
    <?php print $vars['content']; ?>
  </div>
</body>
</html>

MYMODULE.css

.content { color: pink; }
timofey.com
la source
Question: cet exemple fonctionne-t-il avec le système de mise en cache de Drupal et aurait-il des caches séparés pour différentes chaînes de requête?
Darvanen
Je crois que, par défaut, Drupal met en cache le formulaire et la page, respectivement. Je ne suis sûr d'aucun autre processus de mise en cache.
timofey.com
Merci. J'ai fini par créer un cache personnalisé pour mes réponses de page en utilisant l'API.
Darvanen
1

Je pense que vous devez investir un peu de temps pour trouver le crochet le plus approprié pour cela. Tu peux essayer

  • hook_page_alter pour changer "ce qui va être rendu",

  • utilisez hook_menu_alter pour modifier le rappel de livraison pour les routeurs de menu de connexion et d'enregistrement,

  • utiliser un fichier page - user-login.tpl.php pour reprendre le modèle de page de la page de connexion,

  • ajoutez quelques suggestions de modèles dans template.php pour utiliser un fichier html.tpl.php différent juste pour les chemins de connexion,

  • ou enfin, hook_theme_regitry_alter , pour modifier le registre des thèmes et faire ce que vous vouliez faire (le changement html.tpl.php)

AyeshK
la source
+1 Spot on! hook_theme_registry_alter()pourrait ne pas fonctionner car cela changera très probablement le modèle pour toutes les pages, mais delivery callbackcela fonctionnera certainement. J'ai également exploré cette méthode dans ma réponse, ici.
timofey.com