Статьи

HTML5 в Drupal 7

Я давно хотел написать этот пост. Несколько друзей попросили меня объяснить, как сделать HTML5 в Drupal 7 через Twitter . Другой обеспокоенный человек, обнаружив мимолетную ссылку на него в рецензии на книгу , даже написал по электронной почте:

«Я призываю вас начать писать этот пост так же глубоко, как вы объяснили основные принципы 960. Как мне понравилось это читать. Это было похоже на разговор с родственной душой! Это редкая возможность прочитать предысторию о том, почему вещи такие, какие они есть. В моей психической системе, почему это ключевой компонент, чтобы знать, что ты делаешь ».

Итак, без лишних слов, вот оно …


вступление

В дополнение к HTML5, я расскажу, как удалить некоторые из сгенерированных разметок Drupal по умолчанию и как переопределить системный CSS по умолчанию . Я также приведу несколько советов о том, как получить быстрый выигрыш в скорости страницы.

Прежде чем мы углубимся в это, я просто хотел упомянуть, что это не будет всеобъемлющим руководством по созданию темы Drupal 7. Для краткости я не буду рассказывать о модуле HTML5 Tools , который пытается добавить в Drupal такие функции, как новые элементы формы HTML5. Вместо этого я сосредоточусь на устранении перенасыщения XHTML, которое Drupal все еще инстинктивно хочет включить, исходя из своих ранних дней.

Помните — еще до того, как W3C объявил, что XHTML 2.0 мертв , он объявил HTML5 будущим — когда мы все привыкли помещать type = «text / css» в теги, как если бы мы когда-либо использовали тег <style>, который не был CSS ? О, как мы были глупы! И все же мы думали, что мы такие крутые, умиротворяющие валидатора . Затем появился HTML5 , вымощив коровников, разоблачая утомительное множество практик, которые мы когда-то считали необходимыми.


Состав

Когда вы впервые установите Drupal, вы увидите каталог верхнего уровня с именем themes . Здравый смысл скажет вам, что именно здесь вы должны хранить собственные файлы, связанные с темой. В этом случае здравый смысл не прав ! В действительности каталог, в котором вы хотите играть, это сайты . Это все о вас и вашем конкретном сайте (ах), и там есть еще один каталог тем, в котором будут размещены ваши темы.

Примечание: Drupal может обрабатывать несколько доменов через одну кодовую базу, следовательно, каталог «sites» вместо «site», но это выходит за рамки данной статьи. Если вам интересно, есть группа Multisite Drupal, посвященная этой теме.

Drupal 7 - тематическая структура

Первое, что вы должны сделать, это создать файл * .info с названием вашей темы. Поскольку мой сайт — sonspring.com, а моя тема называется «SonSpring», мой информационный файл — sonspring.info . Вот содержимое (”;” комментирует строку)…

; BASIC SETTINGS
name = SonSpring
core = 7.x

; FEATURES (intentionally blank)
features[] =

; REGIONS
regions[front_journal] = front_journal
regions[content] = content
regions[sidebar_first] = sidebar_first
regions[sidebar_second] = sidebar_second
regions = search

; CSS
stylesheets[all][] = assets/css/override/kill/ctools.css
stylesheets[all][] = assets/css/override/kill/field.css
stylesheets[all][] = assets/css/override/kill/node.css
stylesheets[all][] = assets/css/override/kill/system.messages.css
stylesheets[all][] = assets/css/override/kill/system.menus.css
stylesheets[all][] = assets/css/override/kill/user.css
stylesheets[all][] = assets/css/override/kill/views.css
stylesheets[all][] = assets/css/reset.css
stylesheets[all][] = assets/css/override/keep/system.base.css
stylesheets[all][] = assets/css/override/keep/system.theme.css
stylesheets[all][] = assets/css/override/keep/search.css
stylesheets[all][] = assets/css/960_12_col.css
stylesheets[all][] = assets/css/text.css
stylesheets[all][] = assets/css/formalize.css
stylesheets[all][] = assets/css/site.css

