Blog

Saját sticky menü készítése JavaScript görgetés figyeléssel és HTML elem magyarázó

Saját sticky menü készítése JavaScript görgetés figyeléssel és HTML elem magyarázó 2000 1258 bacsoa

Gyakran szembe jött már velem az a probléma, hogy több sticky, azaz ragadós menüre volt szükség. Sokan, sokféle eszközt használnak erre, de sokszor legegyszerűbb a saját. Most leírom hogyan kell egy ilyet megcsinálni.

A sticky menü általában akkor kell, ha a főmenüt, vagy annak egy részét fixen oda akarjuk ragasztani, amikor görgetés közben a böngészőben elértük annak pozícióját. Ehhez a generált HTML kód vizsgálatára és megváltoztatására van szükség, amit Javascript-ben fogok megírni. A PHP-vel ellentétben, ami szerveroldalon fut, a Javascript-et a kliensoldalon használjuk. A kliens oldal maga a böngésző, amit a weboldalunk látogatója lát és, azaz kattint, görget és úgy általában használ. A kliens oldal elemei a böngésző által feldolgozott és megjelenített, generált HTML kód. Ebben szeretnénk most és tudunk is turkálni a JavaScripttel.

Ahhoz, hogy a JavaScriptet hatékonyan tudjuk használni természetesen elengedhetetlen a HTML és a CSS használata. Mindezekről most nem írok hosszan, de akit érdekel az erről szóló cikkem, az ezt olvassa el.

A feladat tehát annyi, hogy egy oldal adott eleméhez érve azt „odaragasztjuk” a képernyő tetejére, tehát a látogató ezt mindig eléri akkor is, így kényelmesen tud navigálni az egyes lehetőségek között és nem kell mindig visszagörgetnie ehhez a részhez. Meg kell csinálnunk természetesen visszafelé is, ha felfelé hagyjuk el ezt a részt, akkor visszatesszük a normál, azaz a „ragadásmentes”, eredeti állapotába.

Mi kell ehhez? Azért szeretem a fejlesztői munkát, mert nagyon kreatív. Ezt a feladatot ugyanis többféleképpen meg lehet oldani, és mi tudjuk kiválasztani, hogy melyik a szimpatikus. Nem az a lényeg, hogy mennyire elegáns a kód, hanem az, hogy működjön, az ügyfél pedig elégedett legyen. Persze, ha fenntartható kódot szeretnénk, akkor erre is figyeljünk, de ez a cikk most nem erről szól.

  1. Kiszámoljuk az összes olyan elem magasságát az oldal tetejétől addig a pontig, ahol a sticky menü elkezdődik.
  2.  Inicializálunk az onscroll eseményfigyelőt (ún. event listener), ami folyamatosan figyel méghozzá csak akkor, ha görgetünk, egyébként nem csinál semmit. A Javascriptben vannak beépített, a HTML szabványhoz tartozó, és az adott böngészőben működő és vannak az egyedi, általunk írt eseményfigyelők. Mi most az alapértelmezett, minden böngészőben elérhető onscroll eseményfigyelőt fogjuk használni.
  3. A görgetés közben figyeljük hol áll a pozíció és ha elérte a kívánt magasságot (azaz a látogató scrollozás közben odaért a kívánt elemhez), akkor hozzáadunk a body DOM elemhez valamilyen egyedi osztályt, hogy majd CSS-sel tudjunk rá hivatkozni. Ha újra elhagyta a látogató ezt a pozíciót, tehát fölfelé görgetett, akkor pedig levesszük róla ugyanezt az osztályt. Így a kétféle állapotot meg tudjuk majd különböztetni egymástól, így annak pozícióját is el tudjuk különíteni.

Csinálhatjuk jQuery-vel, vagy normál Javascripttel is. Én most az utóbbit fogom bemutatni, mert az mindenhol működik, és nem kell hozzá semmi, bárhol, bármilyen környezetben alkalmazható, dependency, azaz függőség nélkül. A dependency azt jelenti, hogy egy adott metódus csak egy másik metódussal együtt működik. Ilyen a jQuery is, ahhoz, hogy az általa megadott egyszerűsített eszközöket használni tudjuk, előbb be kell tölteni a böngészőnek a jQuery-t. A Javascript történetéről most nem írok le egy regényt, akit érdekel, az erre nézelődjön., de ez az oldal is jó kiindulópont lehet.


// Definiáljuk a DOM elemet, hogy később hivatkozhassunk rá.
// Ehhez az elemhez fogjuk később az egyedi osztályt (class) adni
// Azért a elemhez adjuk, mert ez van majdnem legfelül a HTML hierarchiában, így az ez alatti bármely elemre tudunk hivatkozhatunk
const theBody = document.querySelector(`body`);

// Képernyő szélessége: ez opcionális, használhatjuk pl. egy feltételnél, hogy az egész csak akkor fusson le, ha pl. mobilnézetben vagyunk
var screenWidth = window.innerWidth;

// Az első elem, aminek az oldal tetejétől ki kell számolnunk a magasságát
var headerDiv = document.querySelector(`#header-outer`);

// A többi kiszámolandó elem ez alatt az elem alatt található, ami alatt ki kell számoljuk az összes elem magasságát
var mainDiv = document.querySelector(`#ajax-content-wrap .container-wrap .container.main-content div.row`);

// Az előző elem alatti két gyerek elem, mindkettő magassága kell, mivel ez után következik maga a menü
var firstChildDiv = mainDiv.children[0];
var secondChildDiv = mainDiv.children[1];

// Mivel megvan minden elem, kiszámoljuk ki az összes magasságát és összeadjuk
var totalHeight = headerDiv.offsetHeight + firstChildDiv.offsetHeight + secondChildDiv.offsetHeight;

// Görgetés eseményfigyelő (scroll event listener), ez csak akkor fut, amikor görgetünk
window.onscroll = function()
{
  // Ez a böngészőablak oldal tetejétől számolt magassága pixelben
  var windowPageOffset = window.pageYOffset;

  // Ha az oldal tetejétől legörgetett magasság nagyobb, mint az összeszámolt elemek magassága,
  // akkor elértük a sticky menüt, azaz azt az elemet, amit oda akarunk ragasztani
  if ( windowPageOffset >= totalHeight ) {
    theBody.classList.add("sticky_submenu");
  } else {
    // Ha ennek ellenkezője igaz, tehát elhagytuk fölfelé scrollozás közben ezt a területet
    // akkor visszaállítjuk az eredeti állapotot
    theBody.classList.remove("sticky_submenu");
  }

};

Ezeken a képernyőmentéseken elmagyarázom melyik rész, mit csinál. Van benne egy kis HTML alapozó is, aki még mindig nem értené, hogyan kell hivatkozni egy adott HTML elemre.

Annyit csinálok, amit a háromlépéses részben már leírtam, megnézem az elemek magasságát, összeadom, majd a görgetésfigyelővel megnézem elérte már az adott pozíció ezt az értéket vagy már meg is haladta. Ha ez igaz, akkor hozzáadom a body elemhez a `sticky_submenu` nevű osztályt, amit CSS-ben előzőleg már definiáltam. Innentől kezdve, ha a body elem rendelkezik ezzel az osztállyal, akkor az lesz rá érvényes, egyébként nem.

body.sticky_submenu .nectar-sticky-row-wrap.nectar-sticky-row-wrap--top_after_nav {
position: fixed;
top: 44px;
z-index: 99;
width: 100%;
left: 0;
}

Remélem mindenkiben sikerült felkelti az érdeklődést hogyan is működnek a DOM manipulációk és innen megnyílik egy új fejezet a Javascript metódusok és a HTML elemek módosításának fejezetében. Rövid és eredményes kódolást!

WordPress egyedi felhasználói szintek és admin felületre belépés utáni alapértelmezett oldal megváltoztatása

WordPress egyedi felhasználói szintek és admin felületre belépés utáni alapértelmezett oldal megváltoztatása 960 600 bacsoa

Egyedi felhasználói szintet kellett létrehozzak és mivel ennek a felhasználó típusnak egy csomó mindent nem szabad látnia, kézen fekvő volt máshova irányítani őt bejelentkezés után, hogy ne is keresgéljen a WordPress vezérlőpulton.

A WordPress admin felületen (hívhatnám egyszerűsítve backendnek is, de azért ez nem teljesen azt jelenti) egy külön világ van, mint a frontenden (amit a látogató lát), külön CSS beállítással, sokszor elkülönített lekérdezésekkel és sok minden mással is. Aki bele akar mélyedni a felhasználói szintekbe, az itt tudja ezt megtenni.

Első lépésben csináljunk egy új felhasználói szintet. Ehhez az add_role metódust használjuk, aminek három paramétere van:

  • egyedi azonosító slug (ékezetek és szóköz nélkül), itt organizer
  • felhasználó szint neve, ez jelenik majd meg az admin felületen a felhasználóknál, itt Szervező
  • jogok, vagyis képességek, hogy az adott felhasználó mihez férhet hozzá, itt az adminisztrátori jogokat kapja meg. Ez egy elég bonyolult képességfa, akit érdekel az összes, az erre nézelődjön
add_role(
    'organizer',
    __( 'Szervező'  ),
    get_role( 'administrator' )->capabilities
);

A fenti kód csinál egy ‘organizer’ nevű felhasználói szintet, aki gyakorlatilag egy adminisztrátori jogkörrel (aka képességekkel) rendelkező felhasználótípus.

Sok bővítménnyel, vagy egyedi eszközzel meg lehet azt csinálni, hogy mit lásson ez a felhasználó és mit sem, erre jó például a remove_menu_page, vagy a remove_submenu_page metódusok, de egy sima admin oldali inline CSS-sel is el tudunk tüntetni szinte minden menüt attól függően, hogy ki van bejelentkezve.

$user = wp_get_current_user();
$roles = ( array ) $user->roles;
$role = $roles[0];

