Emitir uma substituição html.tpl.php de um módulo?

8

Existe uma maneira de substituir a saída de uma página de um módulo contribuído e emitir seu próprio html.tpl.php, efetivamente assumindo o controle da saída do tema?

Quero fazer isso com esforço para criar uma experiência única de logon / registro, mas apenas parece substituir o modelo no nível da página, não no modelo no nível html. Vejo que o módulo de impressão faz isso, mas é essa a maneira de abordá-lo?

Kevin
fonte
Não tenho tempo para detalhar agora, mas acho que você poderia usar hook_menu_alter()para alterar o delivery callbackcaminho do usuário / login para sua própria versão do drupal_deliver_html_page(). Isso deve lhe dar controle absoluto sobre o que é renderizado na tela, embora signifique definir os cabeçalhos apropriados
Clive
Sim, foi para lá que eu comecei a dirigir, mas não tinha certeza se você precisaria fazer todo esse trabalho braçal.
Kevin
Não tenho certeza de que haja uma maneira de ser honesto, um bom exemplo do núcleo é a ajax_deliver()função, que fica igual $page_callback_result, drupal_html_deliver_page()mas a processa de maneira diferente. Não tenho certeza se você pode interromper o processo de maneira significativa antes que o mecanismo do tema seja envolvido
Clive
Existe algum motivo específico para alterar a saída do html.tpl.php? Existem muitas funções que alteram o resultado desse arquivo de modelo.
kiamlaluno
@kiamlaluno, esta é uma pergunta interessante. Também estou encontrando uma maneira de interromper a renderização da página do Drupal antes que o mecanismo do tema seja envolvido. O objetivo é renderizar uma página (algum tipo de serviço da web) exatamente como a saída JSON ou o que for fornecido pelo Views Datasource quando using_views_api_modeestiver desativado.
Sithu

Respostas:

4

De acordo com esta resposta , você pode simplesmente imprimir o conteúdo da página no retorno de chamada da página de menu, em vez de retorná-lo.

Para obter dados do banco de dados do Drupal e / ou produzido em PHP, você precisa de um retorno de chamada de página (em um módulo personalizado) que produza os dados sem a renderização completa do layout. Isso é facilmente possível imprimindo o conteúdo da página diretamente no retorno de chamada da página, em vez de devolvê-lo.

Acho que o módulo Imprimir implementou a página de impressão dessa maneira. A seguir está o trecho de código do 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 acordo com isso, o módulo usa o modelo HTML personalizado print.tpl.php. É um modelo no nível HTML. O módulo obtém o HTML chamando theme('print',...)e o renderiza diretamente no navegador usando print $html;.

Aqui está uma ideia geral para seu objetivo: 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;
} 

Predefinição: 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 isso personalize sua página de login conforme necessário.

Sithu
fonte
2

Tanto o @Sithu quanto o @Ayesh K forneceram ótimas respostas. Neste exemplo, combinarei o método do @ Ayesh e partes do código do @ Sithu para obter uma solução completa.

As funções hooks_menu ou hook_menu_alter fornecem a delivery callback, que instrui o Drupal sobre como você deseja que seu código seja agrupado . Por padrão, o Drupal define delivery callbackcomo drupal_deliver_html_page () , que aproximadamente informa ao Drupal para agrupar sua página html.tpl.phpe page.tpl.php.

Para modificar a maneira como o Drupal agrupa sua página, copie a função drupal_deliver_html_page()no seu módulo e modifique-a. Em seguida, chame sua nova função delivery callback. O Drupal usará essa função para quebrar sua página.

Exemplo

Aqui está um módulo de trabalho. Coloque o seguinte código em seu /sites/all/modules/MYMODULEdiretório e ative o módulo.

Opcionalmente, para substituir um caminho existente, substitua hook_menupor 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
fonte
Pergunta: este exemplo funciona com o sistema de cache do Drupal e teria caches separados para diferentes cadeias de consulta?
Darvanen
Eu acredito que, por padrão, o Drupal armazena em cache o formulário e a página, respectivamente. Não tenho certeza de outros processos de armazenamento em cache.
timofey.com
Obrigado. Acabei criando um cache personalizado para as respostas da minha página usando a API.
precisa saber é o seguinte
1

Eu acho que você precisa investir algum tempo para encontrar o gancho mais apropriado para isso. Podes tentar

  • hook_page_alter para alterar "o que será processado",

  • use hook_menu_alter para alterar o retorno de chamada de entrega para fazer login e registrar roteadores de menu,

  • use uma página - arquivo user-login.tpl.php para assumir o modelo de página da página de login,

  • adicione algumas sugestões de modelos em template.php para usar um arquivo html.tpl.php diferente apenas para os caminhos de login,

  • ou, finalmente, hook_theme_regitry_alter , para alterar o registro do tema e fazer o que você queria fazer (a alteração html.tpl.php)

AyeshK
fonte
+1 Spot on! hook_theme_registry_alter()pode não funcionar, pois provavelmente mudará o modelo para todas as páginas, mas delivery callbackdefinitivamente funcionará. Além disso, eu explorei esse método na minha resposta aqui.
timofey.com