Drupal 5: Inny wygląd strony głównej

Tags:

Wstęp

Drupal udostępnia wbudowany tryb wyświetlania aktualności "teaser", który umożliwia w prosty sposób umieścić skróty najnowszych wiadomości na stronie głównej. Jednak domyślny wygląd i układ tego trybu jest mało modny i obecnie rzadko stosowany ze względu na lepsze walory estetyczne jak i praktyczne stylu dwukolumnowego, gdzie skróty kolejnych newsów są ułożone naprzemiennie w 2 kolumnach, przy czym często pierwszy news zajmuje szerokość całej kolumny a dalsze są wyświetlane tylko jako lista linków. W poniższym artykule w skrócie opiszę, jak uzyskać w Drupalu 5 taki efekt jak na stronie głównej IT Lublin (zmiany wykonano na skórce Slash Blue).

Jak rozpoznać teaser?

W naszym poradniku będziemy modyfikować pliki skórki - głównie node.tpl.php i style.css (lub inny np. common.css, jeśli nie wszystkie zmiany w pliku css odnoszą efekt, to sprawdź w źródle strony które z nich są dodawane po dołączeniu pliku style.css).
Na początek jako prosty przykład, jak skonfigurować skórkę by jeden z dodanych do newsa obrazków był w trybie "teaser" wyświetlany w pomniejszeniu? Do tego celu musimy dodać dodatkowy styl, dodawany tylko w trybie teaser. Tryb teaser rozpoznamy po tym, że node nie jest wyświetlane w trybie "page" ($page=0). Nową klasę css dodamy do <div id="node-*" class="node *">:

  1.   <div id="node-<?php print $node->nid; ?>" class="node<?php print ($sticky) ? ' sticky' : ''; print (!$status) ? ' node-unpublished' : '';
  2.   if($page==0) {
  3.     print " teaser-node";
  4.   } ?>" >

Dodana przez nas klasa to teaser-node. Teraz ostylujemy obrazek w node, można to zrobić dla jednej klasy obrazka (wtedy wymagany jest format Pełny HTML przy zapisywaniu newsa), lub znacznik img - tak będzie prościej. W pliku css dodajemy następującą definicję:

  1. .teaser-node img{
  2.   float: left;
  3.   width: 80px;
  4.   max-height: 120px;
  5. }

Teraz obrazek dodany w newsie przed znacznikiem   będzie automatycznie pomniejszany (ale przez styl css - więc nie ograniczymy w ten sposób zużycia łącza!), i umieszczany po lewej stronie. Wyświetlanie pełnego obrazka po kliknięciu, to już zasługa modułu lightbox - nie jest to tematem naszego artykułu.

Newsy w 2 kolumnach

Teraz czas na - pozornie - najtrudniejsze zadanie. Pozornie, ponieważ silnik templatek phptemplate, domyślny w Drupalu, definiuje zmienne $id i $zebra w widokach składających się z wielu elementów (tak jak teaser), w tych zmiennych mamy zawarty numer elementu oraz jego parzystość. Wystarczyłaby ta pierwsza zmienna, lecz istnienie drugiej bardzo upraszcza kod w skórce.

Jak będą wyglądały nasze modyfikacje? Pierwszy element ($id==1) będzie ostylowany bez zmian. Kolejne kilka (parzysta liczba - w naszym przypadku 4), będą po 2 umieszczone w dodatkowych <div class="no-float"></div>, których podstawowym zadaniem będzie "poskromienie" opływania poszczególnych newsów. Poszczególne newsy będą miały naprzemiennie styl float: left/right.

Zaś końcowa zmiana, to po 5 pierwszych skrótach, pozostałe newsy będą wyświetlane jedynie jako linki z pierwszym zdaniem opisu.

Podsumowując:

  1. 1-szy element - pełna szerokość, bez zmian
  2. 2-5 element - pogrupowane w parach w dodatkowych "pojemnikach", porozmieszczane za pomocą float
  3. 6 i kolejne - pełna szerokość, inny styl (mniejsza czcionka), tylko pierwsze zdanie ze skrótu

