¿Emitir una anulación html.tpl.php desde un módulo?

8

¿Hay alguna forma de anular el resultado de una página desde un módulo contribuido y emitir su propio html.tpl.php, tomando efectivamente el control del resultado del tema?

Quiero hacer esto en un esfuerzo por crear una experiencia única de inicio de sesión / registro, pero parece que solo puede anular la plantilla de nivel de página, no la plantilla de nivel html. Veo que el módulo de impresión hace esto, pero ¿es esa la forma de abordarlo?

Kevin
fuente
No tengo tiempo para desarrollarlo en este momento, pero creo que podría usarlo hook_menu_alter()para cambiar la delivery callbackruta del usuario / inicio de sesión a su propia versión de drupal_deliver_html_page(). Eso debería darle un control absoluto sobre lo que se muestra en la pantalla, aunque significará configurar los encabezados apropiados usted mismo
Clive
Sí, ahí es donde comencé a dirigirme, pero no estaba seguro de si tendrías que hacer todo ese trabajo preliminar.
Kevin
No estoy seguro de que hay una forma redonda que sea honesto, un buen ejemplo de núcleo es la ajax_deliver()función, que recibe el mismo $page_callback_resultcomo drupal_html_deliver_page()pero los procesos de manera diferente. No estoy seguro de si puede interrumpir el proceso más adelante de manera significativa antes de que el motor del tema se involucre
Clive
¿Hay alguna razón específica para alterar la salida de html.tpl.php? Hay muchas funciones que alteran el resultado de ese archivo de plantilla.
kiamlaluno
@kiamlaluno, esta es una pregunta interesante. También estoy encontrando una manera de detener la representación de la página de Drupal antes de que el motor de temas se involucre. El propósito es renderizar una página (algún tipo de servicio web) al igual que la salida JSON o lo que sea proporcionado por Views Datasource cuando using_views_api_modeestá APAGADO.
Sithu

Respuestas:

4

Según esta respuesta , puede simplemente imprimir el contenido de la página en la devolución de llamada de la página del menú en lugar de devolverlo.

Para obtener datos de la base de datos de Drupal y / o producidos en PHP, necesita una devolución de llamada de página (en un módulo personalizado) que muestre los datos sin la representación completa del diseño. Esto se puede hacer fácilmente imprimiendo el contenido de la página directamente en la devolución de llamada de su página en lugar de devolverlo.

Supongo que el módulo Imprimir implementó la página para imprimir de esta manera. El siguiente es el fragmento de código del módulo.

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

De acuerdo con esto, el módulo utiliza la plantilla HTML personalizada print.tpl.php. Es una plantilla de nivel HTML. Luego, el módulo obtiene el HTML mediante una llamada theme('print',...)y lo procesa directamente en el navegador mediante print $html;.

Aquí hay una idea general para su propósito: 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;
} 

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

Espero que esto personalice su página de inicio de sesión según lo necesite.

Sithu
fuente
2

Tanto @Sithu como @Ayesh K han proporcionado excelentes respuestas. En este ejemplo, combinaré el método de @ Ayesh y partes del código de @ Sithu para obtener una solución completa.

Las funciones hooks_menu o hook_menu_alter proporcionan una delivery callback, que instruye a Drupal sobre cómo desea que se envuelva su código. Por defecto, Drupal se establece delivery callbacken drupal_deliver_html_page () , lo que le dice a Drupal que ajuste su página html.tpl.phpy page.tpl.php.

Para modificar la forma en que Drupal envuelve su página, copie la función drupal_deliver_html_page()en su módulo y modifíquela. Luego llame a su nueva función en delivery callback. Drupal luego usará esa función para ajustar su página.

Ejemplo

Aquí hay un módulo de trabajo. Coloque el siguiente código en su /sites/all/modules/MYMODULEdirectorio y habilite el módulo.

Opcionalmente, para anular una ruta existente, sustituir 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; }
timofey.com
fuente
Pregunta: ¿este ejemplo funciona con el sistema de almacenamiento en caché de Drupal, y tendría cachés separados para diferentes cadenas de consulta?
Darvanen
Creo que, por defecto, Drupal almacena en caché el formulario y la página, respectivamente. No estoy seguro de ningún otro proceso de almacenamiento en caché.
timofey.com
Gracias. Terminé haciendo un caché personalizado para las respuestas de mi página usando la API.
Darvanen
1

Creo que necesitas invertir algo de tiempo para encontrar el gancho más apropiado para esto. Puedes probar

  • hook_page_alter para cambiar "lo que se va a representar",

  • use hook_menu_alter para cambiar la devolución de llamada de entrega para iniciar sesión y registrar enrutadores de menú,

  • use una página - archivo user-login.tpl.php para hacerse cargo de la plantilla de página de la página de inicio de sesión,

  • agregue algunas sugerencias de plantillas en template.php para usar un archivo html.tpl.php diferente solo para las rutas de inicio de sesión,

  • o finalmente, hook_theme_regitry_alter , para alterar el registro de temas y hacer lo que quería hacer (el cambio html.tpl.php)

AyeshK
fuente
+1 Spot on! hook_theme_registry_alter()es posible que no funcione, ya que lo más probable es que cambie la plantilla para todas las páginas, pero delivery callbackdefinitivamente funcionará. También he explorado este método en mi respuesta, aquí.
timofey.com