Blog

Ghost CMS. Podstawy tworzenia własnego tematu. Odsłona pierwsza.

Kolejna część tutoriala, w którym staram się przedstawić zasady rządzące budową własnego tematu dla Ghost CMS.

Ghost CMS. Podstawy tworzenia własnego tematu. Odsłona pierwsza.

Wreszcie czas na praktyczną realizację naszego zamierzenia, czyli utworzenia tematu, który będzie najlepiej oddawał charakter naszego bloga czy tam witryny. Ponieważ perspektywa pisania kodu HTML w parze z odpowiednią jego stylizacją w CSS nieodmiennie mnie przeraża, skorzystam z mojej ulubionej strategii, czyli wezmę na warsztat gotowy motyw, który następnie odpowiednio skroimy na potrzeby Ghost. Do tego celu zaadoptujemy darmowy temat dostępny na startbootstrap.com. Jeśli ktoś śledził moje poprzednie wpisy, z łatwością zauważy, że korzystałem z tego motywu przy innej okazji. Ponowny wybór nie wynika jednak z lenistwa piszącego te słowa, a przynajmniej nie wyłącznie. Idzie nade wszystkim o dwie kwestie, ponieważ od strony wizualnej dość dobrze pasuje on do tego, co zwyczajowo oferują inne tematy dla Ghost, które charakteryzują się względną prostotą mającą wspierać koncentrację na dostarczanej treści. Nade wszystko motyw ten nie jest przeładowany kodem a przy tym poszczególne jego części są wyraźnie od siebie odseparowane, co – jak się okaże – będzie bardzo pomocne przy wydzielaniu odpowiednich elementów na potrzeby tworzenia wymaganych szablonów.  

Zanim przejdziemy dalej w tym miejscu chciałbym złożyć samokrytykę, ponieważ jakieś dwa tygodnie temu napisałem, że nie do końca czuję potrzebę takiego rozdrabniania kodu w przypadku typowych dla Ghost motywów, które charakteryzują się względną prostotą. Z perspektywy czasu napisać jednak muszę, że ma to więcej sensu niż przypuszczałem, a przynajmniej może być szalenie wygodne. Nie zmienia to jednak mojej opinii, że warto czasem dwa razy się zastanowić zanim się wydzieli jakiś fragment kodu, zwłaszcza jeśli ma być on użyty tylko w jednym konkretnym widoku.

Zaczynamy od utworzenie katalogu dla naszego tematu w folderze /content/themes/. Nazwa nie ma większego znaczenia, ale ja z oczywistych względów nazwę go borciugner. Następnie już wewnątrz tego nowo powstałego katalogu dorzucimy dwa inne, czyli assets oraz partials. Co w nich będzie następnie posadowione wyjaśniałem przy okazji wpisu o strukturze projektu, ale gwoli przypomnienia: pierwszy z nich będzie zawierał skrypty CSS oraz JS, a także czcionki oraz grafiki, którymi zechcemy okrasić nasz motyw. W drugim zwyczajowo umieszczane bywają szablony, które odpowiadają blok kodu, które będziemy chcieli wstrzykiwać w ramach poszczególnych stron naszej witryny/bloga. 

Zanim przejdziemy dalej w tym miejscu chciałbym złożyć samokrytykę, ponieważ jakieś dwa tygodnie temu napisałem, że nie do końca czuję potrzebę takiego rozdrabniania kodu w przypadku typowych dla Ghost motywów, które charakteryzują się względną prostotą. Z perspektywy czasu napisać jednak muszę, że ma to więcej sensu niż przypuszczałem, a przynajmniej może być szalenie wygodne. Nie zmienia to jednak mojej opinii, że warto czasem dwa razy się zastanowić zanim się wydzieli jakiś fragment kodu, zwłaszcza jeśli ma być on użyty tylko w jednym konkretnym widoku.

Wracając jednak do struktury naszego projektu: jeśli poradziliśmy sobie z folderami, możemy przejść do utworzenia wymaganych plików w katalogu głównym. Na ten moment będą to:

Ten ostatni jest wymaganym elementem z punktu widzenia motywu dla Ghost, tym niemniej nie chciałbym dzisiaj przesadnie dużo miejsca mu poświęcać, dlatego proponuję na ten moment wrzucić do niego następującą zawartość i chwilowo na tym poprzestać.

TWORZENIE UKŁADU

Tworzenie projektu zaczniemy od przygotowania układu, czyli nadrzędnego szablonu, po którym  będą dziedziczyć wszystkie inne. Zanim jednak za to się zabierzemy, skopiujmy wprzódy wszystkie składniki odpowiedzialne za stylizację wyglądu naszego bloga. W tym celu musimy umieścić w folderze asset następujące katalogi z wcześniej pobranego tematu:

Teraz już możemy w naszym ulubionym edytorze otworzyć pliki default.hbs dostępny w ramach naszego projektu oraz index.html z katalogu, do którego rozpakowaliśmy zawartość motywu CLT. Z tego ostatniego kopiujemy całą zawartość i wklejamy ją do pliku, w którym znajdował się będzie szablon naszego bloga. Gdy to już wykonanym, musimy usunąć większość tego, co przed momentem umieściliśmy w pliku default.hbs, a dokładniej należy zaznaczyć i skasować praktycznie wszystko co znajduje się między znacznikami body, zostawiając jedynie odnośniki do skryptów JS, które znajdują się na końcu tej sekcji. 

W tym momencie zaczynamy powolne dzierganie naszego tematu na modłę “duszkową”. Zacznijmy od samej góry, czyli podmienimy wartość dla atrybutu “lang” i bynajmniej nie chodzi, by dwie obecny literki “en” zastąpić innymi, na ten przykład wskazującymi na nasz rodzimy język. Dodajmy bowiem między cudzysłowami {{@site.lang}}. Zanim wyjaśnię o co chodzi dokonajmy podobnego zabiegu dla znacznika “title”, który w efekcie powinien wygląda tak <title>{{@site.title}}</title>.

O co chodzi z tym całym @site? Otóż dzięki temu odwołaniu w Ghost mamy dostęp do szeregu wartości, które mogą się wedle naszego uznania zmieniać. Te dwie, czyli “lang” oraz “title” możemy ustawić z poziomu panelu administratora Ghost i wówczas przy renderowaniu strony po stronie klienta zostanie dodana odpowiedni ciąg znaków. Poniżej pozwoliłem sobie zamieścić zrzut ustawień Ghost, gdzie te wartości można uzupełnić czy też zmodyfikować.

Do trzech kolejnych z tej grupy będziemy mieli okazję dzisiaj się odwołać, ale na ten moment dokończymy modyfikacje w sekcji “head”, ponieważ została jeszcze jedna rzecz do zrobienia, a mianowicie wskazanie ścieżki do naszych elementów statycznych na sposób proponowany przez twórców Ghost. W tym wypadku rzecz jasna będzie chodziło o wskazanie miejsca składowania skryptów CSS. W związku z tym w przypadku atrybutów “href” tam gdzie takie odwołanie następuje, należy dołożyć charakterystyczne nawiasy klamrowe oraz odpowiednio zapisać całość. Z grubsza ma to wyglądać tak:

 <link href=”{{asset „vendor/bootstrap/css/bootstrap.min.css”}}” rel=”stylesheet”>

To samo możemy zrobić od razu ze skryptami dla JS, która znajdują się na dole sekcji “body”. A skoro już w niej jesteśmy to na sam koniec dorzućmy na jej początku znaczniki {{navigation}}, {{{body}}} oraz {{>footer}} i to dokładnie w takiej kolejności. Pierwszy i ostatni z nich zostaną omówione dalej bardziej szczegółowo. Tutaj wyłącznie napiszę, że znacznik body “odpowiada” za tę część, które będą unikalne dla szablonów, które renderować mają widok dla poszczególnych stron czy też kategorii stron. 

<!DOCTYPE html>
<html lang="{{@site.lang}}">
 
<head>
 
 <meta charset="utf-8">
 <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
 <meta name="description" content="">
 <meta name="author" content="">
 
 <title>{{@site.title}}</title>
 
 <link href="{{asset "vendor/bootstrap/css/bootstrap.min.css"}}" rel="stylesheet">
 <link href="{{asset "vendor/fontawesome-free/css/all.min.css"}}" rel="stylesheet" type="text/css">
 <link href='https://fonts.googleapis.com/css?family=Lora:400,700,400italic,700italic' rel='stylesheet' type='text/css'>
 <link href='https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800' rel='stylesheet' type='text/css'>
 <link href="{{asset "css/clean-blog.min.css"}}" rel="stylesheet">
 
</head>
 
<body>
 
 {{navigation}}
 
 {{{body}}}
 
 {{>footer}}
  <script src="{{asset "vendor/jquery/jquery.min.js"}}"></script>
 <script src="{{asset "vendor/bootstrap/js/bootstrap.bundle.min.js"}}"></script>
 <script src="{{asset "js/clean-blog.min.js"}}"></script>
 
</body>
 
</html>

Nawigacja (navigation)

Nawigacja, którą wywołuje się w Ghost przy pomocy tagu {{navigation}}, to rozwiązanie generujące odpowiednio sformatowany kod HTML, zbudowany na bazie elementów, które definiuje się w panelu administracyjnym. Twórcy omawianego CMS przygotowali dwa typy nawigacji (co widać niżej). Nas jednak interesować będzie wyłącznie pierwszy z nich.

Jeśli podejrzymy kod wygenerowany po stronie klienta domyślnie wygląda on mniej więcej jak na zostało to przedstawione niżej (oczywiście to tylko przykład, więc w naszym wypadku będzie to wyglądało nieco inaczej). 

<ul class="nav">
    <li class="nav-home nav-current"><a href="/">Home</a></li>
    <li class="nav-about"><a href="/about/">About</a></li>
    <li class="nav-contact"><a href="/help/">Help</a></li>
    ...
</ul>