// Megvizsgálja, hogy a bejelentkezett felhasználó típusa 'organizer' és ha igen, akkor az azon belüli rész fut le
if ( $role == "organizer" ) {

	// Elrejti a felső fekete adminisztrációs sávot
	show_admin_bar(false);

	// Beállítja az alább megadott inline CSS-t, az admin_head action csak az adminisztrációs felületen érvényes CSS stíluslapokat állítja be, tehát ennek nincs határsa a frontenden lévő sablonra
	add_action('admin_head', 'my_custom_css');
	function my_custom_css() {
	  echo '<style>
			li#menu-media, li#menu-settings {display:none;}
	  </style>';
	}

	// Ez teszi lehetővé, ha a bejelentkezett felhasználó 'organizer' típusú, akkor az itt található két speciális metódusban lévő dolgok fussanak le
	add_action( 'admin_init', 'stop_access_profile_organizer' );
	add_action( 'admin_enqueue_scripts', 'load_defaults_prevents_organizer' );

}

// Ez a rész megtiltja a hozzáférést néhány admin felületen található oldalhoz. Az előző rész csak elrejti CSS segítségével a menüpontokat, ez viszont azt akadályozza meg, ha valaki szemfüles és tudja az URL-eket fejből és oda próbál menni, akkor egy hibaüzenet kíséretében megtiltja azt
function load_defaults_prevents_organizer($hook)
{
	if ( $hook=="options-general.php" || $hook=="options-writing.php" || $hook=="options-reading.php" || $hook=="options-discussion.php" || $hook=="options-media.php" || $hook=="options-permalink.php" || $hook=="tools.php" || $hook=="widgets.php" || $hook=="customize.php" || ($hook=="post-new.php" && $_GET['post_type']=="page") || $hook=="themes.php" ) {
		wp_die( 'Nincs jogod megtekinteni ezt az oldalt.' );
	}
}

// Ezek le fogják szedni az admin felületről a bal oldalon megjelenő menüpontokat, az első a Megjelenés / Sablonok részt, a második az Oldalak menüt fogja eltüntetni
function stop_access_profile_organizer()
{
    remove_menu_page( 'themes.php' );
    remove_menu_page( 'edit.php?post_type=page' );
}

Nézzük azt a részt, hogy mit csináljunk az ‘organizer’ típusú felhasználókkal, miután sikeresen bejelentkezett. Mondjuk a Hozzászólások részhez. Ez azért jó, mert így nem egyből a Vezérlőpult részre kerül (ahova alapból mindenki), ahol még vagy 100 minden WordPress telepítésnél más és más részt kell elrejteni, hanem oda, ahova mi akarjuk:

add_action('wp_login', 'ba_new_dashboard_home', 10, 2);
function ba_new_dashboard_home($username, $user)
{
  if (array_key_exists('organizer', $user->caps)) {
    wp_redirect(admin_url('edit-comments.php', 'http'), 301);
    exit;
  }
}

Ha nem akarunk annyit inline CSS-ezni, akkor hasznos lehet, ha az ‘organizer’ típusú felhasználók esetén az admin oldal body elem osztályát kiegészítjük valamivel, így könnyebb lesz rá hivatkozni. Erre van egy speciális filter, az admin_body_class nevű. Ez teljesen ugyanazt csinálja, mint a body_class nevű filter, csak míg utóbbi a frontenden módosítja a body tag osztályait, előbb az admin felületen csinálja ugyanezt.

// Hozzáad egy egyedi osztályt a body taghez, ha egy organizer típusú felhasználó van bejelentkezve

add_filter( 'admin_body_class', 'ba_admin_body_classes' );
function ba_admin_body_classes( $classes )
{  
	$user = wp_get_current_user();
	$roles = ( array ) $user->roles;
	$user_role = $roles[0];

	if ( $user_role == 'organizer' ) {
		$classes .= ' logged_organizer ';
	}

  return $classes;
}

Ez a pár hasznos kódrészlet kiválóan alkalmas arra, hogy 2-5 féle plugin feltelepítése helyett saját kóddal, elegánsan és gyorsan oldjuk meg pontosan azt a problémát, amit akarunk, és ne szemeteljük tele a WordPress oldalunkat szuper, mindent megoldó bloatware pluginokkal.

Gravity Forms megadott mezők kivétele a visszaigazoló emailekből a merge tag használatával

Gravity Forms megadott mezők kivétele a visszaigazoló emailekből a merge tag használatával 1200 630 bacsoa

Attól a kevés WordPress bővítménytől eltekintve amit használok, a Gravity Forms az üdítő kivétel egyike. Az egyetlen hátránya, hogy fizetős, de 59 USD szerintem nem sok érte. Legalábbi most, 2023. szeptemberében ennyibe került egy licensz.

A Gravity Forms az egyik legrégebbi és szerintem legjobb űrlapkezelő. Annak idején, amikor még csak Contact Form 7 volt, ami – egyszerű űrlapokra tökéletes – amellett, hogy ingyenes sajnos elég keveset tud. Szükség volt egy komplexebb megoldásra és a Gravity Forms úttörőként megadta ezt. Gyakorlatilag már mindent meg lehet vele csinálni, többek között:

  • Komplex űrlapok feltételekkel és elágazásokkal
  • Bejegyzések küldése és létrehozása akár vendégként
  • Felhasználói regisztráció és profilkezelés
  • Recaptcha védelem
  • Szavazás (polls)
  • Bankkártyás fizetés
  • Hírlevél feliratkozás

Nem is írom le, hogy mi mindent tud, mert sokat. Ahogy Butch mondja Fabiennek a Ponyvaregényben az aranyórájáról: „Van fogalmad, hogy mit állt ki, hogy az enyém lehessen? Most nincs időm belemenni, de sokat állt ki.” 😀

Ebben a rövid, de annál hasznosabb cikkben azt mutatom meg, hogyan lehet adott mezőket kiszedni a visszaigazoló emailekből.

A WordPress-ben lévő shortcode-okhoz kicsit hasonló merge tag nevű objektumot használja, hogy az előredefiniált adatokat dinamikusan, az űrlapban megadott adatokkal helyettesítse. Vannak alapértelmezett merge tag-ek és definálhatunk sajátot, vagy kiegészíthetünk és módosítatjuk valamelyik alapértelmezettet is. Utóbbit fogom most csinálni és bemutatni.

1. Űrlapok listája nézet:

2. A Profil nevű űrlap mezői:

Minden mező, ami itt szerepel az bekerül egy globális mezőlistába, az úgynevezett {all_fields} merge_tag-be. Vannak kivételek, például a rejtett és adminisztratív mezők, de sokszor előfordul, hogy az űrlapban szereplő mezőt nem akarjuk elrejteni, mert a felhasználónak a frontenden meg akarunk valamit jeleníteni, viszont a visszaigazoló emailbe már nem szeretnénk beletenni.

3. Értesítések listája

Az Értesítések résznél lehet megadni, hogy az űrlap elküldése és egyéb események után melyik email és kinek valamint milyen tartalommal kerüljön kézbesítésre.

4. Értesítő email üzenet beállítása

Ez például a profil módosítása nevű űrlap visszaigazoló emailjének beállítása:

Így néz ki maga az email üzenet a küldés után. Látható, hogy az összes mező, amit betettünk a 2. pontban, az bekerül ide.

Mi van akkor, ha vannak olyan mezők, amelyeket nem akarunk az értesítő email üzenetbe betenni? Ha rejtett mezőtípusra tesszük, akkor a felhasználó sem fogja látni, ami nem jó. Erre való a Gravity Forms egyik saját beépített hook-ja, a gform_merge_tag_filter filter metódus.

Itt láthatók az űrlapmezők, azon belül is Születési év nevű mező beállításának részletei. Látható, hogy jobb oldalon a Megjelenés nevű panelen belül van egy Egyedi CSS osztály nevű sor. Itt lehet megadni tetszőleges számú CSS osztályt szóközzel elválasztva. Ha az egyik ezek közül a gf_exclude, akkor ezt a mezőt nem fogja az egyedi kódunk futtatása után a Gravity Forms betenni az all_field nevű merge_tag-be.

5. A merge_tag módosítása saját kóddal

add_filter( 'gform_merge_tag_filter', 'exclude_from_all_fields', 10, 4 );
function exclude_from_all_fields( $value, $merge_tag, $options, $field )
{
  // Opciók mezők tárolása tömbben
  $options_array = explode( ",", $options );

  // Alapértelmezetten {all_fields} a merge tag neve, ami az összes mezőt beteszi az emailbe
  // Itt adjuk meg, hogy ha ez {all_field:exclude}, akkor a gf_exclude (ld lentebb) nevű CSS osztállyal
  // ellátott mezőket nem teszi be, de ehhez az {all_field:exclude} nevű merge_taget kell használjuk
  $exclude = in_array( "exclude", $options_array );

  // Itt jön a lényeg, először kigyűjtjük az összes CSS osztályt
  // minden egyes CSS osztályt, (szóközzel elválasztott karakterláncban van eltárolva)
  // külön tömb elembe teszünk
  $class_array = explode( " ", $field["cssClass"] );

  // Itt jön a lényeg, hogy ha a megadott CSS osztályban találunk 'gf_exclude' nevűt,
  // akkor azt szintén kiszedjük az all_fields nevű merge_tag-ből
  $exclude_class = in_array( "gf_exclude", $class_array );

  if ( $merge_tag == "all_fields" && $exclude == true && $exclude_class == true ) {
    return false;
  } else {    
    return $value;
  }
}

6. A módosított merge_tag beillesztése

Minden kész, már csak a módosított {all_fields:exclude} nevű merge tag elhelyezése van hátra az Értesítő üzenet szövegébe:

Látható, hogy a 4. pontban megadott alapértelmezett {all_fields} nevű paraméterhez képest most már a saját {all_fields:exclude} nevű paramétert használjuk. Azért csináltam ezt, mert így meghagytuk az eredeti működést, mivel ha például az adminisztrátornak továbbra is minden mezőt el akarunk küldeni (még azokat is, amire rátettük a gf_exclude CSS osztályt), akkor használhatjuk az {all_fields} paramétert, ha pedig a nem kívánt mezőket el akarjuk távolítani az emailből, akkor pedig az új, általunk írt {all_fields:exclude} paramétert.

