CSS osz­tály hoz­zá­adá­sa pa­ra­gra­ph tí­pu­sa alap­ján, Dru­pal 8-ban

Várkert bazár kép illusztráció

„Adott egy paragraph, ami további paragraphokra hivatkozik. Szeretnék a hivatkozó elemre egy plusz classt tenni, ami a hivatkozott elem típusától függ. Ha egy képre hivatkozik, akkor »aside-image«, ha szövegre, »aside-text«.” Ezzel a kéréssel fordultam nemrégiben a többiekhez.

A segítségemre Vince sietett, aki néhány tisztázó kérdés után szállította a működő kódot. Én meg – amellett, hogy örültem nagyon – csak néztem, hogy miként oldotta meg ezt így, pikk-pakk!

Pár nappal ezelőtt ezt is elmesélte.

Jó, jó de minek ez az egész?

A látványterven, amit kaptam, kéthasábos elrendezés szerepel. A fő hasáb mindig szöveg, mellette azonban kép vagy szöveg is megjelenhet. És attól függően, hogy mi van oldalt, más-más a két hasáb közötti távolság illetve a kiegészítő mérete is.

Nem szerettem volna emiatt két külön hivatkozó paragraph típust létrehozni. És a leendő tartalomszerkesztőket sem akartam azzal terhelni, hogy külön be kelljen jelölniük, milyen típusú kiegészítőt választottak. Az tűnt az elegáns megoldásnak, hogy automatizáltan jelenítünk meg egy classt, amivel a doboz layoutot tudom befolyásolni. Hiszen a szükséges típus adat elérhető a rendszerben!

No igen. Elérhető. Hogyan is?

Első lépés: theme suggestions és preprocess

A paragraphs modul háromféle theme hook suggestion-t ad meg.

  1. paragraph__[view_mode] (pl. paragraph--default.html.twig)

  2. paragraph__[type] (pl. paragraph--image.html.twig)

  3. paragraph__[type]__[view_mode] (pl. paragraph--image--default.html.twig)

Ez az információ még megtalálható a dokumentációban is, Vince azonban – az egyszerűség kedvéért – a modul forráskódjában kereste meg.

Fontos tudni, hogy a theme hook suggestion-ök, nem csak a használandó template-re adnak javaslatot, hanem az elem renderelése során meghívandó preprocess függvények listáját is bővítik.

Így a következő logikus lépés a paragraphs alapértelmezett preprocess funkciójának a megvizsgálása volt.

Eredet, avagy: mélyebbre kell menni

„Szerencsére” a hivatkozás szabványos módon, mezőn keresztül történik. A mezőkhöz mindig tartozik adatbázis tábla, aminek a felépítése meghatározott struktúrát követ.

A field táblák első 3 mezője az értéket tartalmazó entitást írja le (bundle, entity_id, revision_id). A következő 3 (deleted, langcode, delta) a konkrét értékre vonatkozik: Törölt érték? Milyen nyelvű az érték, hányadik elem a több elemű listában?

Minden további oszlopot a mező típusa határoz meg. Egyszerű típusoknál egy plusz oszlop lesz, aminek a neve általában a [field neve]_value mintát követi.

Az összetett esetben a mező típusa határozza meg, hogy milyen nevű és típusú oszlopok lesznek a táblában.

Sorról-sorra

Íme a kész megoldás:

/**
* Implements hook_preprocess_paragraph().
*
* Paragraph preprocess for ‘Text and Aside’ typed paragraphs.
*/
function THEMENAME_preprocess_paragraph__text_and_aside(&$variables) {
 /** @var Drupal\paragraphs\Entity\Paragraph $paragraph */
 $paragraph = $variables['elements']['#paragraph'];

 foreach ($paragraph->get('field_paph_aside')->getValue() as $item) {
   /** @var Drupal\paragraphs\Entity\Paragraph $sub_item */
   $sub_item = \Drupal\paragraphs\Entity\Paragraph::load($item['target_id']);
   $variables['attributes']['class'][] = 'aside-' . $sub_item->bundle();
 }
}

Nézzük meg, mi micsoda a fenti kódban:

function THEMENAME_preprocess_paragraph__text_and_aside(&$variables)
Ez a függvény a sminkben egy preprocess hook-ot valósít meg, ami a Text and aside típusú paragraph-ok megjelenítésére lesz hatással.

/** @var Drupal\paragraphs\Entity\Paragraph $paragraph */
A @var komment sorokat a fejlesztő környezet (ld: IDE, PHPStorm) számára ad információt, hogy a $paragraph változó milyen típusú értéket tartalmaz. Erre az információra építve tudja a kódkiegészítést építeni.

A $variables-ben megkaptuk az éppen megjelenített paragraph entitást is.

$paragraph = $variables['elements']['#paragraph'];
Az éppen megjelenített $paragraph-tól elkérjük az általa hivatkozott paragraphokat és végignézzük mindegyiket.

foreach ($paragraph->get('field_paph_aside')->getValue() as $item) {
A hivatkozott paragraph-ot az azonosítója alapján betöltjük...

$sub_item = \Drupal\paragraphs\Entity\Paragraph::load($item['target_id']);
... majd elkérjük, hogy milyen típusú (bundle). Ezt az értéket használva a hivatkozó paragraph class listájához adunk egy új elemet.

$variables['attributes']['class'][] = 'aside-' . $sub_item->bundle();

Az eredmény

Epilógus: Preprocess nélkül

A preprocess nem az egyetlen módja, hogy a szükséges class-t hozzáadjuk a hivatkozó paragraph-hoz. Létrehozhatunk egy saját twig sablont (paragraph--text-and-aside.html.twig) a számára. Ebben a következőképp hozhatjuk létre a hivatkozott elem típusát tartalmazó változót (amit aztán class-ként hozzáadhatunk az attribútumokhoz):

{% set aside_bundle = paragraph.field_paph_aside.entity.type.0.target_id %}

Ez a megoldás Mark Conroy-tól származik, a DrupalTwig Slack csatornából.

Köszönet Vincének a fenti bejegyzés elkészítésében nyújtott segítségéért is!

Oszd meg ismerőseiddel!