WordPress - motywy, wtyczki, informacje, programowanie

Motywy potomne

Motywy potomne (child themes) – bezpieczne modyfikacje motywu

W tym poradniku pokażemy, co to są motywy potomne (ang: child themes), jak je tworzyć i dzięki nim modyfikować gotowe motywy kupione lub pobrane za darmo z sieci. Przy okazji (w ramach przykładów) dowiesz się jak dodać do każdego artykułu przycisk Google+1 oraz jak używać Google Web Fonts.

Chociaż na rynku dostępnych jest bardzo wiele gotowych motywów, zarówno tych darmowych jak i płatnych, bardzo często zaawansowani użytkownicy chcą dokonać w nich jakichś modyfikacji. Czasem chodzi o drobne zmiany, dodanie nowych styli, zmianę kolorów, ale czasem wymagane zmiany są poważniejsze, dotyczą nowych funkcjonalności.

Modyfikacja oryginalnego motywu nie jest dobrym pomysłem. Większość lepszych motywów jest regularnie aktualizowana przez autorów, chociażby po to, żeby wykorzystać możliwości nowych wersji WordPressa, lub załatać jakieś błędy i luki w bezpieczeństwie. Jeżeli nowa wersja będzie zawierała zmiany w plikach, które my zmodyfikujemy, nasze dodatki znikną, bo pliki zostaną zastąpione przez te pochodzące z nowszej wersji.

Aby uniknąć tego rodzaju problemów, a jednocześnie nie ograniczać użytkowników i umożliwić im bezpieczne rozwijanie motywów, powstał mechanizm motywów potomnych (child themes). Jest on prawie zawsze wystarczający do takich celów. Jeśli oryginalny motyw został dobrze napisany, zgodnie ze sztuką i zaleceniami WordPress Codex, nie powinniśmy napotkać większych kłopotów.

Co ważne, wykorzystanie motywów potomnych nie wymaga jakiejś wielkiej wiedzy informatycznej, wystarczy pobieżna znajomość PHP i CSS, chyba że zmiany których chcemy dokonać są bardzo skomplikowane. Jeśli zmiany są proste, może je wykonać ogólnie sprawny komputerowo amator.

Przed lektura tej notki warto przeczytać tekst: Szablony stron w WordPressie – z czego składa się każdy motyw.

Co to jest motyw potomny i jak go założyć. Plik style.css

Idea i logika motywu potomnego jest bardzo prosta. Polega on ana tym, że zakładamy nowy motyw jednocześnie informując WordPressa, że jeśli nie znajdzie w jego obrębie szablonu do wyświetlenia jakiejś strony, powinien skorzystać z motywu nadrzędnego, którego nasz motyw jest potomkiem. To trochę tak, jakbyśmy dziedziczyli klasę w PHP, czy w jakimś innym obiektowym języku programowania.

Na potrzeby tego poradnika załóżmy, że będziemy chcieli zbudować motyw potomny do motywu TwentyEleven, który jest domyślnym motywem obecnej instalacji WordPressa (3.3.2).  W motywie potomnym, który nazwiemy Something Better zmienimy podstawową czcionkę i sprawimy, żeby pod każdym postem  pojawiał się przycisk Google +1.

Zacznijmy od tego, że w kartotece /wp-content/themes/ założymy kartotekę something-better. W kartotece założymy plik style.css o następującej zawartości:

/*
Theme Name: Something Better
Template: twentyeleven
*/

@import url("../twentyeleven/style.css");

Plik ten ma dla WordPressa specjalne znaczenie. Na górze pliku znajduje się blok komentarza, w którym zawarte są dwie informacje. Linia:

Theme Name: Something Better

mówi WordPressowi, że własnie utworzylismy motyw o nazwie Something Better, a linia

Template: twentyeleven

określa, że nasz nowy motyw dziedziczy po motywie TwentyEleven. Przy czym podajemy tutaj nie nazwę motywu, po którym dziedziczymy, tylko nazwę katalogu, w którym znajdują się pliki tego motywu.

Kolejna linia

@import url("../twentyeleven/style.css");

oznacza, że WordPress ma załadować  (w tym miejscu) arkusz styli z motywu nadrzędnego.