Nagyon sok mindent meg lehet és meg is csináltam már Gravity Forms-szal, biztos írok még, mert vannak még hasznos tippek.

Rövid és eredményes kódolást!

WordPress REST API egyedi mező hozzáadása a /posts végponthoz

WordPress REST API egyedi mező hozzáadása a /posts végponthoz 1000 563 bacsoa

Azért jó fullstack fejlesztőnek lenni, mert mindenből kapsz egy kicsit. Imádom ezt a munkát, mert változatos, minden nap új kihívással. A mai menü egy meglévő WordPress REST API bővítés. A feladat csak annyi, hogy egy már létező szabvány WordPress REST API végponthoz egy új mezőt kellett létrehoznom.

Akit a WordPress saját REST API-ja érdekel, az itt mindent megtud róla. Aki nem tudja, mi az a REST, az pedig innen induljon, vagy esetleg a Wikipedia oldalon. Röviden egy olyan egységes interfész, amelynek különböző elveknek és követelményeknek kell megfelelnie, nekünk fejlesztőknek pedig alkalmazkodnunk kell hozzá. Ez jó, mert így egy elfogadott szabványhoz kell programozni, amit mindenki (el)ismer.

A lényeg, hogy most egy Cikk / Bejegyzés (post) részletes végpontjába fogunk beszúrni plusz mezőt. Mihez is kell ez? Például alkalmazásfejlesztéshez, vagy bármilyen olyan külső alkalmazásokhoz, ami REST-alapon működik és JSON-ban várja az adatokat, majd azt dolgozza fel.