; JAVASCRIPT
scripts[] = assets/js/master.min.js

 

агрегирование

Если вы просматривали какие-либо темы Drupal, предыдущий код довольно простой материал, ничего особенного. Одна вещь, которую вы могли заметить, это каталог переопределения . Внутри него две другие директории, убей и сохрани .

Я научился этому трюку у Мортена Бёрча Хайде-Йоргенсена во время одной из его бесед на тему Drupal. Он называет свою папку foad и технику FOAD , сокращенно «F *** Off And Die» — умный способ избавиться от системных CSS- файлов, которые вам не нужны.

Если вы называете один из своих собственных файлов CSS тем же, что и один из значений по умолчанию, Drupal будет включать ваши собственные, а не предоставлять свои собственные. Таким образом, все в каталоге kill — это просто пустой файл, тогда как все в каталоге keep — это файл CSS, который лишь незначительно (если вообще) был изменен по сравнению с его исходными значениями по умолчанию.

Теперь у вас может возникнуть вопрос: зачем вообще нужен каталог хранения , если я повторно использую тот же код, что и файлы по умолчанию, которые он содержит? Вот где это становится интересным. Когда вы перейдете на страницу администратора Performance и включите агрегирование и сжатие файлов CSS , Drupal соберет все свои системные таблицы стилей по умолчанию в один файл, а все ваши таблицы стилей — в другой.

Это глупо. Но с моим каталогом keep я заставляю эти таблицы стилей по умолчанию — вместе с моими таблицами стилей темы — объединять и сжимать в один файл.

Drupal 7 - Производительность


Template.php — Раздел

Назовите это старой привычкой из моих начинающих CMS- дней, использующих Textpattern , но в своих целях я хотел бы знать, в каком «разделе» сайта я нахожусь. По сути, это просто означает, что мне любопытно, каков foobar в следующих сценариях…

http://example.com/foobar

http://example.com/foobar?page=1

http://example.com/foobar/node/search%20term

Итак, в начале моего файла template.php у меня есть простая функция, которая просматривает и захватывает первый фрагмент пути в URL , выполняет простой переход / регистр и возвращает строку, которая становится идентификатором <body>.

<?php

function sonspring_section() {
  $section_path = explode('/', request_uri());
  $section_name = $section_path[1];
  $section_q = strpos($section_name, '?');

  if ($section_q) {
    $section_name = substr($section_name, 0, $section_q);
  }

  switch ($section_name) {
    case '':
      return 'section_home';
      break;
    case 'journal':
      return 'section_journal';
      break;
    case 'about':
      return 'section_about';
      break;
    case 'work':
      return 'section_work';
      break;
    case 'resources':
      return 'section_resources';
      break;
    case 'contact':
      return 'section_contact';
      break;
    case 'search':
      return 'section_search';
      break;
    case 'user':
      return 'section_user';
      break;
    case 'users':
      return 'section_user';
      break;
    case 'filter':
      return 'section_filter';
      break;
    case 'admin':
      return 'section_admin';
      break;
    default:
      return 'section_404';
  }
}

Template.php — Обрезка

В моем файле template.php есть функция sonspring_process_html_tag . Очевидно, что если ваша тема называется «MyTheme», то ваша функция будет называться mytheme_process_html_tag . Он просто сбрасывает переменные для типа и атрибутов медиа для тегов style, link и script.

Он также очищает комментарии CDATA, которые когда-либо существовали только для удовлетворения валидатора XHTML , потому что вряд ли кто-либо когда-либо служил XHTML как application / xhtml + xml. В прошлом, несмотря на то, что мы все служили XHTML как text / html, мы все равно прыгали через обручи, добавляя комментарии CDATA. Не так с HTML5.

