Mer avancerat temabyggande: temafunktioner

Events happening in the community are now at Drupal community events on www.drupal.org.
itangalo's picture

Med hjälp av tpl-filer, css-filer och Firebug kan man ändra rätt mycket när det gäller Drupals utseende. Men vissa saker är svåra att ändra, så som i vilken ordning olika element hamnar. För att ändra såna saker behöver man ofta använda tema-funktioner - de funktioner som anropas när innehållet på en sida ska läggas i ordning för att visas.

Här är ett exempel på hur man kan använda temafunktioner för att ändra utseendet på sin webbplats. Exemplet gäller hur man plockar bort avsnittet "Member for" ("Medlem i") på användarsidorna, men förhoppningsvis är det tillräckligt generellt skrivet för att kunna tillämpas i många olika sammanhang.

Steg 0: Ha ett eget tema


När man ändrar saker i Drupal är det viktigt att inte göra ändringarna direkt i core - de filer man får med när man laddar hem Drupal. Teman du vill ändra i bör ligga i katalogen sites/all/themes/namn-på-tema. Om du bara vill leka med temafunktioner är Zen en utmärkt utgångspunkt, men kanske har du ett mer färdigt tema som du bara vill ändra ett par småsaker i.

Steg 1: Hitta funktionen du vill ändra


Det stora jobbet med att ändra en temafunktion är egentligen att hitta vilken funktion det är som styr just det elementet du vill påverka. Ett rätt effektivt sätt är att kolla på källkoden (eventuellt med hjälp av Firebug) efter karaktäristiska css-klasser som står tillsammans med det som du vill ändra.
Om man tittar på källkoden för "Member for" på användarsidan ser den ut som följer:
<div class="profile">
  <div class="picture">
  </div>
  <h3>History</h3>

<dl class="user-member">
  <dt>Member for</dt>
<dd>26 weeks 2 hours</dd>
</dl>
</div>

Lämpliga saker att leta efter här är exempelvis class="user-member" och class="profile" (och kanske class="picture").
>> Varför det? Jo, för att css-klasserna är med allra största sannolikhet resultatet av en temafunktion, eftersom de styr hur sidan ser ut. (Texten "Member for" är visserligen det vi vill ändra, men själva texten handlar om innehållet på sajten, inte hur det visas.)

Det finns olika sätt att leta upp kodbitar i Drupals källkod, men en effektiv metod är Drupal Code Search. Om vi söker på css-klasserna ovan ger class="profile" bingo: På rad 651 i modules/user/user.module finns funktionen theme_user_profile, som verkar innehålla precis det vi vill ändra.
>> Hur vet vi det? Jo, dels börjar funktionsnamnet med theme_, vilket betyder att det är en temafunktion. Dels tyder raderna $output = '<div class="profile">'; och $output .= '<dt class="'. $item['class'] .'">'. $item['title'] .'</dt>'; ... $output .= '<dd class="'. $item['class'] .'">'. $item['value'] .'</dd>'; på att det är precis här som användarens medlemstid skrivs ut. En bra hint är också att detta är den enda träffen vi får upp på kodsökningen.

Steg 2: Kopiera och döp om temafunktionen


När vi väl hittat temafunktionen ska vi inte börja pilla i den förrän vi gjort oss en egen kopia. Det gör vi genom att kopiera hela funktionen - i detta fall rad 651 till 670 - och klistra in den sist i template.php för vårt eget tema. (Det går säkert att använda andra php-filer i temat, men om det inte finns anledning att låta bli är template.php ett bra ställe.)
Nästa sak vi gör är att ändra namn på temafunktionen, från theme_user_profile till namn-på-tema_user_profile. Med ett ett mer specifikt funktionsnamn kommer Drupal att anropa vår egen temafunktion, och låta den mer generella funktionen i core vara. Detta betyder också att temafunktionen bara anropas om vårt eget tema är aktivt, vilket är en fördel. (Dessutom slipper vi två funktioner med exakt samma namn, vilket inte funkar så bra i PHP.)
När vi har gjort detta har vi en alldeles egen temafunktion, som vi får ändra i hur mycket vi vill.