A cikk részletes WordPress REST API URL alapértelmezett URL-je a következő (nyilván a https://domain.hu az a te weboldalad tetszőlegesen behelyettesíthető URL-je), a 999 pedig a post_id (bejegyzésed WordPress-ben tárolt egyedi azonosítója) jelöli:

https://domain.hu/wp-json/wp/v2/posts/999

Ide akarunk egy plusz mezőt, mondjuk a szerző nevét. Alapból ugyanis csak a szerző (author) user_id-ja szerepel itt, de miért ne szeretnénk egyből a szerző nevét megjeleníteni? Abból is mondjuk a display_name részben beállított értéket. Nyilván ez tetszőlegesen változtatható, bővíthető. Az én megoldásom:

add_action( 'rest_api_init',  'exibio_register_custom_field' );
function exibio_register_custom_field() {

    // Register author_name field

    register_rest_field( 'post', 'author_name',
        array(
            'get_callback'          => 'get_author_name',
            'show_in_rest'          => true,
            'auth_callback'	        => 'permission_check',
        )
    );

	function get_author_name( $post,  $field_name, $request ) {
		
		$post_id = (int) $post['id'];
		$user_id = (int) $post['author']; // author user_id
		$author = get_userdata( $user_id ); // author object
		$user_name = (string) $author->display_name;
	    
	    return $user_name;

	}

}

Először inicializáljuk a rest_api_init nevű hook-ot, majd hozzáadunk egy új author_name nevű mezőt (ezen a néven fogjuk megtalálni a /v2/posts végpontban lévő JSON-ban) és végül megmondjuk, hogy az új mezőben mi szerepeljen. (get_author_name nevű függvény). A függvény a felhasználó nevével fog visszatérni (azon belül is a display_name, azaz a Nyilvánosan megjelenő névvel), ami a WordPress-ből már ismert user object-ből származik.

Rövid és eredményes kódolást!

Az egyik leghasznosabb ármódosító WooCommerce metódus, a wc_price()

Az egyik leghasznosabb ármódosító WooCommerce metódus, a wc_price() 1600 700 bacsoa

Minden héten szembejön valami, de amivel ma találkoztam, azt muszáj megosztanom, mert ugyan nekem új volt (mint a múltkori Chrome Easter Egg), de attól még lehet, hogy másnak is az lesz és az egyik leggyakrabban használt dologgal kapcsolatos: a termékek árával.

A feladat, hogy változtassunk meg egy termék árát bizonyos feltételek mentén, majd írjuk ki az eredeti és a módosított árat is. A mostani példában annyi a feladat, hogy a bejelentkezett felhasználók kapjanak 10% kedvezményt.

Ez a bejegyzés nyilván nem a pluginokról fog szólni, habár biztos meg lehetne oldani legalább két különbözővel 🙂

A következő két WooCommerce hookra van szükségünk:

  1. woocommerce_get_price
  2. woocommerce_get_price_html

Az első magát az árat, mint numerikus értéket állítja, a 2. pedig a megjelenített, tehát lerenderelt HTML kimenetet. Igazából ha csak a desszert érdekel, akkor a 2. pontot elhagyhatod, de azért olvass tovább, hátha érdekel a köret is.

Először nézzük az 1. példát, állítsuk be az árat:

add_filter('woocommerce_get_price', 'exibio_return_custom_price', 10, 2);
function exibio_return_custom_price( $price, $product ) {

    $post_id = $product->get_id(); # a termék azonosító (post_id)
    $user_id = get_current_user_id(); # a felhasználói azonosító (user_id)
    $original_price = $price; # az eredeti ár

    if ( is_user_logged_in() ) {
        $discount = $price / 100 * 10; # a kedvezmény mértéke: 10%
        $price -= $discount; # a kedvezménnyel csökkentett új ár
    }

    return $price;

}

Igazából a post_id és  a user_id nem kell ehhez a feladathoz, de odaírtam, hátha valaki csak egy konkrét termékre, vagy felhasználóra akarja megadni a kedvezményt. A fenti hook módosítja a WooCommerce terméknek admin felületen beállított árát. A megoldás ennyi, viszont nem ez volt a heti újdonság, hanem az, hogy szeretném kiírni az új árat úgy, hogy mellé/fölé kiírom az eredeti árat.

Ehhez kell a 2. hook, a woocommerce_get_price_html.

A probléma azzal van, hogy az árat numerikus (float azaz lebegőpontos) formátumban kapjuk meg, majd  formázottan szeretnénk megjeleníteni, pl. ezres elválasztóval, devizanem megjelenítéssel, stb. Tehát bejön ez:

15000

És ezt szeretnénk kiírni:

15 000 Ft

Ekkor jön az, hogy az a számot elkezdjük a jól ismert number_format függvénnyel alakítgatni, majd hozzátesszük a devizanemet, de ez elég macerás (újabb WooCommerce függvény kell hozzá, amivel a beállított devizanemet is le kell kérni a get_woocommerce_currency() metódussal). Plusz, ha esetleg kétnyelvű a webáruházunk és az egyikben HUF-nak, a másikban Ft-nak hívjuk a devizanemet, vagy esetleg eleve két különböző devizanem van, akkor még tovább kell bonyolítani. Arról nem is beszéltem, hogy néha £400 kell kiírnunk, nem pedig 400 £, ugye.

Ezt az egész problémát megoldja egy lépésben a wc_price nevű metódus. Egyetlen paramétert vár, ez pedig az ár numerikus (lebegőpontos vagy integer) formátumban, majd szépen visszaadja a WooCommerce-ben beállított formátumú devizában, ezres elválasztó karakterrel, szépen HTML formátumban.

add_filter( 'woocommerce_get_price_html', 'exibio_return_custom_price_html', 10, 2 );
function exibio_return_custom_price_html( $price, $product ) {
    
    $post_id = $product->get_id();
    $user_id = get_current_user_id();
    $original_price = (float) get_post_meta( $post_id, '_price', true ); // az eredeti ár numerikus formátumban

    if ( is_user_logged_in() ) {
        
        // az eredeti adatbázisban tárolt ár formázva, mielőtt még a 10% kedvezményt megadtuk volna
        $output = "<abbr class='original_price_label'>Eredeti ár:</abbr> <del class='original_price' aria-hidden='true'>" . wc_price($original_price) .  "</del>";
        
        $output .= "<abbr class='discount_price_label'>Akciós ár 10% kedvezménnyel:</abbr>";

        // ez pedig már a 10%-kal csökkentett / módosított ár        
        $output .= $price;
        $price = $output;
    }

    return $price;

}

A woocommerce_get_price előbb fut le, mint a woocommerce_get_price_html hook. Az eredeti ötletet innen nyúltam.

Összegezve, röviden így működik. Nézzük ezt a számot, mint eredeti ár:

15000

Hívjuk meg a wc_price metódust:

echo wc_price( 15000 );

Majd megkapjuk a generált WooCommerce formátumú HTML kimenetet:

<span class="woocommerce-Price-amount amount">
	<bdi>15 000&nbsp;<span class="woocommerce-Price-currencySymbol">Ft</span></bdi>
</span>

Örülünk Vincent. Rövid és eredményes kódolást!

Vicces mászkálós easter egg dínó játék a Chrome böngészőben

Vicces mászkálós easter egg dínó játék a Chrome böngészőben 1318 877 bacsoa

Tegnap az esti hup.hu olvasása közben az internet elment és előjött a szokásos dinoszaurusz, gondolom mindenki ismeri.

Tök véletlenül rákattintottam a dínóra és egyszer csak elindult. Nincs túlbonyolítva, a dínó magától megy a képernyő széle felé és ugrálni lehet vele, amivel ki kell kerülni az útba kerülő kaktuszokat. Van nappali és sötétmód változat is. Egy idő után már madarak is jönnek, nyilván ha a dinó nekimegy a kaktusznak, vagy a madárnak, akkor kampec és vége a játéknak. Nem tudom ki volt ez a pihentagyú programozó, aki belerakta, de innen is üdvözlöm, én nagyon élveztem 🙂

Utánanéztem és egyrészt működik asztali Chrome-on is (ott még hangja és egy sebességbeállítási lehetőség is van), ezen kívül van rá dedikált parancs is, simán be kell írni a Chrome böngészősávba ezt:

chrome://dino/

Lehet, hogy más már ismerte ezt, de újszülöttnek minden vicc új 😀

WooCommerce rendelés utáni item meta adatok mentése, hook különbségek

WooCommerce rendelés utáni item meta adatok mentése, hook különbségek 1440 960 bacsoa

Ma futottam bele egy érdekes problémába, gondoltam megosztom másokkal is, mert szerintem elég nagy a zavar a fejekben – legalábbis az internet népét és a Stackoverflow felhasználóit tekintve.

Adott egy WooCommerce (4.8, de amúgy szerintem majdnem mindegy). A feladat, hogy a WooCommerce-ben leadott rendelés után hajtsunk végre valamit.

Erre több lehetőségünk is van. Mivel a WooCommerce rendelés gyakorlatilag egy egyedi WordPress bejegyzés (shop_order), ezért van neki post_status mezője. Ezeknek a szabványos WordPress bejegyzésekhez hasonlóan többféle státusza van, sőt lehet neki egyedit is adni. Általában alapértelmezetten a wc-processing (feldolgozás alatti) státuszt kapja meg. Egy SQL lekérdezéssel ellenőrizhetjük, hogy egy adott WooCommerce webáruházunkban hány fajta státuszú rendelés létezik:

SELECT post_status
FROM `wp_posts` 
WHERE `post_type` = 'shop_order' 
GROUP BY post_status

A Woocommerce rendelés státuszokról és magáról a Order objektumról itt olvashatsz bővebben.

Azért kellett ez a rövid bevezető, mert nem mindegy, hogy a rendelések mely státuszánál, mi fusson le. A Woocommerce erre többféle beépített hook-ot kínál. Mi az a hook? Ez gyakorlatilag egy callback. Mi az a callback? Na igen, ez az amikor 15 dolgot el kell magyarázni, hogy a végén egy szót megérts 🙂 A Callback-ről magyarul itt olvashatsz bővebben. A WordPress hook-okról pedig itt.

A rendelés leadása utáni tranzakciókezelésre a Woocommerce többféle hook megoldást is nyújt, például ezeket:

  1. woocommerce_checkout_order_processed
  2. woocommerce_payment_complete
  3. woocommerce_thankyou

A teljes listát itt találod.

Több, eltérő leírás van erről a neten, sőt a Woocommerce verziók között is vannak eltérések. Arra is kell vigyázni és ezt sokan elrontják, hogy minden hook-nak eltérő mennyiségű paramétere van. Ha többet adsz át az nem gond, de ha kevesebbet, akkor le sem fut. Sajnos vannak olyan hook-ok, amik nem dobnak hibát, csak egyszerűen nem működnek. Az alábbi példában például a 10, 3 a végén azt jelenti, hogy 3 paramétert vár és 10 prioritással fusson le. Mivel többet is egymásba ágyazhatsz, és az egyik felülírhatja a másikat, hogy ne legyen olyan egyszerű az élet. Főleg akkor jó ez, ha egy másik plugin már használja valami unintelligens 99999 prioritással és te meg nem jössz rá, hogy a tiéd miért nem működik… 😀

Amibe ma belefutottam, az egy elég egyszerűnek tűnő probléma. Én általában a woocommerce_checkout_order_processed hook-ot használom. Ez három paramétert vár. Az 1. a Woocommerce rendelés azonosító (wc_order_id), a 2. az elküldött személyes adatok (posted_data), a 3. pedig maga a rendelés objektum (order class):


add_action( 'woocommerce_checkout_order_processed', 'exibio_woocommerce_order_processed', 10, 3 );
function exibio_woocommerce_order_processed( $wc_order_id, $posted_data, $order ) {
    // ez fut le a rendelés leadása után
}

Ez a hook akkor fut le, ha a rendelés a processing státuszára már átváltott (tehát a wc-processed után). Sajnos vannak olyan bővítmények, amelyek rosszul használják a rendeléshez tartozó és elmentett item meta data, azaz a rendelés tétel meta adatok (ezek általában a rendeléshez tartozó egyedi mezők, paraméterek, akár a felhasználók által átadott változók, stb.) elmentését és nem a woocommerce_checkout_order_processed hook-ot használják, hanem a woocommerce_thankyou hook-ot. Nem ugyanarra való, de sajnos sokan összekeverik vagy helytelenül használják.

 

Emiatt hiába vártam egy plugin által összegyűjtött mezőit a rendelés meta adatait között, az csak a rendelés leadása utáni pillanatban vált elérhetővé. Ez azért volt, mert a plugin nem a processed utáni pillanatban mentette el a meta adatokat, hanem a thank you endpoint utáni pillanatban. Ez azt okozta, hogy a hook utáni iterálásnál on-the-fly hiába kérdeztem le az order_itemmeta táblát, nyoma sem volt a plugin által elmentett adatoknak.

Először a woocommerce_checkout_order_processed hook után egy sima SQL lekérdezést használtam (az item_id egyébként az order objektumon belüli változó). Az $items objektum iterálása SQL lekérdezéssel:

global $wpdb;
$items = $order->get_items();
foreach ($items as $item_id => $item) {
$sql = "
	SELECT meta_value
	FROM wp_woocommerce_order_itemmeta
	WHERE `order_item_id` = {$item_id}
	AND (meta_key = '_sumo_pp_payment_id')
";

$result = $wpdb->get_results($sql, ARRAY_A);
if ( !empty($result) ) {
	$sumo_pp_payment_obj = $result[0];
	$sumo_pp_payment_id = (int) $sumo_pp_payment_obj['meta_value'];
}

}

Ugyanez, dedikált Woocommerce függvénnyel lényegesen egyszerűbb, de egyik sem adott vissza találatot.

$items = $order->get_items();
foreach ($items as $item_id => $item) {
	$sumo_pp_payment_id = (int) wc_get_order_item_meta( $item_id, '_sumo_pp_payment_id', true );
}

Sehol semmi. Aztán amikor már lezajlott a rendelésleadás (és lefutott a woocommerce_thankyou hook filtere is, ami kb 1 mp múlva már megtörtént), akkor már ott volt a _sumo_pp_payment_id nevű rekord tartalma. Tanulság: ha legközelebb belefutsz egy ilyenbe és nem találod az adott meta mezőt, próbáld ki mindhárom hook-ot, hátha az adott megoldásban az lesz a nyerő.

Ajánlott irodalom:

  1. Egy WooCommerce hiba, amikor a woocommerce_checkout_order_processed hook előbb lefut, mint kéne: https://github.com/woocommerce/woocommerce/issues/28113
  2. A woocommerce-checkout-order-processed miért nem működik? https://stackoverflow.com/questions/45997729/any-idea-why-woocommerce-checkout-order-processed-not-firing-when-user-is-not-lo
  3. A woocommerce_thankyou hook használata https://stackoverflow.com/questions/43301940/woocommerce-thankyou-hook-not-working
  4. A woocommerce_payment_complete értelme, vagyis amikor az a fontos, hogy mikor van kifizetve egy rendelés: https://stackoverflow.com/questions/46686075/woocommerce-checkout-order-processed-hook-executing-function-twice

Mi kell ahhoz, hogy (WordPress) webfejlesztő legyél?

Mi kell ahhoz, hogy (WordPress) webfejlesztő legyél? 2000 1331 bacsoa

Azt látom, hogy évek óta hiány van informatikusokból. Magyarországon emiatt már évek óta elkezdődtek több cégnél a programozó, rendszergazda és informatikus képzések. Most leírom, hogy szerintem mi szükséges ahhoz, hogy WordPress weboldalakat készíts egyedi webdesign vagy sablon alapján. Fontos a sorrend, ne a 3-as ponttal kezd. Ha nem ismered az 1. pontot, akkor a 2. pontot nem is fogod érteni.

1. HTML

Először tanuld meg az alapokat. A HTML leíró nyelvként egységbe foglalja azt, amitől egy böngészőben megjelenő tartalom közel ugyanúgy néz ki minden platformon (pl. Linux, Windows, MacOS, Android, iOS) és minden böngészőben (pl. Firefox, Chrome, Edge). Mert mi is történik amikor beírsz egy webcímet egy böngészőbe? Például ezt: https://www.w3schools.com/html/

A böngésző lekéri a beírt címhez tartozó oldalt, tartalmat, fájlt, bármit. Ezt hívjuk kérésnek, azaz request-nek. Ezt a (web)szerver (ami a „másik oldalon” van), ami ezt a kérést fogadja, feldolgozza, majd válaszol nekünk. Ezt hívják válasznak, azaz response-nak. Azért fontos mindezt angolul is leírnom, mert magyarul nem fogsz túl sok hasznos dolgot találni, így egy nem is annyira zárójeles nulladik helyre az angol nyelv alapfokú ismeretét is beírnám. A feldolgozás után megkapjuk a feldolgozott választ, ami ez esetben egy HTML kód. Hiszen a w3schools.com fejlesztője már elkészítette ehhez a webcímhez tartozó választ, azaz egy weboldalt, amit nyilván HTML-lé alakított. Azért HTML-lé, mert ez a böngészők által használt szabvány. Vannak más szabványok is, például JSON, XML, amit nem böngészők számára írtak, hanem más alkalmazások, igények kiszolgálására.

Tehát minden internetes „szörfölés”, azaz böngészés kérések és válaszok folyamatos ismétlődéséből áll. A böngésző először is megkeresi a webcímhez tartozó domain nevet, ami ez esetben a w3schools.com. Ezután megkeresi a domain névhez tartozó domain név szervert, ami egy  IP cím. Az IP cím egy host, számítógép, bármi egyedi azonosítója. Maradjunk a fenti esetnél. A domain nevekhez tartozó szerverek IP címei nyilvánosak, különben hogyan tudná lekérni a böngésző? 🙂 Ezeket bárki ellenőrizheti, akár te is. A legegyszerűbb módszer egy terminál, ha MacOS-ed vagy Linuxod van, akkor beírod a két parancs valamelyikét:

Nekünk ebből az A rekord (más néven címrekord) kell, vagyis az a szerver, aki kiszolgálja a w3schools.com domain nevet. Ha érdekel a többi DNS rekordtípus is, erre nézelődj. Ha lusta vagy, ugyanezt megteheted weben keresztül is egy whois szolgáltatóval is. Jelen esetben a https://who.is/dns/w3schools.com próbáltam ki, ezzel az eredménnyel. A DNS Records rész érdekel minket, ott vannak a Domain Name Server rekordok.

Tehát amikor beírsz a címsorba egy webcímet, akkor a böngésző megkeresi az A rekordhoz (66.29.212.110) tartozó szervert és elindít egy kérést. A szerver ezt a kérést https://www.w3schools.com/html/ feldolgozza és visszakapsz egy eredményt, jelen esetben ezt:

Amit látsz a böngésződben egy generált HTML kód. Nézzük hogyan néz ez ki. Ha Chrome-ot használsz, nyomj egy jobb gombot bárhol az oldalon, ami nem link vagy kép (azaz egy üres területen) és válaszd a forráskód megtekintése (nálam ez View Page source) lehetőséget.

Kiválaszthatod menüből is. Ehhez válaszd a View (magyar böngészőben Nézet) / Developer (magyar böngészőben Fejlesztői eszközök, vagy hasonló), View Source (magyar böngészőben Forrás megtekintése) menüpontot.

Így vagy úgy, de végül ilyesmit fogsz látni:

Ahhoz, hogy weboldalakat készíts, egy ilyen HTML kódot kell írj azért, hogy a végén a látogatók egy ilyet lássanak:

Ezért elengedhetetlenül fontos, hogy ha weboldalakat akarsz készíteni, akkor tisztában legyél mi az a HTML. Enélkül ugyanis csak a sötétben fogsz tapogatózni és a WordPress esetében előre (más webfejlesztők által) elkészített sablonokból (template) és bővítményekből (plugin) fogsz weboldalakat csinálni. Ami addig lesz jó, amíg az ügyfél megelégedik azzal, amit a te általad használt sablon megenged. Vagyis ha a sablonban bal oldalon van a logó, de az ügyfél jobb oldalra akarja és te nem értesz a HTML-hez, a sablon pedig nem támogatja ezt, akkor nem fogod tudni megcsinálni, mert azt sem tudod hogyan épül fel egy weboldal. A W3schools.com-ot azért is hoztam fel példának, mert nagyon egyszerűen elmagyarázza és megtanít az alapokra. Szerintem maximum 2 nap alatt elsajátítható, mert tényleg nem bonyolult. Ha már mennek az alapok, gyakorolhatsz, vannak tök jó ingyenes oldalak, ahol konkrét feladatokat oldhatsz meg, a teljessége igénye nélkül néhány példa:

2. CSS

A CSS (Cascade Style Sheet rövidítése) a HTML kód formázására kialakított (közel egységes) leíró nyelv. A HTML a CSS-sel együtt fejlődött, szinte párhuzamosan egymással. Ha érdekel az egész sztori, erre keresgélj. A CSS használatával meg tudod formázni a HTML elemeket. Például hogy egy betű milyen színű, méretű legyen. Margókat (margin) és eltartást (padding) és még kb ezer dolgot meg tudsz adni. Alapvetően a HTML és CSS ismeretével már tudsz működő weboldalt csinálni, akár mobilnézetben is. Nézzük az eredeti példánál maradva, hogy mit is jelent ez a gyakorlatban.

Bemutatom az egyik leghasznosabb eszközt, amit egy webfejlesztő kívánhat magának, a Chrome Inspectorját (Firefox-ban, Edge-ben és Safariban is van ilyen). Régen, amikor még nem volt Chrome, leginkább Firefox-ban nézegettük a weboldalakat, volt hozzá egy Firebug nevű tool, ami ennek az őse volt. A https://www.w3schools.com/html/ oldalhoz nyissuk ki Chrome-ban az ún. Fejlesztői eszközöket. MacOS gyorsbillentyű: CMD + OPTION + i, Linux / Windows gyorsbillentyű: CTRL + ALT + i. Kinyithatod menüből is (Developer Tools vagy Fejlesztői eszközök a neve):

Ezt fogod látni:

Ezzel az eszközzel párhuzamosan két nézetet fogsz látni, kicsit hasonlít egy fordítógéphez. Felül látszik a generált HTML kód, alul pedig a forráskód. Ezt a Developer Tools-t amúgy átmozgathatod jobbra és balra is. Jó cucc annyi biztos. Nemcsak a HTML kód látszik, de még egy csomó más is. Nem akarok annyira belemenni, mert ez a cikk nem erről szól, de többek között a hibákat (ha vannak) is megtekinthetjük (mert van saját konzol is benne), valamint a betöltött függvényeket, cookie-kat és még sok minden mást is. Ja és van benne egy komplett mobileszköz emulátor is, amivel meg tudjuk tekinteni, hogyan néz ki a weboldal egy iPhone-on, vagy Samsung táblagépen. Ha föléviszed az egeret a lenti sávban lévő elemekre, akkor megmutatja, hogy amire az egeret odavitted, az valójában hogyan néz ki a weboldalon. Jól látszik, hogy ami alul világoskék (én piros kerettel külön kiemeltem), azt felül is világoskékkel beszínezi. Amit alul kijelölsz, azt felül párhuzamosan megmutatja.

Ennél jobb módszer szerintem nincs a HTML megértésére, mert egyből látod, hogy mi micsoda és mihez tartozik. Ami még érdekes, az a jobb oldalon látható Styles fül. Itt látható az összes CSS definíció fájlonként és szülőnként.

A CSS a HTML elemeket formázza meg, igazítja őket egymás mellé, fölé, színezi őket, állítgatja a margókat az arányokat. A példa URL-en például fent van a főmenü, bal oldalon van egy világosszürke oldalsáv, középen van a tartalom, jobb oldalon pedig szintén egy oldalsáv. Ezeknek a fő konténereknek a helyét előre megtervezte valaki (pl. egy webdesigner, vagy UI designer), majd a fejlesztő az elfogadott látványterv alapján összeállította HTML elemekből. Hogyan csinálta? Megtanulta, hogy milyen elemtípusok vannak HTML-ben (pl. div, span, p, section, header, footer, stb.) majd egymás mellé tette őket és CSS-sel megformázta, hogy pont olyan legyen, ahogy most látszik egy böngészőben.

A CSS elsajátítása nem annyira egyszerű, mint a HTML nyelvé. Sokkal komplexebb és hála a különböző böngészőknek sokszor előfordul, hogy egy elfogadott szabály egyik böngészőben működik, másikban pedig nem, vagy nem pont ugyanúgy. Ez többnyire a böngészők belső HTML „fordítójának” köszönhető. Akit érdekelnek a különböző böngészőmotorok, renderer engine-ek, az erre nézelődjön. Most olvasok egy könyvet (Peter Thiel: Nulláról egyre), amiben az első fejezetben meg is említik az első böngészőt, a Netscape Navigatort. Emlékszem az első munkahelyemen 1997-ban, a SZÜV Rt-nél már volt internethozzáférésem és én is a Netscape Navigator-t használtam. Nagyon hasznos oldal még a Can I Use? nevű csoda, ahol szinte minden CSS definíciót meg tudunk nézni, hogy melyik böngésző támogatja és melyik verziótól. Régen, amikor még volt Internet Explorer rengeteget szenvedtünk azzal, hogy ami Firefox, Safari, Chrome hármasban (tehát a normálisan működő böngészőkben) működött, az működjön Internet Explorer alatt is. A Microsoft szégyene ez a szeméthalom, amit szerencsére kivezettek a francba és lecserélték egy Chromium alapú böngészőre, az Edge-re. Ez gyakorlatilag egy Chrome, bátran használható, végre szabványosan működik. Akit érdekelnek a különböző böngészőmotorok (Webkit, Blink, Gecko, stb.), az látogasson ide.

Ezen az ábrán jól látszik hogyan működik egy böngésző. A Felhasználói felületet (piros szín) látja és kezeli a mezei felhasználó, aki csak böngészi a lapot és olvasgat, nyomogatja a felület gombjait, beírja a webcímeket a menüsávba, stb. A böngészőmotor (kék szín) a böngésző belső magja. Ez tartja a kapcsolatot a „túlvilággal”, azaz a render engine-nel, kezeli a kéréseket, elosztja az erőforrásokat, fogadja az adatokat a felhasználói felületről, valamint a fordítórészről. A Renderelő motor a legfontosabb rész. Ő rendereli, azaz feldolgozza és kirajzolja, megjeleníti a értelmezett HTML, CSS, egyéb adatokat. A Renderelőmotortól (lila színű doboz) függ, hogy végül mit látunk a böngészőben. A hálózatkezelő (zöld színű doboz) kezeli a request-response részt, a Javascript értelmező végrehajtja a Javascript programrészleteket, ő is egyfajta compiler, azaz fordító. A UI (User Interface, azaz felhasználói felület) backend (azaz háttérfeladatokat végző, de elég nehéz lefordítani ezt magyarra) pedig az általad használt operációs rendszerben definált ablakkezelőtől örökölt kinézet alapján rajzolja meg az űrlapelemeket, gombokat, magát a böngészőablakot és így tovább. Ez a rész nem a böngésző sajátja, hanem az operációs rendszertől kapja. Ezért néz ki máshogyan egy görgetősáv (scrollbar), vagy egy űrlapmező, lenyílólista és maga a böngésző is máshogyan Windows 10, MacOS, Ubuntu vagy bármilyen más operációs rendszer alatt. A tárolt adatok pedig (narancs színű doboz) egy perzisztens, azaz tartós adatréteg. Itt tárolódik minden adat, pl. a cookie-k. Az ábra eredetijét innen nyúltam.

3. Javascript

A Javascript egy alapvetően objektum-orientált programnyelv, amivel a webfejlesztés során biztosan találkozni fogsz. Nem azt mondom, hogy elengedhetetlen a weboldal fejlesztéshez, de nehéz kikerülni. Főleg akkor, ha kliens oldalon (a böngészőben) akarsz adatokkal dolgozni. Az első böngészőhöz, a Netscape-hez fejlesztették ki és alapvetően a Java programnyelvhez hasonlít (az akkori Java-hoz). Az utóbbi 20 évben rengeteget fejlődött és több, önálló programnyelv „nőtt ki belőle”, azaz használja ugyanazt az elgondolást, szintaktist. Ilyen például a TypeScript, a React, az Angular (ami meg a TypeScript alapjaiból fejlődött ki) vagy a Node.JS. Aztán vannak olyan ún keretrendszerek, vagy más néven framework-ök és library-k (könyvtárak) is, amelyek a Javascriptet „egyszerűsítik” le, az egyik ilyen, mai napig is népszerű (és a WordPress által is használt) jQuery.

Ha már megismertük a HTML nyelv elemeit és tudjuk, hogy mi az a DOM (Document Object Model), akkor a Javascript segítségével dinamikusan, a böngészőben közvetlenül tudjuk manipulálni ezeket az ún. DOM elemeket. Azért jó ez, mert sokszor van olyan, hogy figyelnünk kell a felhasználó adott mozdulataira. Pl. odaviszi az egeret a böngésző egy adott részére és ha ez megtörténik, mi feldobunk neki egy ablakot egy szöveggel, hogy iratkozz fel a hírlevélre, vagy hasonló. Ezt Javascripttel tudjuk megoldani. Vagy elkezd görgetni és ha elér egy bizonyos pontot, akkor a főmenüt összekicsinyítjük és odaragasztjuk az oldal tetejére (ezt hívjuk pl. sticky menünek, biztos láttál már ilyet), majd ha visszagörget, újra visszanagyítjuk. Vagy rákattint egy linkre és odagörgetjük az oldal egy másik részére. Rengeteg ilyen van és Javascript nélkül ezt nem lehet megoldani. A WordPress a jQuery-t használja erre, ami leegyszerűsíti a Javascripteben használt leggyakrabban használt parancsokat és kevesebb gépeléssel tudjuk ugyanezt megoldani.

Mutatok rá egy példát. Azt szeretnénk megcsinálni, hogy minden, adott tulajdonsággal rendelkező gombra (pl. minden Kosárba teszem feliratú) kattintva jelenítsünk meg egy üzenetet a böngészőben.

Normál Javascriptben, vagy viccesen használva Vanilla JS-ben (ez a Stack Overflow cikk jól elmagyarázza mit is jelent a köznyelvben használatos Vanilla JS) így néz ki ez a kód:

const kosarbaGombok = document.querySelectorAll('.addtocart')

for (const kosarbaGomb of kosarbaGombok) {

	kosarbaGomb.addEventListener('click', function(event) {

		event.preventDefault()
		alert(`Ön megnyomta a kosárba gombot!`)

	})

}

Ez a kódrészlet annyit csinál, hogy minden olyan elemre kattintva (gomb, hivatkozás, bármi), aminek az osztályában (class) szerepel az „addtocart” feldob a böngészőben egy figyelmeztető ablakot azzal a szöveggel, hogy Ön megnyomta a kosárba gombot! Ugyanez a kód jQuery-ben így néz ki:

$(`.addtocart`).click(function(event) {
	
	event.preventDefault()
	alert(`Ön megnyomta a kosárba gombot!`)

})

Látszik, hogy mennyivel könnyebb ugye? Nem véletlenül az a szlogenje, hogy „Write less, do more”. Arról nem is beszélve, hogy a jQuery áthidalja a Javascript verziók közötti verzióproblémákat, mert a Javascript is fejlődött a évek során, de a böngészők nem mindig, vagy nem egyformán követték ezt a fejlődést, ezért elképzelhető, hogy az előbb leírt kódrészlet, amit már ES6 szabvány szerint írtam, egy 2015 előtti böngészőben nem fog működni. A jQuery viszont figyel erre és szinte majdnem minden verziója (nyilván a jQuery-nek is vannak verziószámai és fejlődési ciklusa) majdnem minden verziójú és típusú böngészővel működik.

4. PHP

A programnyelv, amit már sokan, sokszor leírtak mégis él és virul, sőt az utóbbi években a reneszánszát éli. Fontos tudni és nem összekeverni, hogy mire való. Már a nevében is benne van, hogy mire is találták ki a PHP nyelvet. Eredetileg Personal Homepage Tools volt a rövidítése, ami nagyjából Otthoni személyes weboldal készítő eszköznek fordítható. Később aztán, mikor elkezdett fejlődni és önálló programnyelvvé vált, átnevezték Hypertext Preprocessor-ra, azaz Hypertext előfeldolgozóra. Ennél azért jóval többet tud a PHP, mint amire a neve hivatott (szerintem ráférne egy új név, de gondolom nem találtak ki erre a hárombetűs rövidítésre megfelelő, új jelentést), egy objektum-orientált programnyelv (a 4.0 óta részlegesen, az 5-ös verzió óta teljesen), amivel gyakorlatlag bármilyen rendszer leképezhető, megírható. Ha WordPress-ben szeretnél weboldalakat készíteni sokszor elég, ha a PHP-nak csak a preprocessor, azaz a feldolgozó részét használod ki, azaz a megkapott adatokat feldolgozod és kiíratod vele. Mit jelent ez a gyakorlatban, azaz a WordPress-ben?

A WordPress egy nyílt forráskódú PHP-ban írt CMS (Content Management System) keretrendszer. Mivel a WordPress-t eleve PHP nyelven írták, így minden függvényhez, funkcióhoz, osztályhoz PHP-ban tudunk hozzányúlni és azokat bővíteni. Ezért ha nem ismerjük a PHP alapjait, nem fogunk tudni megcsinálni semmilyen egyedi feldolgozást vagy lekérdezést. A Preprocessor nem egészen jó megfogalmazás, mert sokszor nem csak előfeldolgozást végzünk vele, hanem utófeldolgozást is. Tehát van egy kérés (request), azt a PHP az SQL adatbázis felé egy lekérdezéssé alakítja (SQL nyelven), majd visszakapja az SQL adatbázistól a kért adatokra a választ (response) és mivel még mindig a PHP fut, ezért az utófeldolgozást is ő végzi, tehét az értelmezett kérést, feldolgozva kiíratja a felhasználónak a képernyőre.

A WordPressben vannak egy csomó osztály és eljárás (függvény) is. Ehhez nyilván meg kell érteni, hogy mi a különbség a procedurális és objektum-orientált szemléletű programozás között, de ebbe most nem megyek bele. A WordPressben rengeteg beépített, (nyilván PHP nyelven megírt) saját függvény és osztály van, melyek azért kellenek, hogy ne nekünk kelljen SQL lekérdezéseket írni, vagy dátumot átalakítani magyar formátummá, esetleg ékezetteleníteni egy karakterláncot, stb. Ha a PHP szintaktikájával tisztában vagyunk, onnan már könnyű lesz megérteni hogyan működik egy sablon (template), vagy akár egy bővítmény (plugin), mivel ezek is PHP nyelven vannak.

A PHP másik nagy előnye, hogy bármilyen HTML kódot képes kiírni és előtte akár feldolgozva megjeleníteni. Ha az 1. HTML és a 2. CSS ponttal tisztában vagy, akkor a PHP segítségével nem csak statikus HTML oldalakat tudsz majd írni, hanem dinamikusan generált, komplexebb oldalakat. Ugyanis a PHP-val megoldható az is, hogy egy weboldalt, (aminek alapvetően három része van: 1. Fejléc 2. Tartalom 3. Lábléc) teljesen dinamikusan összelegózz és ki-, vagy akár felcserélj és ezt kiírasd, generálj belőle egy HTML kódot, amit a böngészők megjelenítenek.

A másik nagyon fontos különbség a Javascript és a PHP programnyelv között, hogy a PHP szerveroldalon fut, a Javascript pedig a kliensoldalon. Tehát a PHP a webszervereden fut és értelmezi a parancsokat, amit te a .php kiterjesztésű fájlokban megírsz, azt a látogató sosem fogja ebben a formában látni, ő már csak a kimenetet, azaz a PHP által legenerált HTML kódot (ha erre használjuk) látja. Nézzük mit jelent ez a gyakorlatban. Adott a következő PHP kódrészlet:

<div class="tartalom">

<?php if ( is_super_admin() ) { ?>
	
	<p>Ezt a szöveget csak egy bejelentkezett WordPress adminisztrátor látja</p>
	
<?php } else { ?>
	
	<p>Ezt a szöveget minden látogató látja.</p>
	
<?php } ?>

</div>

Ez annyit csinál, hogy PHP-ban egy feltételbe ágyazza a WordPress saját is_super_admin nevű függvényét. Ez megvizsgálja, hogy az adott felhasználó adminisztrátor vagy sem. Egyúttal azt is leellenőrzi, hogy az adott látogató be van jelentkezve vagy sem. Ez egy elég gyakori kérés ügyfelektől, hogy „Attila lehet olyat, hogy ezt a részt a weboldalon csak bejelentkezett felhasználók lássák?” Hát, hogy a viharba’ ne lehetne? Mivel ismerem a PHP szintaktikáját (ettől még nem tudok feltételenül programozni) és ismerem a WordPress is_super_admin() függvényét, máris megoldottam, hogy egy feltételhez kötve két elágazást írtam.

Tehát ha nem ismered a PHP-t, akkor erre az lesz a következő lépésed, hogy elkezdesz vadul bővítményeket (pluginokat) keresni, az ügyfél által kért funkcióra. Erre nagyjából 50% esélyed, hogy találsz megoldást. Azért csak 50%, mert a legtöbb kérésre már van bővítmény. Az viszont majdnem biztos, hogy nem pontosan úgy fog működni, ahogy az ügyfél kéri. Erre majd az jön, hogy meggyőzöd az ügyfelet, hogy legyen inkább úgy, ahogy te gondolod (illetve ahogy a plugint megírták, mert te ugye nem értesz hozzá). Ha nem megy bele az ügyfél, akkor keresel egy újabb bővítményt. Aztán azon kapod magad, hogy 3 plugint kellett föltegyél ahelyett, hogy utánanéztél volna a PHP-nak és a WordPress codexen és 1 sor PHP kóddal megoldottad volna. Vagy használnád a Google-t. Lustaság fél egészség? Nem hiszem, szerintem inkább igénytelenség. Azt a mérhetetlen mennyiségű időt, amit pluginok és template-k keresgélésével töltesz, eltölthetted volna hasznosabban is, és megtanulhattál volna 5 gyakran használt WordPress függvényt. Vagy például azt, hogyan írjunk ciklust PHP-ban. Vagy mi az a ciklus? Vagy mi az a feltétel.

PHP-t tanulni amúgy könnyű, erre is van annyi oldal, mint égen a csillag. Megint bemásolom ide a szerintem két legjobbat:

5. SQL

Nagyjából 3 évig csináltam WordPress sablonokat anélkül, hogy egyetlen sornyi SQL kódot leírtam volna. Miért? Mert a WordPress megcsinálta helyettem. Van rá egy csomó függvény, ami kiszolgálja ezt az igényt. Megadott paraméterek szerint adatokat kér le az adatbázisból, majd visszaadja pont úgy, ahogy kell. Minek akkor ide SQL? A WordPress minden adatot adatbázisban tárol, méghozzá MySQL alapú adatbázisban. Előbb-utóbb eljutsz majd oda, hogy szeretnél saját lekérdezéseket írni, mert az ügyfél olyat kér tőled, hogy légyszi küldd át az összes olyan felhasználót, akinek a keresztneve Attila. Ezt megoldhatod a WordPress saját, get_users függvényével, vagy írhatsz rá egy SQL lekérdezést. Mondanom sem kell, hogy melyik a gyorsabb. Nézzük az előbbi példa két különböző megoldását, szerintem jól szemlélteti.

PHP-ban megírva a WordPress saját get_users függvényével:

$args = array(
    'meta_query' => array(
    'relation' => 'AND',
	    array(
	        'key'     => 'last_name',
	        'value'   => 'Attila',
	        'compare' => '='
	    )
	)
);
$users = get_users($args);

SQL-ben megírva ugyanez a WordPress adatbázisból közvetlenül kiolvasva:

SELECT *
FROM `wp_users` AS wpu
	INNER JOIN `wp_usermeta` AS wpum ON (wpum.user_id = wpu.ID)
WHERE wpum.meta_key = 'last_name' AND wpum.meta_value = 'Attila' 
GROUP BY wpu.ID

A példa nem annyira triviális, mert van benne pl. egy kapcsolt táblás lekérdezés, de jól szemlélteti, hogy mennyivel egyszerűbb közvetlenül azon a nyelven kommunikálni, amiben az adatokat a WordPress amúgy letárolta. SQL nyelven. A SQL az egyik legjobb dolog, ami valaha a programozási világban történt. Kicsi eszköztár, iszonyatosan gyors és még több szálon is működik. Van ennél jobb? Szerintem nincs. A MySQL olyan érzést ad, mintha Windows vagy MacOS után áttérnél egy Linux alapú operációs rendszerre (Ubuntu, Debian, LinuxMint, tökmindegy) és megtanulnál rendszert kezelni, felügyelni és működtetni. A teljes szabadság.

Kicsit hosszúra nyúlt ez a leírás, de úgy érzem ez az 5 pont szükséges ahhoz, hogy szinte mindent meg tudj csinálni WordPressben. Ha pisztolyt szorítanának a fejemhez és ki kellene belőle választanom a tényleg csak legfontosabbakat, akkor ez a három maradna:

  1. HTML
  2. CSS
  3. PHP

Viszont ebből már nem engedek, akkor inkább a golyó 🙂 Ha ezt a hármat ismered, akkor már jó úton haladsz ahhoz, hogy ügyes webfejlesztő legyél.

Mindig tanulj, mert a tudás hatalom és a legjobb befektetés!

Ubuntu 18.04 szerver frissítés 20.04 Focal Fossa verzióra

Ubuntu 18.04 szerver frissítés 20.04 Focal Fossa verzióra 1280 720 bacsoa

Az elmúlt két napom a a telepítésekről és frissítésekről szólt. Tegnap fel kellett tennem az új Macbook Air M1-emre egy Apache, PHP, MySQL kombót, ma pedig a régóta esedékes Ubuntu 20.04 frissítést csináltam meg a szerveremen. Ez a post utóbbiról szól, de talán leírom majd az M1 Silicon LAMP telepítést is, abban kicsit nagyobb kihívás volt.

A szerverem a Digital Ocean-nél van másfél éve, akkor Ubuntu 18.04-gyel jött, de már 2021 van, a Focal Fossa pedig tavaly jött ki és már itt volt az ideje a frissítésnek. Van ugyan egy részletes angol nyelvű leírás a Digital Ocean oldalán, de ha kizárólag azt követtem volna, akkor most bajban lennék, mert nekem például történt egy kis probléma telepítés során (lásd később).

1. Előkészületek

Három dolgot mentettem le:

  • webszerveren lévő fájlok
  • MySQL adatbázisok
  • /etc könyvtár

A MySQL adatbázisok dumpolásával kezdtem, erre egy 3 soros batch file (hívjuk mondjuk „backup-sql.sh”-nak) alkalmas a következő tartalomal („nano backup-sql.sh” parancs kiadásával szerkeszthetjük a fájlt, ami egyből létre is hozza. Használhatjuk a Midnight Commandert is, de előtte hozzuk létre „touch backup-sql.sh” paranccsal):

#!/bin/sh
for DB in $(mysql -e 'show databases' -s --skip-column-names); do
     mysqldump $DB > "$DB.sql";
done

Kell neki futtatási jog is, mert a Linuxban az új fájlok alapból nem kapnak ilyet:

chmod 500 backup-sql.sh

Futtatás után az aktuális könyvtárban szépen sorban minden adatbázisból készül egy SQL fájl. Azzal most nem akarok foglalkozni, hogy mi kell ahhoz, hogy a bejelentkezett usernél ne kérjen a MariaDB jelszót, de akit érdekel, itt erről egy cikk. Mivel most már van futtatási jogunk a fájlra, akkor egyszerűen lefuttatjuk:

./backup-sql.sh

Ha ez is kész, jöhet a /etc könyvtár. Ez azért hasznos, mert ha az Ubuntu 20.04 frissítés után a telepítő felülír valamit és utána nem fog működni (pl. postfix/levélküldés, SSH, openssl, bármi), akkor vissza tudjuk tenni a régi konfig fájlból, vagy legalább meg tudjuk nézni, hogy ami előtte működött, az most miért nem, tehát össze tudjuk hasonlítani a kettőt. Ezt a parancsot is a /var/www/html adjuk ki a terminálban (vagy onnan, ahonnan majd rsync-kelni fogjuk a fájlokat):

root@xact:/var/www/html $ tar -zcvf ./backup-etc.tar.gz /etc

Jöhet az rsync, a parancs MacOS alatt kb így néz ki (user@1.2.3.4 a szerverünk címe, a /var/www/html pedig az a könyvtár, ahol a lementendő fájlaink vannak, nyilván az előző backup-sql.sh nevű parancsot is ide érdemes tenni, és innen futtatni, hogy az SQL dumpok is ide kerüljenek):

rsync -avr --progress -L user@1.2.3.4:/var/www/html/ /Users/macusername/Documents/backup-directory

A -L kapcsoló azt jelenti, hogy az rsync követi a symlinkeket és azokat is át fogja másolni. Nekem az első partíción nem sok hely van, ezért a /mnt alatt van a weboldalak nagyrésze (ide mountoltam még egy volume-t). Az Apache konfig egységessége miatt át van symlinkelve a /var/www/ alá. Ha a -L kapcsolót kihagyjuk, akkor csak a fizikai fájlokat fogja átmásolni, tehát csak azokat, amik a /var/www/html alatt vannak.

Ez ellesz egy darabig, attól függően, hogy a webszerveren hány virtuálhost (weboldal) van és mekkora mennyiségű fájllal.

Ezzel megvan a mentés. Mielőtt elindítanánk a frissítést érdemes egy terminálon be SSH-zni a szerverre egy SUDO jogú userrel és átváltani root-ra, ha esetleg beüt a krach az installálás során, legyen egy plusz lábunk. Ha nem tesszük meg és lerohad az install, lehet, hogy nem fogunk tudni SUDO-zni, azaz elveszítjuk az irányítást a rendszer fölött. Tehát mielőtt do-release, előtte be SSH-zunk a szerverre egy Sudo joggal rendelkező userrel (ez fontos!):

ssh user@1.2.3.4

Majd átváltunk root userre:

sudo su

Én az installt a Digital Ocean beépített Java-s konzoljából indítottam el böngésző alól, de SSH-ból is csinálhatjuk (de akkor is indítsunk egy külön SSH sessiont az előbb leírt módon).

2. Installálás

Miután beléptem a konzolon először érdemes leállítani a lényeges futó szolgáltatásokat, ne egy élő rendszeren indítsunk operációs rendszer frissítést. Én az Apache-ot és a MySQL-t állítottam le, de ha nálad NGINX van PHP-FPM-mel, vagy bármi egyéb akkor érdemes lelőni azokat is:

sudo systemctl stop apache2

Majd a MySQL-t is:

sudo systemctl stop mysql

Még egy ellenőrzés, hogy biztos leállt:

sudo systemctl status apache2
sudo systemctl status mysql

Ha azt látjuk mindkettőnél, hogy Active: inactive, akkor kezdhetjük a frissítést ezzel a paranccsal:

sudo do-release-upgrade

Ezután jön a következő képernyő:

Itt nyilván nyomjuk ‘y’-t, ha ‘N’-t nyomunk (kis és nagybetű számít), akkor a telepítő kilép. Ezután valami hasonlót fogunk látni:

Itt arról tájékoztat, hogy az új Ubuntu 20.04 rendszer a mostanihoz képest 2 csomagot már nem támogat, 13 csomag el lesz távolítva, 208 csomagot fel fog rakni és 665 csomagot frissíteni fog. Rohadt vicces, hogy ha most visszamennénk 20 évet az időben, amikor még 56k modemmel interneteztünk (aki mondjuk a 80-as évek körül született, mint én is), akkor 19 óra alatt jönne le az 508MB-nyi telepítő adat 🙂 Én itt nyomtam egy ‘d’-t mert kíváncsi voltam a részletekre. Ha téged nem érdekel, nyomj ‘y’-t (fontos a kis és nagybetű!). Tehát a ‘d’-re kattintva ez fogadott:

A PHP 7.2 el lesz távolítva, ami nem is baj, mert más amúgy is 7.4-re akartam frissíteni (sőt már itt van a 8.0 is), meg pár Apache2 modul. Na és akkor itt van ez a kérdés, ami miatt érdemes be SSH-zni jól egy külön terminál sessionben:

Itt annyit közöl, hogy egy csomó szolgáltatás újraindul és ha megszakad valami, akkor nem fogsz tudni bejelentkezni (pl. SSH-val sem).

Ezután még jó sok mindent fogunk látni a képernyőn és sokszor, sok minden fog kérdezni az Ubuntu telepítőő. Főleg olyanokat, hogy a már meglévő konfig fájl eltér attól, amit installálni szeretnénk. Én a nagyrészét felülírtam, leginkább azokat, amiről tudtam hogy nem nyúltam hozzá. Amit viszont sokat állítgattam (pl. opendmarc), abból meghagytam a 18.04-es verziót. Nekem egészen eddig a kérdésig nem történt semmi probléma:

Itt nyomtam egy ‘D’-t, hogy mutassa a különbségeket. Ez amúgy az SSH konfig, ahol én pl. olyanokat állítottam be, hogy jelszóval ne lehessen be SSH-zni a szerverre, csak SSH kulccsal, stb. Viszont valamiért a ‘D’ megnyomása után fogta magát a rendszer és visszadobott ide:

Kicsit furcsa is volt, hogy a telepítés kellős közepén egy kérdés után visszakapom ezt a képernyőt. Mivel már csinálta egy ideje a telepítést még az is felmerült bennem, hogy végzett. Gondoltam megnézem az oprendszer verziót:

Úgy tűnik minden oké igaz? Sajnos nem, itt csak annyi történt, hogy az alapcsomag már befrissült, tehát a /etc/issue fájl tartalma lefrissült új oprendszer verziószámára, de azon kívül minden a régi maradt. Tehát megszakadt a telepítés. Ellenőriztem a PHP verziót, ami a 18.04-en még 7.2 volt, viszont a 20.04-n már 7.4-nek kellene lennie, és a gyanúm beigazolódott:

Gondoltam kiadom újra a do-release-upgrade parancsot, de nem segített:

Itt már látszik a gond a do-release-upgrade-re azt mondja a telepítő, hogy nincs fejlesztői változat, azaz a rendszer már a legfrissebb. Csakhogy a dist-upgrade -f (‘-f’, azaz force kapcsoló kell!) kiadva látszik, hogy a dpkg csomagkezelő frissítés közben leállt, tehát akkor adjuk ki ezt a parancsot:

sudo dpkg --configure -a

Ez már jó lett, elkezdte folytatni a frissítést a dpkg. Újra jött a kérdés:

Most ahelyett, hogy megnéztem volna a különbségeket (az előbb itt fagyott le a telepítő, plusz nem érdekelt, mert már elmentettem a teljes /etc könyvtárat) inkább felülírtam a régit a legújabb konfig fájllal. Ezután még jött egy csomó hasonló kérdés, majdnem mindenre (kivéve pl. opendmarc) Y-t nyomtam. Jött egy ilyen:

A dpkg lefutott, de az lxd-client nem tudta frissíteni. Akkor újra kiadtam ezt:

sudo apt dist-upgrade -f

Ezután újra elkezdett frissítgetni, köztük ezt a problémás LXD klienst is:

Fogalmam sincs mi volt ez, úgyhogy nyomtam egy ‘latest’-t (bár a telepítő a 4.0-t ajánlott). Folytatódott a frissítés, majd jött egy ilyen:

Amiről tudtam, hogy nem nyúltam hozzá a 18.04 konfigurálása után (ez volt az első Ubuntu verzióm), azt felülírtam az új verzióval (tehát ‘Y’-t nyomtam). Miután végzett a csomagok frissítésével, a grub-ot is frissíteni akarta:

Mivel az én szerveremen nincs más oprendszer, csak az Ubuntu, ezért itt a ‘package maintainer’s version’ lehetőséget választottam. Jött még néhány konfig fájl, például a Midnight Commanderé is:

Ezt véletlenül felülírtam, így a 20.04-en megint be kellett állítanom, hogy a backspace-re kattintva menjen vissza egy könyvtárat (mivel ez a beállítás az mc.keymap fájlban van tárolva, leírást lásd itt). Aztán jött az Opendkim konfig kérdése:

Na erre nyomtam például N-t nyomtam, mert elég sokat szórakoztam az email címeim authentikálásával, hiányzik a francnak, hogy újra be kelljen állítani. A vége felé még jött egy ilyen:

Itt Yes-t választottam, mert szeretném a jövőben saját kezűleg beállítani ezt. Néhány adabázisra vonatkozó kérdés, jelszó miegymás:

Ezután végzett a telepítés, amit egy rövid ‘done’ üzenettel adott tudtomra. Újraindítás után még nyomtam egy update-t és leszedtem a már nem használt csomagokat (ezt a do-release-upgrade amúgy megtenné helyettünk):

sudo apt autoremove

Ezután újraindítottam a szervert:

sudo init 6

Újraindítás után már a jól megszokott képernyő fogadott:

Újra leellenőriztem a php verziót:

Minden jó, ha vége jó. A telepítéshez köszönöm a segítséget Szécsényi Zoltán barátomnak!

Macbook Air M1-re váltás

Macbook Air M1-re váltás 2000 1500 bacsoa

Ez már a negyedik Macem. Az előző, egy 2017-es Touchbaros Macbook Pro egy rémálom volt. Egyrészt a billentyűzet miatt, amit kétszer is meg kellett csináltatnom – szerencsére gyári visszahívásban -, másrészt a touchbar miatt. Először jó ötletnek tűnt (de jó lesz majd Photoshopban, stb.), de a Macbookon eleve kevés a billentyű egy PC-hez képest, és akkor még a funkcióbillentyűket is elvették…borzalmas.

Tavaly jött az M1, amiről nem tudtam semmit, de a tesztek alapján meggyőző volt. Gyors és viszonylag olcsó. Mármint egy Apple termékhez képest 🙂 Volt még pár hónapja egy próbálkozásom, hogy egy Lenovo-ra tettem kizárólag Linuxot, hogy egyszerűbb legyen kipróbálni az új dolgokat (új Ubuntu, 8-as PHP kipróbálása, Redis vs. Memcached stb), de az nagyon nem jött be. Inkább a régi Macbook Pro-mra tettem egy Ubuntu külön partícióra, teljesen jól működik. A helyzet az, hogy a Macbook billentyűzet és főleg a trackpad egyszerűen tökéletes, ennél csak sokkal rosszabbakat próbáltam.

Vissza az M1-re. 2 hete használom és többségében elégedett vagyok.

Előnyök:

  • Gyors. Minden azonnal megnyílik és bőven elég a 8GB RAM. Legalábbis nekem, aki egy Atom vagy Sublime Text és Photoshop / Illustrator társaságában dolgozik nap, mint nap. Emellett nyitva van még kb 20 Chrome fül és 3-4 Firefox fül is. Plusz a szokásos Slack, Viber és Telegram folyamatosan. Egyáltalán nem érzem, hogy 16GB kellene, viszont az 512GB SSD az kell.
  • Billentyűzet. Végre visszakaptam a rendes gépelési élményt. Az Apple is rájött, hogy a pillangómechnikás fejlesztés egy zsákutca volt. Ezért visszatértek az jó öreg ollós mechnanizmushoz. Ezerszer jobb.
  • Trackpad. Ezen nincs mit magyarázni, a világ legjobb trackpadja. Ez az egyik oka annak, hogy notebookon dolgozom és nem asztalin, hogy a billentyűzet és a trackpad közel van egymáshoz, emiatt nem kell az egérhez jobbra nyúlni és emiatt felemelni a kezemet a billentyűzetről. Sokkal hatékonyabb így dolgozni. Én egyfolytában egy text editorban írom a kódot, közben nézem és tesztelem a weboldal működését, amihez meg egér kell. Megőrülnék, ha ezt egy külön egérrel kellene megtennem.
  • Kedvező ár. Hardveraprón áfa nélkül vettem ezt a gépet, vadonatújan, fóliával, magyar billentyűzettel. Ha az Apple-s árát nézed, akkor is teljesen jó. 200e Ft alatt egyáltalán nem kapsz normális gépet, ami gyors és megbízható. Maximum asztali verzióban.
  • Akkuidő. Nem mintha számítana, mert ezzel eddig sem volt gond (meg amúgy is rá van dugva folyamatosan a töltőre), de azért az elég jó, hogy esténként 2-3 óra netezés, youtube videó nézés után 4%-ot merül a gép. Ezzel tényleg megvan a 18 óra munkaidő.

Hátrányok:

  • Kompatibilitás. Tény, hogy pár program egyáltalán, vagy nem tökéletesen fut a Big Sur operációs rendszeren. Az Atom text editor, amin dolgozom konkrétan összefagy állandóan. Ezért most visszatértem a jó öreg Sublime Texthez, azzal tökéletes. Az SSHFS beállítása kb 3 órámba telt, mert a Big Surban egy csomó mindent megváltoztattak, emiatt nem volt egyszerű beállítani. Újraindítás után engedélyezni kellett a Kernel szintű kiegészítők telepítését, stb.
  • Brew csomagkezelő nem működik rendesen. A Brew az egyes Linux disztrók csomagkezelője (pl. apt, yum, pacman) helyett van. Sok minden nincs alapból a MacOS alatt (pl. Midnight Commander), amire a brew kínál megoldást. Jelenleg elég béta állapotban van. Annyira, hogy felraktam, aztán eltűnt 🙂 Majd újra felraktam, és épp most nem működik. Egyelőre várok vele.


Fotók