Uprzednio zmieniana przez nas linijka, uzyska teraz postać (rozszerzając się przy tym do kilku linijek;):

  1. <?
  2.  if ($page==0 and $zebra=='even' and $id>1 and $id<6) {
  3.   print "<div class='no-float'>";
  4.  }
  5.  if ($page==0 and $id>5) {
  6.   // wycinam pierwsze zdanie dla skrótów dalszych newsów
  7.   $nodeclass = ' teaser-shortened';
  8.   // usuwanie znaczników html
  9.   $content = preg_replace('/<[^!][^<>]*>/','',$content);
  10.   if ($tag_position =strpos($content, '<!--short-->')) {
  11.    $content = substr($content, 0, $tag_position);
  12.   } else {
  13.    $content = substr($content, 0, strpos($content, '.'));
  14.   }
  15.   $content = '<i><a href="'.$node_url.'">'.$content.'...</a></i>';
  16.  }
  17.  ?>
  18.  <div id="node-<?php print $node->nid; ?>" class="node<?php print ($sticky) ? ' sticky' : ''; print (!$status) ? ' node-unpublished' : '';
  19.  if($page==0) {
  20.   print " teaser-node";
  21.   print " teaser-".$zebra;
  22.   print " teaser-item-".$id;
  23.   print $nodeclass;
  24.  } ?>" >

W powyższym kodzie, wycinam pierwsze zdanie newsa, do pierwszej kropki. Ze względu na występowanie kropki np. w skrócie ul., dodałem tag <!--short-->, który umożliwia oznaczenie końca pierwszego zdania w dowolnym miejscu (wymagany format Pełny HTML). Natomiast po końcowym </div>, kod kończący dodatkowe "pojemniki" na 2 newsy:

  1. <?
  2.  if ($page==0 and $zebra=='odd' and $id>1 and $id<6) {
  3.   print "<br/></div>";
  4.  }

Teraz kilka definicji w arkuszu styli:

  1. .teaser-even {
  2.   width: 255px;
  3.   float: left;
  4. }
  5. .teaser-odd {
  6.   width: 255px;
  7.   float: right;
  8. }
  9. .teaser-item-1 {
  10.   width: 530px;
  11.   float: none;
  12. }
  13. .no-float {
  14.   overflow: auto;
  15.   height: auto;
  16.   width: 530px;
  17. }
  18. .no-float .content {
  19.   font-size: 0.85em;
  20. }
  21. .teaser-shortened {
  22.   float: none;
  23.   width: 530px;
  24. }