Steg 3: Ändra i temafunktionen


Sista steget är det roligaste. Då får vi mecka runt i funktionen för att få den att göra precis som vi vill. För många temafunktioner är det rätt lätt att se vad som skrivs ut - olika element har olika rader, och det framgår rätt tydligt vad de olika raderna gör. I vårt fall är det däremot lite knepigare. En foreach-loop går igenom alla kategorier i användarkontot, och matar ut etiketter och värden som finns lagrade för (icke-tomma) kategorier:
  foreach ($fields as $category => $items) {
    if (strlen($category) > 0) {
      $output .= '<h2 class="title">'. $category .'</h2>';
    }
    $output .= '<dl>';
    foreach ($items as $item) {
      if (isset($item['title'])) {
        $output .= '<dt class="'. $item['class'] .'">'. $item['title'] .'</dt>';
      }
      $output .= '<dd class="'. $item['class'] .'">'. $item['value'] .'</dd>';
    }
    $output .= '</dl>';
  }

Det vi vill är att kategorin "History" ska hoppas över. Ett smidigt sätt att göra detta är att använda ett enkelt if-villkor, som hoppar över all form av output om $category skulle vara "History". Funktionen blir så som följer (med ny rad näst överst, och matchande slutparentes näst underst):
  foreach ($fields as $category => $items) {
    if ($category != 'History') { // <-- gör endast följande om $category inte är "History"
      if (strlen($category) > 0) {
        $output .= '<h2 class="title">'. check_plain($category) .'</h2>';
      }
      $output .= '<dl>';
      foreach ($items as $item) {
        if (isset($item['title'])) {
          $output .= '<dt class="'. $item['class'] .'">'. $item['title'] .'</dt>';
        }
        $output .= '<dd class="'. $item['class'] .'">'. $item['value'] .'</dd>';
      }
      $output .= '</dl>';
    }
  }

Som vanligt när man håller på och meckar i kod är det smart att spara och testa resultatet. Förhoppningvis fungerar detta bra, men om vi skulle ha installerat svenska på sajten skulle det förmodligen inte ha funkat. Varför? Jo, för att $category inte längre är "History", utan "Historia".
För att avhjälpa detta använder vi funktionen t(), som är den som översätter strängar i Drupal. Den nya raden blir då if ($category != t('History')) {, och allt fungerar som vi vill.
Resultatet blir som följer:
  foreach ($fields as $category => $items) {
    if ($category != t('History')) { // <-- gör endast följande om $category inte är översättningen av "History"
      if (strlen($category) > 0) {
        $output .= '<h2 class="title">'. check_plain($category) .'</h2>';
      }
      $output .= '<dl>';
      foreach ($items as $item) {
        if (isset($item['title'])) {
          $output .= '<dt class="'. $item['class'] .'">'. $item['title'] .'</dt>';
        }
        $output .= '<dd class="'. $item['class'] .'">'. $item['value'] .'</dd>';
      }
      $output .= '</dl>';
    }
  }

Tack till mapiedra, Campsouster, med flera för bra bakgrund till denna guide, samt till deviantintegral som tog sig tid att förklara lite grejer på Drupals IRC-forum.

Comments

Wow

zoo33's picture

Wow, ytterligare en grym guide! Bra att du förklarar varje del ordentligt så man förstår varför man gör som man gör.

Jag ska tipsa om ett annat sätt att hitta rätt temafunktion (eller temafil, som det ofta är fråga om i Drupal 6). Det är att använda Theme developer, som är en del av Devel. När man har aktiverat Theme developer får man en liten kryssruta i nedre vänstra hörnet. Den används för att aktivera ett särskilt läge där man kan klicka på valfri del av sidan och få upp en inforuta om vilka temafunktioner/filer som används för att generera det valda området. Det är väldigt användbart och snyggt – det liknar Firebug en hel del.

Tänk bara på att stänga av den när theming-jobbet är klart.

Låt mig också inflika att det nästan är vanligare att man lägger sitt tema i sites/default/themes (förutsatt att man jobbar med siten default) än i sites/all. Man brukar säga att sites/all-mappen är till för moduler och teman man laddar ner, medan sites/[site] i allmänhet är till för sånt man själv skapar.

Igen: jättebra guide!

/ Hannes Lilljequist – SthlmConnection

Man tackar

itangalo's picture

Man tackar, både för snälla ord och bra tips. =)
Nästa gång jag ska modifiera teman ska jag definitivt kolla in Theme developer i Devel. Och så ska jag börja lägga mina egensnickrade/modifierade saker i sites/default.

