从模块发出html.tpl.php覆盖?


8

有没有一种方法可以覆盖来自贡献模块的页面输出并发出自己的html.tpl.php,从而有效地控制主题的输出?

我想这样做是为了创建独特的登录/注册体验,但似乎只能覆盖页面级别模板,而不是html级别模板。我看到打印模块可以做到这一点,但这是解决问题的方法吗?


我现在没有时间充实它,但是我认为您可以用来将用户/登录路径hook_menu_alter()更改delivery callback为您自己的版本drupal_deliver_html_page()。尽管这将意味着您自己设置适当的标题,但应该可以完全控制屏幕上呈现的内容
Clive

是的,那是我开始前往的地方,但是不确定您是否需要做所有这些工作。
凯文

我不知道有一个捷径可走的,说实话,从核心的一个很好的例子就是ajax_deliver()函数,得到相同$page_callback_resultdrupal_html_deliver_page(),但不同的过程吧。我不确定您是否可以在主题引擎参与之前以有意义的方式进一步中断该过程
Clive

是否有任何特定原因更改html.tpl.php的输出?有许多功能可以更改模板文件输出的内容。
kiamlaluno

@kiamlaluno,这是一个有趣的问题。我也在寻找一种在主题引擎参与之前停止Drupal页面渲染的方法。目的是呈现页面(某种Web服务),就像JSON输出或在OFF 时由Views Datasource提供的using_views_api_mode内容一样。
锡胡

Answers:


4

根据此答案,您可以简单地在菜单页面回调中打印页面内容,而不返回它。

为了从Drupal的数据库中获取数据和/或用PHP生成数据,您需要一个页面回调(在自定义模块中),该回调无需完整的布局呈现即可输出数据。通过直接在页面回调中打印页面内容而不是返回页面内容,很容易做到这一点。

我猜打印模块以这种方式实现了打印机友好的页面。以下是该模块的代码片段。

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

据此,该模块使用自定义HTML模板print.tpl.php。它是HTML级别的模板。然后,模块通过调用来获取HTML,theme('print',...)并使用将该HTML 直接呈现给浏览器print $html;

这是您所需的一般想法: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;
} 

模板: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>

我希望这将根据需要自定义您的登录页面。


2

无论@Sithu@Ayeshķ提供了极大的答案。在此示例中,我将结合使用@Ayesh的方法和@Sithu的代码部分,以获取完整的解决方案。

hooks_menuhook_menu_alter函数都提供了一个delivery callback,用于指示Drupal如何包装代码。默认情况下,Drupal设置delivery callbackdrupal_deliver_html_page(),这大致告诉Drupal在html.tpl.php和中包装页面page.tpl.php

要修改Drupal包裹页面的方式,请将函数复制drupal_deliver_html_page()到模块中并进行修改。然后在中调用新函数delivery callback。然后,Drupal将使用该功能包装您的页面。

这是一个工作模块。将以下代码放入/sites/all/modules/MYMODULE目录并启用该模块。

任选地,以覆盖现有的路径,代替hook_menuhook_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; }

问:此示例是否可与Drupal的缓存系统一起使用,并且针对不同的查询字符串是否具有单独的缓存?
Darvanen

我相信,默认情况下,Drupal分别缓存表单和页面。我不确定其他任何缓存过程。
timofey.com 2015年

谢谢。我最终使用API​​为页面响应创建了自定义缓存。
Darvanen 2015年

1

我认为您需要花费一些时间来为此找到最合适的挂钩。你可以试试


+1点!hook_theme_registry_alter()可能不起作用,因为它很可能会更改所有页面的模板,但delivery callback肯定会起作用。我还在这里的答案中探讨了这种方法。
timofey.com 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.