W tym momencie utworzyliśmy już motyw potomny i możemy się na niego przełączyć, korzystając ze strony administracyjnej Wygląd/Motywy. Gdy to zrobimy możemy zauważyć, że wszystko wygląda dokładnie tak samo jak w oryginalnym motywie TwentyEleven. Aby zobaczyć, jak ważna jest komenda @import z pliku style.css, możemy ją na chwile usunąć, lub zakomentować. Zobaczymy wtedy, że nasz serwis rozleciał się zupełnie  – po prostu nie ma żadnych styli.

Przywracamy linię z komenda @import i poniżej dodajemy modyfikację czcionki, której chcieliśmy dokonać. Załóżmy, że chcemy zmienić czcionkę naszego serwisu na jedną z dostępnych w Google WebFonts. Niech będzie to Droid Sans.

/*
Theme Name: Something Better
Template: twentyeleven
*/

@import url("../twentyeleven/style.css");
@import url(http://fonts.googleapis.com/css?family=Droid+Sans:regular,bold|Droid+Serif:regular,italic,bold,bolditalic&subset=latin);

body, input, textarea {
 font-family: 'Droid Sans', Arial, Helvetica, sans-serif;
}

Przy okazji, jeśli dotąd tego nie wiedziałeś, nauczyłeś się korzystać z Web Fonts. Czcionki możesz osadzać na kilka sposobów, zarówno z serwisu Google (Google Web Fonts) jak i z własnej strony. Możłiwość ta jest w tej chwili obsługiwana przez wszystkie nowoczesne przeglądarki.

Dodatkowe funkcjonalności motywu – plik functions.php

Zwykle tworząc motyw potomny chcemy zrobić coś więcej niż tylko zmienić style i w takim wypadku najczęściej będziemy chcieli dodać jakieś dodatkowe funkcje. Można to zrobić tworząc własną wersję pliku functions.php. Plik o tej nazwie występuje w większości motywów i WordPress tratuje go specjalnie, inaczej niż plik style.css. Jak zauważyłeś, plik style.css, ładowany jest z Twojego, potomnego motywu, a Ty sam musisz zatroszczyć się, żeby wczytać przez @import arkusz lub arkusze styli z motywu nadrzędnego. Jeśli tego nie zrobisz, serwis będzie nieostylowany. W wypadku pliku functions.php najpierw ładowany jest Twój plik , a po nim automatycznie plik z motywu nadrzędnego. W ten sposób działają wszystkie funkcje motywu nadrzędnego, ale mogą być przykryte (zamienione) przez te, które znajda się w motywie potomnym, pod warunkiem, że twórca motywu nadrzędnego użył konstrukcji.

if (!function_exists('add_decoration')) {
  function add_decoration() {
    // do something
  }
}

Jeśli teraz w swoim pliku functions.php napiszesz funkcję add_decoration, zastąpi ona analogiczną funkcje  motywu nadrzędnego.

Najczęściej jednak nie chodzi o zmianę działania funkcji, a raczej o dokładanie nowych funkcjonalności. Jeśli utworzysz w kartotece swojego szablonu potomnego plik functions.php o poniższej zawartości, pod każdym  postem na twoim blogu pojawi się przycisk Google +1.

<?php

function disp_gplus($content){
  global $post;
  $post_link = get_permalink($post->ID);
  $epost_link = urlencode($post_link);
  $gplus_button =
    '<div class="g-plusone" data-size="medium" data-href="'.
    $epost_link.'"></div>';
  return $content . $gplus_button;
}

function gplus_js() {
?>
<!-- Script for Google +1 button -->
<script type="text/javascript">
  window.___gcfg = {lang: 'pl'};
  (function() {
    var po = document.createElement('script');
    po.type = 'text/javascript'; po.async = true;
    po.src = 'https://apis.google.com/js/plusone.js';
    var s = document.getElementsByTagName('script')[0];
    s.parentNode.insertBefore(po, s);
  })();
</script>
<?php
}

add_action( 'wp_head', 'gplus_js' );
add_filter('the_content', 'disp_gplus',1);

?>

Funkcja gplus_js wypisuje skrypt, który jest niezbędny aby przycisk Google +1 zadziałał. Przy pomocy

add_action( 'wp_head', 'gplus_js' );

„podpinamy” funkcję gplus_js do miejsca w kodzie WordPressa, gdzie wypisywany jest nagłówek <head>...</head> wszystkich stron serwisu, ponieważ dobrze jest, aby skrypt ładował się właśnie w tym miejscu.

Funkcja disp_gplus „podpięta” jest przy pomocy

add_filter('the_content', 'disp_gplus',1);

jako filter, przez który przepuszczana jest treść każdego postu przed wypisaniem na stronie. Funkcja dokleja do postu fragment HTML w wyniku którego pod postem pojawia się prawidłowo umieszczony przycisk Google +1.

Obydwa mechanizmy – add_filter i add_action pozwalają podpinać swoje funkcje na tak zwane haki WordPressa. Umożliwia to zmianę istniejących i dodawanie nowych funkcjonalności do serwisu (w pliku functions.php, wtyczce lub dowolnym innym pliku php) bez ingerencji w kod WordPressa. Mechanimy te dokładnie omawiamy w artykułach Wprowadzenie do akcji i filtrów oraz Akcje i filtry od środka.

Szablony stron w motywie potomnym

Oprócz plików style.css i functions.css w kartotece motywu znajdują się szablony stron. na przykład pliki: single.php albo tag.php oraz szablony elementów stron np. header.php albo sidebar.php. Bardzo często autorzy motywów potomnych chcą zmienić jeden z tych szablonów.

Aby zmienić jeden z szablonów, wystarczy powołać plik o tej samej nazwie w kartotece motywu potomnego. Jeśli WordPress go napotka, użyje go zamiast szablonu z motywu nadrzędnego. Najczęściej rozsądne będzie skopiowanie oryginalnego szablonu do motywu potomnego i zmienianie go tutaj, bez naruszania wersji oryginalnej.

W wypadku plików takich jak header.php czy sidebar.php, czyli takich, które są częściami szablonów, działa to identycznie jeśli tylko autor motywu nadrzędnego, z którego korzystamy użył ich właściwie. Plików tych nigdy nie wolno ładować instrukcją require albo require_once języka PHP, zamiast tego należy użyć odpowiednio funkcji get_header, get_siedebar, itd.  Dołączają one wspomniane pliki najpierw z kartoteki motywu potomnego, a dopiero później z motywu nadrzędnego. Gdyby użyć komendy require lub require_once, ścieżka do pliku byłaby wpisana na stałe i zawsze byłby ładowany plik z motywu nadrzędnego.

Jeśli motyw, z którego dziedziczymy jest rozbudowany, np. szablony stron są różnorodne i podzielone na wiele plików, które są dołączane do głównych szablonów (podobnie jak w wypadku header.php czy sidebar.php), autorzy takich  motywów często dostarczają dodatkowych funkcji podobnych w swojej logice do get_header czy get_sidebar, abyśmy mogli łatwo nadpisać poszczególne fragmenty szablonów. Jeśli tworzymy motyw potomny dobrym zwyczajem jest zaglądnąć do dokumentacji motywu z którego dziedziczymy,  bardzo często znajdziemy tam instrukcje o tym jak tworzyć motywy potomne, spis użytecznych funkcji, jakieś uwagi związane z kompatybilnością i możliwymi problemami.

Przy pomocy motywu potomnego możemy też dodać nowe szablony i WordPress skorzysta nich właściwie. Na przykład motyw nadrzędny może zawierać tylko szablon archive.php,  który odpowiada za wyświetalanie wszystkich zbiorczych list postów w serwisie – np. listy postów w danej kategorii, z danym tagiem, listy postów danego autora, listy postów z danej daty itd. Możemy jednak utworzyć szablon tag.php, którego WordPress używa domyślnie aby wyświetlić archiwum postów dla danego taga. Teraz archiwa wszystkich tagów będa wyświetlane przez szablon tag.php a wszystkie pozostałe listy postów w dalszym ciągu szablonem archive.php.

Możemy pójść jeszcze dalej i stworzyć szablon tag-12.php. WordPress użyje go jeśli będzie miał wyświetlić archiwum taga o ID=12, pozostałe tagi wyświetli szablonem tag.php, a resztę archiwów szablonem archive.php.

Inne pliki w motywach potomnych

Oprócz tego, w kartotece z motywem potomnym mogą się znajdować dowolne inne pliki, z których możemy korzystać – jakieś dodatkowe piki PHP, obrazki, inne arkusze styli, pliki mp3, itp. Nie ma tu ograniczeń z wyjatkiem jednego – uważaj, aby pliki .php nie pokrywały się ze standardowymi nazwami szablonów WordPressa albo z nazwami, które ustandardyzował autor motywu nadrzędnego. Najrozsądniej jest stworzyć kartotekę o nazwie, która nie występuje w motywie nadrzędnym (np. child-inc) i wszelkie pliki PHP umieszczać tam.

Aby użyć jakiegoś innego pliku z motywu potomnego należy się posługiwać funkcją get_stylesheet_directory, która zwraca kartotekę, w której znajduje się głowny arkusz styli dla danego motywu (style.css) a zatem kartotekę motywu potomnego. Np.:

require_once( get_stylesheet_directory(). '/my_decorations.php' );

Jeśli zamiast kartoteki potrzebujemy URI (np. po to, żeby odwołać się do obrazka) trzeba użyć funkcji get_stylesheet_directory_uri.

Analogicznie, aby użyć w motywie potomnym jakiegoś pliku z szablonu nadrzędnego, możesz użyć funkcji get_template_directory i get_template_directory_uri.

Uwagi dodatkowe:

  1. Nie da się zrobić motywu potomnego do motywu potomnego. Dlatego jeśli korzystasz z motywu, który już jest motywem potomnym, będziesz musiał go modyfikować żywcem, ze wszystkimi tego konsekwencjami.
  2. Motyw TwentyEleven zawiera alteranatywny arkusz styli (dark.css) dla ciemnej wersji serwisu. Znajduje się on w kartotece /wp-coontent/twentyeleven/colors/. Niestety nie ma prostej i eleganckiej metody aby zmodyfikować jego style, ponieważ jest ładowany po arkuszu style.css i WordPress w żaden sposób nam tu nie pomaga. Najłatwiejszym (choć niezbyt eleganckim) rozwiązaniem jest nadpisanie odpowiednich styli w arkuszu style.css z użyciem !important. Dla większości zastosowań to powinno wystarczyć.
  3. Jeżeli twoja strona ma obsługiwać języki czytane od prawej do lewej (np. hebrajski) i motyw z którego dziedziczysz zawiera plik rtl.css (czyli arkusz styli dla tych języków), możesz założyć w swoim motywie potomnym taki plik i zaimportować do niego rtl.css z motywu nadrzędnego – dokładnie tak samo jak to  robiliśmy w wypadku pliku style.css.


Powiadomimy Cię o nowych artykułach

Komentarzy: 25

  1. Cześć Marek. Nie wiem czy to zauważyłeś ale obcina Ci tekst. Sidebar przykrywa część contentu. Bardzo mnie to zdziwiło jak czytałem artykuł, bo zdanie tak dziwnie wyglądało. Dpiero po małych modyfikacjach szerokości contentu (jest na 100%!) na udało się odczytać. Zerknij sobie na to – wyszło, że 64% lub 720px wystarczy
    Pozdrawiam Serdecznie 😉

    P.s. Dzięki za artykuł i zapraszam do siebie 😉

    • Serdeczne dzięki za czujność. Już naprawiłem – to był efekt uboczny innej zmiany. Tak to jest jak się coś robi na szybko :-/

  2. „Aby zmienić jeden z szablonów, wystarczy powołać plik o tej samej nazwie w kartotece motywu potomnego.”

    A później:

    „Oprócz tego, w kartotece z motywem potomnym mogą się znajdować dowolne inne pliki, z których możemy korzystać – jakieś dodatkowe piki PHP, obrazki, inne arkusze styli, pliki mp3, itp.

    Nie ma tu ograniczeń z wyjatkiem jednego – uważaj, aby pliki .php nie pokrywały się ze standardowymi nazwami szablonów WordPressa albo z nazwami, które ustandardyzował autor motywu nadrzędnego. ”

    Czyli co?! Najpierw napisałeś, że trzeba zrobić plik z taką samą nazwą jak oryginalna, a później że nazwy mają się nie pokrywać, nie rozumiem 😛

    Ale i tak wpis bardzo fajny, poza tą jedną kwestią cała reszta jest dla mnie zrozumiała. Od teraz będę korzystał z motywów potomnych 😀

    • Nazwy mają się pokrywać jeśli chcesz nadpisać jakiś szablon. Natomiast musisz uważać, żeby nie skolidować z nazwami szablonów jak chcesz dodać jakiś inny plik PHP, który nie ma nadpisać szablonu w motywie bazowym.

  3. Świetny wpis. Biorę się za tworzenie child theme. Mam nadzieję że dobrze zrozumiałem:
    1. tworzę motyw potomny
    2. tworzę plik w któtym chciałbym wprowadzić zmiany, np. functions.php
    3. kopiuję zawartość oryginału (w moim przypadku functions.php) i wklejam do pliku który właśnie stworzyłem
    4. teraz mogę go edytować.

    Zgadza się? Jeśli tak, to wydaje się proste. Pozdrawiam

    • Akurat plik functions.php jest traktowany inaczej niż pozostałe – najpierw ładowana jest zawartość z motywu-dziecka a później z motywu-rodzica więc nie ma tu potrzeby kopiowania czegokolwiek.

      Marek opisał to szczegółowo w powyższym artykule.

  4. Motyw, który modyfikuję ma własne specyficzne pliki jak np. w katalogu functions plik custom-functions.php. Chcę w nim zmienić kod jednej funkcji. Z tego co zrozumiałem kopiuję ten plik do swojego katalogu z motywem potomnym do takiego samego katalogu. Usuwam w nim zbędny kod i zostawiam tą zmodyfikowaną funkcję. Powinno pobrać zawartość tej funkcji z motywu potomnego, a tego nie robi. Sprawdziłem też, że jak umieszczę cały kod z tego pliku też to nie działa. Dopiero jak zrobiłem zmiany w motywie głównym, to zadziałało. Jak zrobić, aby zmiany zostały uwzględnione w motywie potomnym w tym pliku?

  5. Pingback: Struktura motywu wordpress | Tworzenie witryn interntowych

  6. Wszystko w porządku tylko mam problem po dodaniu dodatkowego pliku z funkcjami i podpięciu go pod functions.php w panelu admina jak dodaje wpisy – to wyskakuje komunikat że wpis został zaktualizowany a strona się nie przeładowała i formularz nie jest wyczyszczony a poza tym u mnie występuje odstęp pomiędzy paskiem admina u góry a główną stroną. W momencie kiedy odłączam dodatkowy plik z funkcjami wszystko wraca do normy

    • Twój plik wypisuje coś (np. pustą linię). Efektem jest to, że nie działają AJAXy oraz mogą się pojawiać takie rzeczy jak odstęp pod toolbarem. Pusta linia jest wypisywana najczęściej jeśli ją wstawisz przed pierwszym otwierającym tagiem < ?php lub po ostatnim tagu ?> (ten ostatni najlepiej jest pominąć). To najbardziej prawdopodobna przyczyna. Zobacz sobie źródło strony w przeglądarce. Prawie na pewno zaczyna się od pustej linii, albo jakiegoś śmiecia. Pamiętaj, że w pliku functions.php NIE MOŻE BYĆ żadnego HTML’a ‚luzem’ poza funkcjami. Ten plik jest wykonywany zanim jeszcze wypisana jest pierwsza literka serwisu. Cokolwiek on wypisze, będzie Ci rozwalać serwis.

      Innym wytłumaczeniem może być jakiś wyskakujący błąd, ale wtedy powinieneś go widzieć.

  7. Cześć. Mam problem z motywem potomnym dla motywu SnapWire – jego włączenie powoduje wyświetlenie pustej strony (źródło strony też jest pustym dokumentem). Z całą pewnością nie ma błędu w pliku css motywu potomnego – zresztą jak tworzę child theme dla jakiegokolwiek innego zainstalowanego u siebie motywu wszystko jest ok, tworzy się prawidłowo motyw potomny.
    Czy problemem może być to, że motyw zawiera 3 alternatywne arkusze styli dark.css, default.css i grey.css, w katalogu wp-content/themes/snapwire-master/styles, analogicznie jak opisałeś to dla TwentyEleven?
    Mój niedoszły motyw nadrzędny: http://www.gabfirethemes.com/themes/snapwire/
    Będę wdzięczna za pomoc, dziękuję.
    Pozdrawiam!

    • No przykro mi, ale ten motyw nie jest zrobiony zgodnie ze sztuką wordpressową, więc nie da się zrobić do niego motywu pochodnego zgodnie ze sztuką 🙂 Ale na szczęście autorzy motywu podają przepis jak to zrobić lewą ręką przez prawe ramię. Jest tutaj.

  8. Naprawdę głupia sprawa, że sama tego nie znalazłam ;/ Dziękuję.

    • Nie ma sprawy. Pracuję z gościem, który zawsze znajduje w Googlu rzeczy których ja nie mogę znaleźć, więc wiem jak to jest 🙂

  9. A co przy założeniu: gdy chcę zmodyfikować zawartość plików header, footer, może widok pojedynczej strony używając motywów potomnych?
    Do modyfikacji stylów jest to jak najbardziej świetne rozwiązanie. Ale co, gdy chcę bardziej ingerować w strukturę plików motywu nadrzędnego? Jest na to jakaś możliwość?

    • Jeśli chcesz zmodyfikować jeden z plików PHP motywu, kopiujesz go do katalogu z motywem potomnym i tam modyfikujesz. WordPress dołączy Twoją, zmodyfikowaną kopię, a zignoruje oryginalna w katalogu motywu nadrzędnego. To się odnosi do wszystkich standardowych plików motywu, czyli wymienionych w kodeksie w Template hierarchy, jeśli motyw nadrzędny ich używa. Jeśli Twoje zmiany są tak daleko idące, że musiałbyś zmodyfikować większość plików, korzystanie z mechanizmu motywów potomnych mija się z celem. Wtedy skopiuj motyw nadrzędny, zmień mu nazwę, żeby przypadkiem sobie potem nie zaktualizować (bo nadpiszesz własne zmiany) i modyfikuj go do woli.

  10. Witam,
    świetny artykuł. Mam pytania:
    1. Czy wszystkie zmiany w kodzie mam przeprowadzać na dziedzicznym temacie, a aktualizacje motywu na pierwotnym?
    2. Czy aktualizacje pluginów mają być przeprowadzane na pierwotnym temacie czy nie ma to znaczenia?
    3. Który temat ma być aktywny „na co dzień”? Pierwotny czy dziedziczny? Tzn, które temat ma byś wyświetlany dla użytkowników, gości mojej strony internetowej?
    4. Jeżeli aktualizację przeprowadzę na pierwotnym temacie to czy te aktualizacje zostaną wprowadzone do tematu dziedzicznego?

    Proszę o wyjaśnienie tych kwestii.
    Serdecznie pozdrawiam,
    Tomek

  11. Skąd wziąć ten kod do zmiany czcionki? Gdy chciałem pobrać taki kod czcionki droid sans ze strony google fonts to miał on taką postać:

    Kod we wpisie wygląda całkiem inaczej

  12. Pingback: WordPress – motywy potomne | lukrecjan

  13. Do ustalenia kolejności wczytywania stylu potomnego można wykorzystać parametr $deps w funkcji wp_register_style.

  14. Właśnie czegoś takiego szukałem. Dzięki!. Niestety na wielu dostępnych kursach pokazuje się modyfikację motywów, które giną po kolejnej aktualizacji!

  15. A co zrobić jeżeli motyw NADRZĘDNY jest jednocześnie motywem POTOMNYM innego szablonu ? Kupiłem szablon i do jego działania jest potrzebny Framework Klasik który w sumie jest motywem.
    Teraz gdy próbuje utworzyć motyw potomny wyskakuje komunikat iż :

    Poniższe motywy zostały zainstalowane, ale są niekompletne. Motywy muszą składać się co najmniej z arkusza stylu i szablonu.

    Motyw „test” nie jest prawidłowym motywem nadrzędnym.

  16. To u mnie trochę lipa, mam płatny motyw VOICE. Wystarczy że utworzę plik style.css tak jak napisałeś, wgram na ftp, załączę motyw-dziecko i menu na stronie znika. Co może być powodem?