Dość oczywistym jest, że raczej rzadko będzie nas zadowalał ten wyjściowy sposób prezentacji, co oczywiście nie umknęło uwadze twórcom Ghost i w efekcie mamy możliwość przygotowania własnego szablonu przy wykorzystaniu atrybutów dostępnych dla “navigation”, które występują w liczbie czterech i są to:

W praktyce w naszym projekcie skorzystamy tylko z dwóch pierwszych, ale w tym celu na początek w folderze partials musimy utworzyć plik navigation.hbs, a następnie wkleić do niego kod widoczny poniżej.

<nav class="navbar navbar-expand-lg navbar-light fixed-top" id="mainNav">
   <div class="container">
     <a class="navbar-brand" href="/">
     {{#if @site.logo}}
           <img src="{{@site.logo}}" alt="{{@site.title}}" />
       {{/if}}
     </a>
 
     <button class="navbar-toggler navbar-toggler-right" type="button" data-toggle="collapse" data-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
       Menu
       <i class="fas fa-bars"></i>
     </button>
     <div class="collapse navbar-collapse" id="navbarResponsive">
       <ul class="navbar-nav ml-auto">
         {{#foreach navigation}}
         <li class="nav-item"><a class="nav-link" href="{{url absolute="true"}}">{{label}}</a></li>
         {{/foreach}}
       </ul>
     </div>
   </div>
 </nav>

Co my tutaj widzimy? Jest to odpowiednio spreparowany fragment z naszego bazowego motywu, gdzie w miejsce na sztywno wpisanych wartości dodaliśmy znaczniki odwołujące się do konfigurowalnych elementów Ghost. Na górze w miejsce statycznego wskazania na dedykowaną grafikę odwołujemy się do pola @site.logo. Tym sposobem w łatwy sposób z poziomu ustawień możemy podmienić lub w ogóle usunąć stosowany obrazek. Ponieważ dopuszczamy taką możliwość, czyli że tego logo może zabraknąć dodajemy funckję pomocniczą if, która sprawdza, czy Ghost zwraca coś dla tego pola i jeśli tak jest wyświetla odpowiedni odnośnik.

Dalej interesuje nas blok zawarty między znacznikami “foreach”. Jeśli chodzi o ten ostatni, to mamy do czynienia tutaj z autorską strukturą, która na pierwszy rzut oka niczym nie różni się od od standardowej funkcji “each”. Tym niemniej twórcy proszą, by zawsze przy budowaniu tematu posługiwać się ich rozwiązaniem, co niniejszym uczyniliśmy (The {{#foreach}} helper is context-aware and should always be used instead of Handlebars each when working with Ghost themes.). Dzięki użyciu tej pętli oraz atrybutów label oraz url po stronie klienta zostanie wygenerowana nawigacja wyglądająca i działająca tak jak sobie to założyliśmy.

Stopka (footer)

Kolejnym stałym elementem naszego układu (nadrzędnego szablonu) była stopka. W tym wypadku twórcy Ghost nie przygotowali gotowego komponentu po stronie ustawień, ale nic nie stoi na przeszkodzie, by wykorzystać do tego celu inne dostępne elementy konfigurowalne z poziomu panelu administracyjnego, a dokładniej chodzi o linki do konta na Facebooku oraz Twitterze.

Podobnie jak w przypadku nawigacji w folderze partials tworzymy nowy plik i nazywamy go footer.hbs i wklejamy do niego widoczny poniżej kod.

<footer>
    <div class="container">
      <div class="row">
        <div class="col-lg-8 col-md-10 mx-auto">
          <ul class="list-inline text-center">
            {{#if @site.twitter}}
            <li class="list-inline-item">
              <a href="{{twitter_url @site.twitter}}" target="_blank">
                <span class="fa-stack fa-lg">
                  <i class="fas fa-circle fa-stack-2x"></i>
                  <i class="fab fa-twitter fa-stack-1x fa-inverse"></i>
                </span>
              </a>
            </li>
            {{/if}}
            {{#if @site.facebook}}
            <li class="list-inline-item">
              <a href="{{facebook_url @site.facebook}}" target="_blank">
                <span class="fa-stack fa-lg">
                  <i class="fas fa-circle fa-stack-2x"></i>
                  <i class="fab fa-facebook-f fa-stack-1x fa-inverse"></i>
                </span>
              </a>
            </li>
            {{/if}}
          </ul>
          <p class="copyright text-muted">Copyright &copy; {{@site.title}} 2021</p>
        </div>
      </div>
    </div>
  </footer>

Wydaj mi się, że to rozwiązanie jest na tyle proste, że nie wymaga specjalnego komentarza. W obu wypadkach sprawdzamy, czy skonfigurowane zostały odpowiednie adresy, a jeśli tak, to wówczas wyświetlany odpowiednią ikonkę, która będzie przenosiła nas do podlinkowanej strony.

Na dzisiaj to byłoby tyle. Kolejny wpis w pewnym sensie będzie zamykał temat tworzenia własnych motywów Ghost na takim najbardziej podstawowym poziomie.