Vásárolt WordPress Sablon Bővítése – Esettanulmány

A feladat a következő: a sablonban megtalálható egyéni bejegyzés-szerkesztő kibővítése új mezőkkel, és az ehhez tartozó funkcionalitás kialakítása a sablonban. Mindezt lehetőleg úgy, hogy ne a vásárolt sablon fájljait szerkesszük, hanem plusz kódot adjunk hozzá valamiféleképpen, hogy a sablon továbbra is frissíthető maradjon.

Kontextus

Adott egy egyéni bejegyzés-típus (“portfolio“), ami a sablonban van regisztrálva, és az egyes elemek (bejegyzések) jellemzőit Advanced Custom Fields mezők kitöltésével adhatja hozzá az adminisztrátor.

ACF mezők a “portfolio” bejegyzéseknél

Ezen típusba tartozó bejegyzések különböző stílusú galériákban megjeleníthetők, pl. egészoldalas, carousel, stb. A galériákat blokként vagy shortcode-dal lehet hozzáadni az egyes oldalakhoz. A galériák már be vannak illesztve előre létrehozott oldalakra – a végfelhasználónak leginkább csak a portfolio bejegyzéseket kell majd kezelnie, ehhez kellenek új mezők.

A feladatok

  1. A galériákban megjelenik egy “Tovább” gomb, ami elvezet az adott portfolio bejegyzésre (“single post” nézetre). Azt szeretnénk, hogy ez a link egy egyénileg megadott URL-re mutasson, nem pedig a bejegyzés linkjére. Ez lenne az első extra mező ACF-ben.
  2. Minden galériában megjelenik az összes portfolio bejegyzés. Azt szeretnénk, hogy közvetlenül a szerkesztőben megadhassuk, mely oldalakon jelenjen meg egy adott bejegyzés, és melyeken ne. Ehhez kéne még egy ACF mező.

Új mezők hozzáadása a szerkesztőfelülethez

A fenti screenshot-on látható mezők alá akarunk két új mezőt hozzáadni. Ehhez meg kell keresnünk a sablon fájljaiban a kódot, ahol ezeket a mezőket regisztrálja. Mivel tudjuk, hogy Advanced Custom Fields mezőkről van szó, ezért első körben ehhez kapcsolódó fájlneveket keresünk. Ha nem találunk ilyen fájlt, akkor érdemes letölteni az összes sablonfájlt a saját gépünkre, majd valamilyen fájlszerkesztő vagy fájlkezelő programmal az összes fájl tartalmában egyszerre keresni, például az egyik mező nevére: “Meta 1 Title“, vagy arra, hogy “acf“.

A kérdéses sablonban meg is találtuk a fájlt, amiben szerepel a kód:

acf_add_local_field_group(array(
	'key' => 'group_5f05a7575b216',
	'title' => 'Portfolio Meta',
	'fields' => array(
		array(
			'key' => 'field_5f05ac0726f03',
			'label' => '',
			'name' => 'meta_1_title',
			'type' => 'text',
			'instructions' => '',
			'required' => 0,
			'conditional_logic' => 0,
			'wrapper' => array(
				'width' => '50',
				'class' => '',
				'id' => '',
			),
			'default_value' => '',
			'placeholder' => '',
			'prepend' => 'Meta 1 Title',
			'append' => '',
			'maxlength' => '',
		),
[...]

Az ACF dokumentációjából megtudható, hogyan kell hozzáadni egy új mezőt egy létező mezőcsoporthoz: az acf_add_local_field() függvényt kell használni, és meg kell adni a mezőcsoport nevét a parent paraméterben. A mezőcsoport neve az acf_add_local_field_group() függvény key paraméterében található – a fenti kódban ez “group_5f05a7575b216“.

A kódunkat ajánlott az acf_init action hook-ban lefuttatni, de mindenképp az alap mezőket regisztráló sablon kód után kell. Az acf_init használatának az előnye, hogy csak akkor fog lefutni a kód, ha telepítve van az Advanced Custom Fields, így nem fog hibára futni, amikor valamiért deaktiváljuk az ACF plugint.

Az egyéni mezőket hozzáadó kódunk így fog kinézni:

/**
 * ACF mezők hozzáadása.
 *
 * @return void
 */
function oldalneveponthu_acf() {
	acf_add_local_field( array(
		'key'          => 'link_url',
		'label'        => 'Tovább Gomb Link',
		'instructions' => 'Ha üresen hagyjuk, akkor az alap portfolio-link lesz használva.',
		'name'         => 'moreinfo_url',
		'type'         => 'url',
		'parent'       => 'group_5f05a7575b216',
		'wrapper'      => array(
			'width' => '50',
		),
	) );

	acf_add_local_field( array(
		'key'           => 'show_on_pages',
		'label'         => 'Elem Megjelenítése Itt',
		'instructions'  => 'Ez az elem csak a kijelölt oldalakon fog megjelenni.',
		'name'          => 'show_on_pages',
		'type'          => 'select',
		'default_value' => '',
		'ui'            => 1,
		'multiple'      => true,
		'parent'        => 'group_5f05a7575b216',
		'choices'       => oldalneveponthu_get_pages(),
		'allow_null'    => true,
		'placeholder'   => 'Válasszuk ki az oldalakat',
		'wrapper'       => array(
			'width' => '50',
		),
	) );
}
add_action( 'acf/init', 'oldalneveponthu_acf', 20 );

A kódban a következő dolgok történnek:

  1. A link_url mező hozzáadása, ami egy szöveges (URL) mező. Ebben semmi különös nincs, a szokásos paramétereket adjuk meg hozzá.
  2. A show_on_pages mező hozzáadása, ami egy “select” (legördülő menü) típusú mező, amiben több érték is kiválasztható ('multiple' => true), és mivel a 'ui' => 1 paraméter is meg van adva, ezért nem legördülő menüként, hanem kiválasztható “címkékként” fog megjelenni a mező (lásd lejjebb). A választható értékek (choices paraméter) az oldalneveponthu_get_pages() egyéni függvényből jön.

A oldalneveponthu_get_pages() függvény így néz ki:

/**
 * Oldalak listázása, az admin checkboxokhoz.
 *
 * @return void
 */
function oldalneveponthu_get_pages() {
	$out   = array();
	$pages = get_pages( array( 'hierarchical' => false ) );

	foreach ( $pages as $post ) {
		$out[ $post->ID ] = $post->post_title;
	}

	return $out;
}

Ez a függvény az összes létrehozott oldalt listázza egy tömbként, mégpedig “ID => Oldalcím” formátumban. Így a felhasználó az oldalcímeket látja a mezőben, az adatbázisba elmentett értékek pedig az ID-k lesznek.

Egyéni plugin létrehozása

Mivel azt akarjuk, hogy a sablont továbbra is frissíteni lehessen, ezért nem szerkeszthetjük közvetlenül. A vásárolt sablonoknál és bővítményeknél nagyon fontos, hogy mindig a legfrissebb verziót használjuk (itt leírtuk miért: A WP Frissítésekről). Ha egy egyéni sablonról lenne szó, és nem várható soha frissítés hozzá, akkor nyugodtan szerkeszthetnénk magát a sablont is.

Így a következő lehetőségeink vannak a kód hozzáadására:

  • Származtatott sablon (child theme)
  • Egyéni bővítmény
  • Kötelezően használandó bővítmény (mu-plugin)

Az egyes módszerek különbségeiről az egyéni kóddal kapcsolatos cikkünkben írtunk.

Jelen esetben az egyéni bővítményt választottuk. Létrehoztunk egy új mappát a /wp-content/plugins mappában, és benne egy új PHP fájlt, a következő tartalommal:

<?php
/**
 * Plugin Name:       OldalNevePontHu Webhely-plugin
 * Plugin URI:        https://oldalneve.hu
 * Description:       Az OldalNevePontHu webhellyel kapcsolatos egyéni kódok.
 * Version:           1.0
 */

Ez alá pedig beillesztettük a fenti ACF mezőket regisztráló kódot. Az új plugin aktiválása után az admin felületen meg is jelennek az új mezők:

Az általunk hozzáadott új ACF mezők

Az új mezők ott vannak, és el lehet menteni az egyéni post meta értékeket, de nincsen semmilyen funkciójuk még.

1. Új funkció: “Tovább” gomb link módosítása

A sablonfájlokban kikerestük azt a részt, ami megjeleníti a linket. Így néz ki:

<a href="<?php echo get_the_permalink(); ?>">

A get_the_permalink() egy alap WP függvény, és az értéke módosítható a post_type_link filterrel. Ezt használva ki tudjuk alakítani a kívánt funkciót:


/**
 * Link kicserélése, ha szükséges.
 *
 * @param string $url     Permalink.
 * @param int    $post_id Post ID.
 * @return string
 */
function oldalneveponthu_portfolio_permalink( $url, $post_id ) {
	if ( ! function_exists( 'get_field' ) ) {
		return $url;
	}

	if ( ! is_page() || get_post_type( $post_id ) != 'portfolios' ) {
		return $url;
	}

	$link_url = get_field( 'link_url' );
	if ( ! $link_url ) {
		return $url;
	}

	return $link_url;
}
add_filter( 'post_type_link', 'oldalneveponthu_portfolio_permalink', 20, 2 );

Ebben a kódban a következők történnek:

  1. Az if ( ! function_exists( 'get_field' ) ) { sorral ellenőrizzük, hogy az ACF plugin aktiválva van, hogy ne legyen PHP hiba, amikor nincs. Ha az ACF nem aktív, és a get_field() funkciója nincs definiálva, akkor simán visszaadjuk a filternek az eredeti $url értéket a return $url; sorral. Így az alatta lévő kódok nem futnak le.
  2. Az if ( ! is_page() || get_post_type( $post_id ) != 'portfolios' ) { sorral ellenőrizzük, hogy jelenleg egy oldalt (page típusú bejegyzést) nézünk-e, illetve, hogy a kért permalink portfolio típusú bejegyzéshez tartozik-e. Ha ezek közül bármelyik nem teljesül, akkor csakúgy mint az előző feltételnél, itt is visszaadjuk módosítatlanul az $url-t.
  3. A $link_url = get_field( 'link_url' ); sorban lekérjük az ACF mezőben elmentett link_url értékét. Ha nincs megadva egyéni URL ebben a mezőben, akkor az if ( ! $link_url ) { feltétellel megint csak visszaadjuk az eredeti $url-t.
  4. Ha minden oké, és az előző feltételeken túljutott a kód, akkor visszaadjuk az egyéni URL-t, a return $link_url; sorban.

A kódot az egyéni plugin fájlba beillesztve működik is a funkció, ahogy kell: ha meg van adva egy egyéni “Tovább Gomb Link”, akkor a galériában megjelenő “Tovább” gomb arra a linkre mutat, nem pedig a portfolio oldalra.

2. Új funkció: “portfolio” bejegyzések szűrése oldal szerint

A portfolio bejegyzéseket a sablon a WP_Query osztály segítségével tölti be, egy ehhez hasonló kóddal:

$args = array(  
	'post_type' => 'portfolios',
	'post_status' => 'publish',
	'posts_per_page' => 10,
);

$loop = new \WP_Query( $args ); ?>
<div class="portfolio-gallery">
	<?php while ( $loop->have_posts() ) : $loop->the_post(); ?>
	<div class="gallery-item">
		<h3><?php the_title(); ?></h3>
		[...]
	</div>
	<?php endwhile; ?>
</div>

Szerencsére itt is elérhető egy filter hook (a pre_get_posts filter), amivel módosíthatjuk a WP_Query lekérés paramétereit mielőtt az lefut, így leszűrhetjük a bejegyzéseket, hogy csak azokat mutassa, amiket bejelölt a felhasználó.

A kódunk így fog kinézni:

/**
 * Elemek elrejtése a gyűjtő oldalakon, ha szükséges.
 *
 * @param WP_Query $query WP Query object.
 * @return void
 */
function oldalneveponthu_exclude_portfolios( $query ) {
	if ( is_admin() || ! is_page() || $query->is_main_query() || $query->get( 'post_type' ) != 'portfolios' ) {
		return;
	}

	$page_id    = get_the_ID();
	$meta_query = array(
		'relation' => 'or',
		array(
			'key'     => 'show_on_pages',
			'compare' => '=',
			'value'   => $page_id,
		),
		array(
			'key'     => 'show_on_pages',
			'compare' => 'LIKE',
			'value'   => '"' . $page_id . '"',
		),
	);

	$query->set( 'meta_query', $meta_query );
}
add_action( 'pre_get_posts', 'oldalneveponthu_exclude_portfolios' );

A kódban ezek a lépések futnak le:

  1. Először is ellenőrizzük, hogy le kell-e futnia a kódunknak vagy sem: if ( is_admin() || ! is_page() || $query->is_main_query() || $query->get( 'post_type' ) != 'portfolios' ) {
    Mivel a pre_get_posts szinte minden oldalon többször is lefut (amikor bármilyen bejegyzést lekér a rendszer), de nekünk csak azokat a kéréseket kell szűrnünk, amikre a következők mind igazak:
    1. Nem az admin oldalon vagyunk épp: is_admin()
    2. Egy adott oldalt nézünk, “single page” nézetben: is_page() (mivel ezekre vannak beillesztve a galériák)
    3. Nem az oldal “fő kéréséről” van szó: $query->is_main_query()
      A fő kérés az, amiben a rendszer magát az oldalt kéri le a megjelenítéshez (címét, tartalmát, stb.)
    4. A kérés portfolio típusú bejegyzéseket kér le: $query->get( 'post_type' ) != 'portfolios'
  2. Ha a fenti feltételek közül bármelyik nem teljesül, akkor a return; sorral egyből le is zárjuk a függvényt, nem futtatjuk tovább, és nem módosítunk semmit.
  3. Ezután a WP_Query-nek a meta_query paraméterével beállítjuk, hogy csak azon portfolio elemeket mutassa, amelyeknél a show_on_pages meta érték egyenlő a jelenlegi oldal ID-vel ('compare' => '='), vagy pedig tartalmazza azt ('compare' => 'LIKE'), amennyiben a show_on_pages több értéket is tárol.

Ezzel a kóddal már úgy működik a dolog, ahogy kell: minden oldalon (“page” típusú bejegyzésnél, “single post” nézetben) lefutó portfolio-t lekérő WP_Query szűrve lesz a függvényünk által, és csak a jelen oldalhoz kiválasztott portfolio elemeket fogja visszaadni.

+1 Funkció: mezők magyarítása

Mivel az oldal sosem lesz többnyelvűsítve, ezért az egyéni kódban nem használtuk a gettext fordítási funkciókat. Ha fordíthatóvá és többnyelvűsíthetővé akarjuk tenni a kódot, akkor minden, a felhasználó számára látható szövegnél használni kell a megfelelő fordítási funkciót, pl. ehelyett: 'Tovább Gomb Link' ezt kell írnunk: __( 'Tovább Gomb Link', 'oldalneveponthu-plugin' ).

Viszont a vásárolt sablon eredeti készítője sem használta a fordítási funkciókat mindenhol, ahol kellett volna, így a sablon szövegei nem lefordíthatóak a hagyományos módokon (.po fájlokkal, a Poedit app vagy a Loco Translate bővítmény segítségével). Például ez a sor nem fordítható:

'title' => 'Portfolio Meta',

Így kéne kinéznie a sornak, hogy könnyen lefordítható legyen az adminisztrátor számára:

'title' => __( 'Portfolio Meta', 'sablonneve' ),

Szerencsére az ACF egyik filter hook-ját használva át lehet írni ezeket a sorokat:


/**
 * Mező nevek és leírások fordítása.
 *
 * @param array $field
 * @return array
 */
function oldalneveponthu_translate_fields( $field ) {
	switch ( $field['label'] ) {
		case 'Summary':
			$field['label']        = 'Leírás';
			$field['instructions'] = 'Elem teljes leírása.';
			break;

		case 'Excerpt':
			$field['label']        = 'Rövid leírás';
			$field['instructions'] = 'Elem rövid bemutatója.';
			break;
	}
	return $field;
}
add_action( 'acf/prepare_field', 'oldalneveponthu_translate_fields' );

Ez a kód minden ACF mező paramétereit tudja módosítani. A label paraméter (a mező címkéje) alapján célozva változtathatjuk meg a paramétereket. Például, ha a label “Summary”, akkor a label paraméter változzon arra, hogy “Leírás”, és az instructions paraméter (a mező kitöltési útmutatója) pedig legyen “Elem teljes leírása”. A label paraméter helyett célozhatunk akármelyik másik paraméter alapján is, például a key-vel, és ebben az esetben így változik a kód:

[...]
	switch ( $field['key'] ) {
		case 'field_5f05ac0726f03':
[...]

Ez a kód annak a feltételnek felel meg, hogy “ha a mező key paramétere field_5f05ac0726f03, akkor […]”.

Végszó

Az általunk lérehozott egyéni pluginnal hozzáadtuk a kívánt funkciókat, sőt, még a sablon hiányosságán is javítani tudtunk, anélkül, hogy a sablon fájljait szerkesztettük volna. Megkönnyítette a dolgunkat, hogy a sablon az Advanced Custom Fields-et használta a mezők hozzáadásához, mivel az ACF egy fejlesztőbarát, könnyen bővíthető plugin.


A Szerzőről
Piller Balázs senior webfejlesztő, SEO specialista, és a WordPress szakértője. Számos sikeres projektben vett részt vezető fejlesztőként. Az általa írt kód jelenleg több mint 1 000 000 webhelyen fut.

Vélemény, hozzászólás?

Az e-mail-címet nem tesszük közzé. A kötelező mezőket * karakterrel jelöltük