Szablony w JavaScript z użyciem wp.template

Generowanie dużych ilości kodu HTML w JavaScript jest uciążliwe bez odpowiednich narzędzi. JavaScript dopiero niedawno wzbogacił się dzięki standardowi ES2015 (ES6) o wsparcie wielolinijkowych ciągów znaków. Jeżeli chcemy wspierać starsze przeglądarki to musimy skorzystać z innych rozwiązań. Handlebars czy Mustache wyglądają kusząco, ale warto pamiętać, że WordPress posiada już własny mechanizm szablonów dla JavaScript dostępny dzięki funkcji wp.template.

Jest to silnik szablonów wykorzystywany w bibliotece Underscore.js z własną składnią podobną do tej znanej z Mustache by uniknąć konfliktów z niektórymi konfiguracjami PHP. W tym wpisie przyjrzymy mu się bliżej 🙂

Podstawy

Szablony tworzymy wewnątrz znaczników <script> z atrybutem type="text/html" – dzięki temu kod wewnątrz nich nie jest parsowany jako JavaScript. Dodatkowo szablon powinien mieć nadany atrybut id, który będzie służył do identyfikacji danego szablonu.

Uwaga! Atrybut id musi zaczynać się od prefiksu tmpl- – bez tego wczytywanie szablonu poprzez wp.template nie zadziała.

Stwórzmy zatem pierwszy szablon:

<script type="text/html" id="tmpl-helloworld">
   <strong>Hello World!</strong>
</script>

Do naszego szablonu możemy się dostać poprzez wywołanie:

var testTemplate = wp.template('helloworld');

Jak widać – nie stosujemy tutaj już prefiksu tmpl- by podać nazwę naszego szablonu.

Dodatkową zaletą silnika szablonów jest fakt zapisywania wyników wywołań funkcji wp.template – zatem wielokrotne wykorzystanie danego szablonu będzie po pierwszym wywołaniu już dużo szybsze dzięki wykorzystaniu _.memoize z Underscore.js.

By zobaczyć efekty działania naszego kodu możemy teraz wypisać gdzieś zawartość naszego szablonu poprzez wywołanie funkcji testTemplate:

console.log(testTemplate());

Tak. Wywołanie wp.template zwraca kolejną funkcję – jest ona potrzebna do obsługi zmiennych.

Zmienne i kod wewnątrz szablonów

wp.template wspiera trzy rodzaje wstawek:

  • {{data.variableName}} – zmienne, które są dodatkowo przetwarzane przez funkcje escape’ujące,
  • {{{data.variableName}}} – zmienne, które nie będą dodatkowo przetwarzane,
  • <# code to evaluate #> – kod JavaScript wykonywany w danym miejscu szablonu

Wszystkie zmienne muszą być wywoływane z poziomu obiektu data.

Przykład użycia w szablonie wszystkich rodzajów wstawek:

<div class="{{{data.classname}}}">
	<# if(data.message == '') { #>
           Empty message
	<# } else { #>
           {{data.message}}
	<# } #>
</div>

Własna składnia i prefiksy

Implementacja funkcji wp.template nie jest szczególnie skomplikowana – poniżej kod z pliku wp-includes/js/wp-util.js bez komentarzy:

wp.template = _.memoize(function ( id ) {
	var compiled,
		options = {
			evaluate:    /<#([\s\S]+?)#>/g,
			interpolate: /\{\{\{([\s\S]+?)\}\}\}/g,
			escape:      /\{\{([^\}]+?)\}\}(?!\})/g,
			variable:    'data'
		};

	return function ( data ) {
		compiled = compiled || _.template( $( '#tmpl-' + id ).html(), null, options );
		return compiled( data );
	};
});

Zatem jak widać relatywnie łatwo można stworzyć własną wersję tej funkcji i zmienić elementy takie jak:

  • składnia wstawek,
  • nazwa zmiennej zawierającej parametry szablonu,
  • prefiks znaczników <script>.

Jeszcze jedna zaleta stosowania wp.template

Korzystanie z szablonów powoduje, że nie musimy eksportować do JavaScript zmiennych językowych poprzez wp_localize_script – gdyż szablony generujemy z poziomu PHP.

A co jeśli wp.template nie działa?

Może się zdarzyć, że funkcja wp.template będzie niedostępna – wystarczy wtedy do listy zależności naszego skryptu dodać wp-util:

wp_enqueue_script( 'script_name', plugin_dir_url( __FILE__ ) . 'my-script.js', array('wp-util'), '1.0', true );

Krótkie szablony

Niestety ze względu na konstrukcję wp.template nie możemy stworzyć krótkich szablonów bez użycia znaczników <script> – co powoduje, że dla krótszych szablonów wp.templatemoże powodować dodatkowy narzut kodu – gdy chcemy konsekwentnie stosować jeden sposób generowania kodu HTML.

Podsumowanie

Funkcja wp.template to całkiem wygodne rozwiązanie dość częstych problemów z generowaniem dłuższych fragmentów kodu HTML. Powinna się ona sprawdzić w większości typowych zastosowań – jest ona na przykład intensywnie wykorzystywana w ekranie personalizacji motywu WordPressa.