wartości 530px i 255px należy zmienić odpowiednio na pełną szerokość treści strony, oraz połowę - lub kilka pikseli mniej (zależnie od stylu - np. margin i padding mogą nam tutaj kolidować). Definicję .teaser-shortened { umieszczamy po .teaser-even .teaser-odd { , ponieważ musimy nadpisać pewne wartości w nich zdefiniowane (zamiast tego można dodać w node.tpl.php warunek nie dodający tych ostatnich klas dla dalszych newsów).

Modyfikacja tylko wybranych stron

Co jednak, jeśli chcemy zmienić w ten sposób wygląd tylko strony głównej (bądź kilku wybranych stron), zaś pozostałe strony typu teaser (np. kategorie), pozostawić bez zmian? Najszybciej można dodać prosty warunek, tylko na wskazanych stronach dodający wszystkie modyfikacje (moja strona główna jest wyświetlana przez moduł "views" pod linkiem frontpage):

  1. <?
  2.  if ($_GET['q']=='frontpage' or !$_GET['q']) {
  3.   $styled_teaser = true;
  4.  }
  5.  if ($page==0 and $zebra=='even' and $id>1 and $id<6 and $styled_teaser) {
  6.   print "<div class='no-float'>";
  7.  }
  8.  if ($page==0 and $id>5 and $styled_teaser) {
  9.   // wycinam pierwsze zdanie dla skrótów dalszych newsów
  10.   $nodeclass = ' teaser-shortened';
  11.   // usuwanie znacznikow html
  12.   $content = preg_replace('/<[^!][^<>]*>/','',$content);
  13.   if ($tag_position =strpos($content, '<!--short-->')) {
  14.    $content = substr($content, 0, $tag_position);
  15.   } else {
  16.    $content = substr($content, 0, strpos($content, '.'));
  17.   }
  18.   $content = '<i><a href="'.$node_url.'">'.$content.'...</a></i>';
  19.  }
  20.  ?>
  21.  <div id="node-<?php print $node->nid; ?>" class="node<?php print ($sticky) ? ' sticky' : ''; print (!$status) ? ' node-unpublished' : '';
  22.  if($page==0) {
  23.   print " teaser-node";
  24.   if ($styled_teaser) {
  25.    print " teaser-".$zebra;
  26.    print " teaser-item-".$id;
  27.    print $nodeclass;
  28.   }
  29.  } ?>" >

i na końcu

  1. <?
  2.  if ($page==0 and $zebra=='odd' and $id>1 and $id<6 and $styled_teaser) {
  3.   print "<br/></div>";
  4.  }

Zwróć uwagę na sprawdzanie we wszystkich warunkach wartości zmiennej $styled_teaser . Ponadto w powyższym przykładzie, klasa .teaser-node { będzie dodawana zawsze - jest to potrzebne by nasze duże obrazki dodawane do newsa przed znacznikiem <!--break-->, nie rozwaliły widoku kategorii itp.

Wyświetl wszystkie newsy

Jeśli wykonasz powyższe zmiany, to z pewnością zauważysz że korzystanie z pagera stało się praktycznie bezużyteczne, ponieważ za każdym razem wyświetlają się tylko skróty kilku pierwszych newsów, zaś pozostałe są jedynie jako linki. Aby to ominąć, po prostu wyłączyłem pager na widoku ("view") frontpage, i dałem w stopce link do innego widoku typu teaser, wyświetlającego tą samą liczbę newsów - tym razem bez modyfikacji w wyglądzie.

Małym problemem jest teraz istnienie kanału RSS newsów pod dwoma różnymi linkami (frontpage/feed i np. news/feed) - są one generowane przez oba wykorzystane przez nas widoki. Niestety moduł views w wykorzystywanej wersji (views 1), nie umożliwia zmiany tego domyślnego zachowania, konieczna byłaby bądź modyfikacja samego modułu (niezalecane ze względu na problemy z aktualizacjami), bądź napisanie własnego modułu do obsługi RSS dla views.

Podsumowanie

Okazuje się, że korzystając z domyślnych jedynie widoków dostępnych w Drupalu, można w prosty sposób modyfikować sposób wyświetlania strony z newsami. Mimo że powszechnie znany i kojarzony z Drupalem widok "teaser" nie posiada opcji zmieniających jego dość niemodny już układ, można kilkoma zmianami w skórce całkowicie odmienić jego wygląd.

Dodatkowe uwagi:

  • jeśli chcesz w różny sposób modyfikować kod w node.tpl.php dla różnych widoków (podstron), to najlepiej skorzystać z mechanizmu include(), przyspieszysz działanie witryny przez nie-parsowanie niepotrzebnego kodu
  • dużo zmian da się wykonać, wykorzystując tylko same zmiany w pliku .css - np. w ten sposób można ukryć blok z linkami "Odpowiedz", "Autor" itp.
  • zamiast sprawdzania $_GET['q'] można użyć drupalowej funkcji arg()
  • artykuł był pisany już po wprowadzeniu modyfikacji na działającej stronie, i nie wszystkie wprowadzone modyfikacje opisałem, dlatego może się zdarzyć że jakiś element nie działa zgodnie z opisem - jeśli zauważysz błędy, śmiało to zgłaszaj