Emettere un override html.tpl.php da un modulo?


8

C'è un modo per sovrascrivere l'output di una pagina da un modulo contribuito ed emettere il proprio html.tpl.php, prendendo effettivamente il controllo dell'output dal tema?

Voglio fare questo nel tentativo di creare un'esperienza unica di accesso / registrazione, ma sembra solo che possa sovrascrivere il modello a livello di pagina, non il modello a livello html. Vedo che il modulo di stampa fa questo, ma è questo il modo di affrontarlo?


Non ho tempo per dargli una risposta in questo momento, ma penso che potresti usarlo hook_menu_alter()per cambiare il percorso delivery callbackper l'utente / login con la tua versione di drupal_deliver_html_page(). Ciò dovrebbe darti il ​​controllo assoluto su ciò che viene visualizzato sullo schermo, sebbene ciò significhi impostare personalmente le intestazioni appropriate
Clive

Sì, è lì che ho iniziato a dirigermi, ma non ero sicuro che avresti dovuto fare tutto quel lavoro di gambe.
Kevin

Non sono sicuro che c'è un modo intorno ad esso ad essere onesti, un buon esempio dal nucleo è la ajax_deliver()funzione, che ottiene lo stesso $page_callback_resultcome drupal_html_deliver_page(), ma i processi in modo diverso. Non sono sicuro di poter interrompere ulteriormente il processo in modo significativo prima che il motore del tema venga coinvolto
Clive

C'è un motivo specifico per modificare l'output di html.tpl.php? Esistono molte funzioni che alterano ciò che quel file modello genera.
kiamlaluno

@kiamlaluno, Questa è una domanda interessante. Sto anche trovando un modo per interrompere il rendering della pagina Drupal prima che il motore del tema venga coinvolto. Lo scopo è di rendere una pagina (una sorta di servizio web) proprio come l'output JSON o qualsiasi altra cosa fornita da Views Datasource quando using_views_api_modeè OFF.
Sithu,

Risposte:


4

Secondo questa risposta , è possibile semplicemente stampare il contenuto della pagina nel callback della pagina del menu anziché restituirlo.

Per ottenere dati dal database di Drupal e / o prodotti in PHP, è necessario un callback di pagina (in un modulo personalizzato) che emetta i dati senza il rendering completo del layout. Questo è facilmente realizzabile stampando il contenuto della pagina direttamente nel callback della pagina invece di restituirlo.

Immagino che il modulo Stampa abbia implementato la pagina stampabile in questo modo. Di seguito è riportato lo snippet di codice dal modulo.

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

In base a ciò, il modulo utilizza il modello HTML personalizzato print.tpl.php. È un modello a livello HTML. Il modulo quindi ottiene l'HTML chiamando theme('print',...)e lo rende direttamente al browser utilizzando print $html;.

Ecco un'idea generale per il tuo scopo: 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;
} 

Modello: 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>

Spero che questo personalizzi la tua pagina di accesso di cui hai bisogno.


2

Sia @Sithu che @Ayesh K hanno fornito ottime risposte. In questo esempio, combinerò il metodo di @ Ayesh e parti del codice di @ Sithu per una soluzione completa.

Le funzioni hooks_menu o hook_menu_alter forniscono entrambe una delivery callback, che istruisce Drupal su come vuoi che il tuo codice venga spostato. Per impostazione predefinita, Drupal imposta delivery callbacka drupal_deliver_html_page () , che dice più o meno Drupal per avvolgere la tua pagina in html.tpl.phpe page.tpl.php.

Per modificare il modo in cui Drupal avvolge la tua pagina, copia la funzione drupal_deliver_html_page()nel tuo modulo e modificala. Quindi chiama la tua nuova funzione delivery callback. Drupal utilizzerà quindi quella funzione per avvolgere la tua pagina.

Esempio

Ecco un modulo funzionante. Inserire il codice seguente nella /sites/all/modules/MYMODULEdirectory e abilitare il modulo.

Facoltativamente, per sovrascrivere un percorso esistente, sostituirlo hook_menucon 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; }

Domanda: questo esempio funziona con il sistema di memorizzazione nella cache di Drupal e avrebbe cache separate per stringhe di query diverse?
Darvanen,

Credo, per impostazione predefinita, Drupal memorizza nella cache il modulo e la pagina, rispettivamente. Non sono sicuro di altri processi di memorizzazione nella cache.
timofey.com,

Grazie. Ho finito per creare una cache personalizzata per le risposte della mia pagina utilizzando l'API.
Darvanen,

1

Penso che tu abbia bisogno di dedicare un po 'di tempo a trovare l'amo più adatto per questo. Puoi provare

  • hook_page_alter per cambiare "ciò che verrà reso",

  • utilizzare hook_menu_alter per modificare la richiamata di consegna per i router dei menu di accesso e registrazione,

  • usa una pagina - file user-login.tpl.php per assumere il modello di pagina della pagina di accesso,

  • aggiungi alcuni suggerimenti di template in template.php per usare un diverso file html.tpl.php solo per i percorsi di login,

  • o, infine, hook_theme_regitry_alter , per modificare il registro dei temi e fare quello che volevi fare (la modifica di html.tpl.php)


+1 Spot on! hook_theme_registry_alter()potrebbe non funzionare in quanto molto probabilmente cambierà il modello per tutte le pagine, ma delivery callbacksicuramente funzionerà. Ho anche esplorato questo metodo nella mia risposta, qui.
timofey.com
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.