// Purge needless XHTML stuff.
function sonspring_process_html_tag(&$vars) {
  $el = &$vars['element'];

  // Remove type="..." and CDATA prefix/suffix.
  unset($el['#attributes']['type'], $el['#value_prefix'], $el['#value_suffix']);

  // Remove media="all" but leave others unaffected.
  if (isset($el['#attributes']['media']) && $el['#attributes']['media'] === 'all') {
    unset($el['#attributes']['media']);
  }

В действительности XHTML всегда работал без лишнего кода. HTML5 просто делает его официальным. Для сравнения, здесь есть до и после того, что Drupal обычно выводит по умолчанию, после чего следует уменьшенный результат.

До — XHTML

<link rel="stylesheet" href="..." type="text/css" media="all" />

<style type="text/css" media="all">
/* Code here. */
</style>

<script type="text/javascript">
<!--//--><![CDATA[//><!--
/* Code here. */
//--><!]]>
</script>

 После — HTML5

<link rel="stylesheet" href="..." />

<style>
/* Code here. */
</style>

<script>
/* Code here. */
</script>

Template.php — Минификация

Хотя это не относится непосредственно к HTML5, я решил, что пока я копаюсь в файле template.php , я мог бы также добавить некоторое минимизацию HTML . По сути, следующий код просто удаляет ненужные пробелы и разрывы строк, сохраняя немного размер файла, где это возможно. Если страница содержит тег <pre> или <textarea>, он остается один, чтобы не затрагивать блоки кода или текст, введенный в форму.

// Minify HTML output.
function sonspring_process_html(&$vars) {
  $before = array(
    "/>\s\s+/",
    "/\s\s+</",
    "/>\t+</",
    "/\s\s+(?=\w)/",
    "/(?<=\w)\s\s+/"
  );

  $after = array('> ', ' <', '> <', ' ', ' ');

  // Page top.
  $page_top = $vars['page_top'];
  $page_top = preg_replace($before, $after, $page_top);
  $vars['page_top'] = $page_top;

  // Page content.
  if (!preg_match('/<pre|<textarea/', $vars['page'])) {
    $page = $vars['page'];
    $page = preg_replace($before, $after, $page);
    $vars['page'] = $page;
  }

  // Page bottom.
  $page_bottom = $vars['page_bottom'];
  $page_bottom = preg_replace($before, $after, $page_bottom);
  $vars['page_bottom'] = $page_bottom . drupal_get_js('footer');
}

Блок, Поле, Регион, Виды

Хотя технически возможно использовать HTML5 и RDF вместе, я решил просто исключить этот аспект из моих шаблонов, как вы вскоре увидите. Поэтому я просто отключил модуль RDF (включен по умолчанию).

Drupal 7 - Модуль RDF

По большей части Drupal отображает только то, что находится в ваших шаблонах. Но есть несколько областей, в которых есть тенденция оборачивать вещи в теги <div>, которые вам могут не понадобиться. К счастью, система тем Drupal позволяет легко ее исправить. Ниже приведен список файлов, которые я создал, которые содержат только код, необходимый для генерации вашего контента, тем самым переопределяя вывод по умолчанию в Drupal.

Я намеренно пропустил закрывающий тег?>, Потому что рекомендуется (как Drupal, так и Zend ) не закрывать тег <? Php. Вместо этого синтаксический анализатор понимает, что код PHP закончен, когда он достиг конца файла. Это предотвращает непреднамеренное внедрение пробелов в страницу. (Излишне говорить, что?> Все еще необходимо при смешивании PHP и HTML в одном файле.)

Примечание. Шаблоны, начинающиеся с «views-», относятся к Views , стороннему модулю Drupal, который позволяет легко выводить списки содержимого на основе различных критериев.

block.tpl.php

<?php print $content;

Примечание: я удалил $ item_attributes из моего файла field.tpl.php . Это используется модулем RDF и потенциально может использоваться сторонними модулями для добавления таких вещей, как onclick = «…» к различным элементам. Я удалил его, потому что я не использую модуль RDF , но ваш пробег может отличаться — читайте дальше .

field.tpl.php

<?php print render($items);

region.tpl.php

<?php print $content;

просмотры-view.tpl.php

<?php

// Shorthand for if, then print.
// I write PHP like a JS hacker.
// Pager at the top, and bottom.

isset($admin_links) && print $admin_links;
$header && print $header;
$exposed && print $exposed;
$attachment_before && print $attachment_before;
$pager && print $pager;
$rows ? print $rows : $empty && print $empty;
$pager && print $pager;
$attachment_after && print $attachment_after;
$more && print $more;
$footer && print $footer;
$feed_icon && print $feed_icon;

просмотры ракурс-unformatted.tpl.php

<?php

$title && print $title;

foreach ($rows as $id => $row) {
  print $row;
}

просмотры ракурс-list.tpl.php

<?php

$title && print $title;

print '<ul class="list">';

foreach ($rows as $id => $row) {
  print '<li>' . $row . '</li>';
}

print '</ul>';

просмотры ракурс-fields.tpl.php

<?php

foreach ($fields as $id => $field) {
  if (isset($field->separator)) {
    print $field->separator;
  }

  print $field->content;
}

HTML , Page, Node

Хотя вышеупомянутые файлы, относящиеся к блокам , полям , регионам и представлениям, являются технически шаблонами, поскольку они заканчиваются на * .tpl.php , суть системы шаблонов вращается вокруг шаблонов HTML , страниц и узлов.

Ниже я перечислил большую часть кода моего шаблона. Вы можете заметить, что я не включил свой файл page-front.tpl.php . Он в основном жестко запрограммирован, потому что не меняется так часто, единственной динамической частью являются недавние записи в журнале.

html.tpl.php

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta http-equiv="x-ua-compatible" content="ie=edge, chrome=1" />
<title><?php
  if (sonspring_section() === 'section_home') {
    print 'SonSpring by Nathan Smith';
  }
  else {
    print $head_title;
  }
?></title>
<!--[if lt IE 8]>
<script>
window.top.location = 'http://desktop.sonspring.com/ie.html';
</script>
<![endif]-->
<meta name="author" content="Nathan Smith">
<meta name="description" content="Personal and professional home of Christian web designer Nathan Smith." />
<link rel="alternate" type="application/rss+xml" title="SonSpring RSS" href="http://feeds.feedburner.com/sonspring" />
<link rel="shortcut icon" type="image/x-icon" href="/sites/all/themes/sonspring/assets/images/favicon.ico" />
<link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Oswald" />
<?php print $styles; ?>
</head>
<body id="<?php print sonspring_section(); ?>">
<?php
  print $page_top;
  print $page;
  print $scripts;
  print $page_bottom;
?>
<script async="async" src="http://mint.sonspring.com/?js"></script>
</body>
</html>

page.tpl.php

<div id="wrapper">
  <?php include 'assets/includes/header.inc'; ?>
  <div id="main" class="container_12">
    <div class="grid_10">
      <h1><?php print $title; ?></h1>
      <?php $tabs && print render($tabs); ?>
      <div class="grid_7 alpha">
        <?php print render($page['content']); ?>
      </div>
      <div class="grid_3 omega aside">
        <?php $page['sidebar_first'] && print render($page['sidebar_first']); ?>
      </div>
    </div>
    <div class="grid_2 aside">
      <?php
        include 'assets/includes/fusion.inc';
        $page['sidebar_second'] && print render($page['sidebar_second']);
      ?>
    </div>
  </div>
</div>
<?php include 'assets/includes/footer.inc';

страница — search.tpl.php

<div id="wrapper">
  <?php include 'assets/includes/header.inc'; ?>
  <div id="main" class="container_12">
    <div class="grid_10">
      <h1><?php print $title; ?></h1>
      <?php
        $tabs && print render($tabs);
        $page['content'] && print render($page['content']);
      ?>
    </div>
    <div class="grid_2 aside">
      <?php
        include 'assets/includes/fusion.inc';
        $page['sidebar_second'] && print render($page['sidebar_second']);
      ?>
    </div>
  </div>
</div>
<?php include 'assets/includes/footer.inc';

Примечание. В файле node.tpl.php я удалил $ attribute, $ title_attributes и $ content_attributes, используемые для RDF . Для нетронутого node.tpl.phpисточник .

node.tpl.php

<?php
  !empty($content['upload']) && hide($content['upload']);
  !empty($content['taxonomy_vocabulary_1']) && hide($content['taxonomy_vocabulary_1']);
  !empty($content['links']) && hide($content['links']);
?>
<div class="node clearfix">
  <?php if (!$page) { ?>
    <?php print render($title_prefix); ?>
    <h2>
      <a href="<?php print $node_url; ?>"><?php print $title; ?></a>
    </h2>
    <?php print render($title_suffix); ?>
  <?php } ?>
  <?php if ($submitted) { ?>
    <?php if ($page) { ?>
      <div class="g_plus"><div class="g-plusone" data-size="small" data-count="false"></div></div>
    <?php } ?>
    <div class="meta mute">
      <span class="submitted">
        <?php print format_date($node->created); ?>
      </span>
      —
      Topic:
      <?php print render($content['taxonomy_vocabulary_1']); ?>
    </div>
  <?php } ?>
  <?php
    print render($content);
    print render($content['links']);
  ?>
</div>

Включает в себя

Для полноты картины , я понял , что я должен закончить пречисление содержимого моих * .inc файлов, содержащихся внутри включает в себя каталог под активами . Хотя эти файлы можно было так же легко оставить в файлах более высокого уровня * .tpl.php , чтобы упростить их поддержку и поддерживать принципы DRY , я выделил их в свои собственные файлы. Имея расширение файла * .inc , Drupal знает, что запрещает прямой просмотр, поэтому их можно использовать только через включение на страницу PHP .

header.inc

<div id="header">
  <div class="container_12">
    <div class="grid_3" id="ss_logo">
      <?php
        if (!$is_front) {
          print '<a href="/">';
        }

        print '<span>SonSpring</span>';

        if (!$is_front) {
          print '</a>';
        }
      ?>
    </div>
    <div class="grid_7">
      <ul id="nav">
        <li id="nav_journal">
          <a href="/journal">Journal</a>
        </li>
        <li id="nav_about">
          <a href="/about">About</a>
        </li>
        <li id="nav_work">
          <a href="/work">Work</a>
        </li>
        <li id="nav_resources">
          <a href="/resources">Resources</a>
        </li>
        <li id="nav_contact">
          <a href="/contact">Contact</a>
        </li>
      </ul>
    </div>
    <div class="grid_2">
      <?php
        if ($page['search'] && sonspring_section() !== 'section_search') {
          print render($page['search']);
        }
      ?>
    </div>
  </div>
</div>

fusion.inc

<a href="http://fusionads.net/" id="fusion_link">Powered by Fusion Ads</a>
<div id="fusion_ad"><span class="clear"> </span></div>

footer.inc

<div id="footer">
  <div class="container_12">
    <div class="grid_4">
      © <?php print date('Y'); ?> <a href="https://profiles.google.com/sonspring/about">Nathan Smith</a>. All rights reserved.
    </div>
    <div class="grid_4">
      <a href="http://www.firehost.com/?ref=spon_nsmith_sonspring" title="Secure Hosting" id="hosted_by_firehost">Hosted by FireHost</a>
    </div>
    <div class="grid_4 align_right">
      <a href="http://feeds.feedburner.com/sonspring">Subscribe</a> via RSS. Follow me on <a href="http://twitter.com/nathansmith">Twitter</a>.
    </div>
  </div>
</div>

Вывод

Хотя на первый взгляд все это может показаться большим количеством кода, имейте в виду, что это почти вся тема моего сайта (кроме CSS и легкого JavaScript). Как только вы поймете, как это работает, система тем Drupal действительно не так сложна для понимания. Кроме того, вы изучаете настоящий PHP , а не псевдокод.

Я бы не сказал, что Drupal идеален, но он предлагает расширяемость с помощью простых переопределений. Безусловно, это наиболее интуитивный подход, который я нашел в своем извилистом поиске идеальной CMS . Надеемся, что это пошаговое руководство помогло развеять миф о том, что кривая обучения в Drupal «крута» или, по крайней мере, сделала процесс менее пугающим.