Om jag fattar saken rätt finns det bra sätt att göra underteman som bygger på ett färdig tema, utan att kopiera hela temat och byta namn. Hur funkar sånt, någon? (Kanske borde det vara en egen tråd, eller så passar det bra här...)

//Johan Falk, Solna

Zen

zoo33's picture

Kolla README-filen i Zen-temat. Där finns en bra instruktion för hur man gör ett subtema. I det fallet brukar jag lägga zen i sites/all och subtemat i sites/default. Men det funkar bara i Drupal 6.

Det sköna med att göra ett subtema är att man i regel bara behöver lägga till det man vill ändra i det överliggande temat (t ex zen), resten ligger kvar i det orörda grundtemat. Det gör att man faktiskt kan uppdatera grundtemat efterhand som det kommer nya versioner (även om det kan vara riskabelt).

/ Hannes Lilljequist – SthlmConnection

Tackar igen

itangalo's picture

Zen-temat är ju hur fett som helst. (Och fetare än jag trodde tidigare.) Blir man ninja på att använda det borde man inte behöva något annat tema, någonsin.
Det borde ges kurser i hur man blir Zen-ninja. (Vänta nu - det kanske det redan finns...)

Jaja. Helt klart är att svenska Drupalforumet ska få en guide om hur, och varför, man ska göra saker med Zen.

//Johan Falk, Solna

det ser jag fram emot.. :)

Qonos's picture

det ser jag fram emot.. :)

tackar

karl-johan's picture

För en mycket bra guide, efter att jag läst detta inlägg kan jag göra saker jag bara drömt om tidigare :)

Code Search Drupal

zy's picture

Code Search Drupal - länken dit hittas inte. Är det tillfälligt eller? Vad är det för ställe annars?

H,
Lena

When in trouble or in doubt, run in circles, scream and shout.

When in trouble or in doubt, run in circles, scream and shout.

hittat rätt...

zy's picture

drupalcodesearch ska det vara.

When in trouble or in doubt, run in circles, scream and shout.

Tackar

itangalo's picture

Vet inte riktigt vad jag tänkte på när jag skrev den länken...
Tack för att du uppmärksammade felet – nu är länken lagad.

//Johan Falk, Solna

Hjälp med 960 Grid System

dipprod's picture

Hej.

Jag undrar ifall du Johan har jobbat med 960 Grid System eller om du vet kanske någon bättre grej än det. Så mycket som jag har kollat på det så ska det vara ganska enkelt och bra att jobba med men jag vet inte hur jag ska anpassa den till min Drupal.
Det finns också något som heter Fluid 960 Grid System som är liknande grej men där är också problemet att det inte finns mycket info om det på varken youtube eller google. Eller rättare sagt så finns det massor men inget i samband med Drupal.

Snälla hjälp.

P.S. Mycket bra tutorials och screencast.

// Dejan Inic.

Tyvärr ingen koll

itangalo's picture

Tackar för snälla ord om screencasts och tutorials!

Tyvärr har jag näst intill noll koll på gridsystem – mer än att jag vet vad det är för något. Än mindre när det gäller fluid-varianter. Får hoppas på att någon annan kan fylla i luckorna. :-/

//Johan Falk, NodeOne
**
Vill du lära dig mer om Drupal? Kolla in samlingen av tips och guider!
Har du en fråga om Drupal? Missa inte FAQ-sidan på forumet!
Kolla in min senaste guide: Hundra småsteg för att självlära sig Drupal 6

Prova bastemat Fusion

msafiri's picture

Prova bastemat Fusion (http://drupal.org/project/fusion). Där har man väldigt mycket gratis.

Sweden

Group notifications

This group offers an RSS feed. Or subscribe to these personalized, sitewide feeds: