Magento vs. WooCommerce – Melyik az okosabb választás?

A piacon rengeteg különféle e-kereskedelmi rendszer érhető el, a domináns azonban a címben szereplő két versenyző, és nem is véletlenül. Mindkét rendszer rengeteg előnnyel rendelkezik, melyek vetélytársaik fölé emelik őket – de összehasonlítva hogyan teljesítenek? Honnan tudhatod, hogy jól választasz? Mielőtt belevágnál a kiválasztás folyamatába, ajánlatos lehetőségeidet, terveidet és igényeidet számba venni.

  • Ki a célcsoportod, mekkora a célpiacod?
  • Hány termékkel számolsz és milyen terheléssel?
  • Hogyan képzeled el az oldalt?
  • Képes vagy infrastruktúrával megtámogatni, pl. ERP-rendszerrel?
  • Keveset vagy többet szeretnél költeni a testre szabásra megjelenésében, funkcionalitásában? 
  • Szükséged van egy fejlesztőcsapat nyújtotta biztonságos háttérre, vagy megfelel egy előre meghatározott alap funkcionalitás, amit korlátozottan ugyan, de egymagad tudsz állítgatni?

Számos kérdésen kell végigmenned, és még azelőtt, hogy letennéd a voksod bármelyik megoldás mellett. Ugyan kipróbálni bármelyiket nem kerül semmibe, időt azonban vesztegetsz, és az átállás is problémás lehet, ha egyszer már beleszoktál a használatba, de rájössz, hogy mégsem a tökéleteset választottad. Most tehát részletesen végigvesszük az egyes szempontokat, amelyek alapján bölcs döntést hozhatsz, és hatékonyan e-értékesítheted portékádat.

Miben hasonlít egymásra a Magento és a WooCommerce?

Az egyik legfontosabb hasonlóság, hogy a Magento és a WooCommerce egyaránt nyílt forráskódúak, vagyis bárki hozzájárulhat fejlesztésükhöz. Ez mindkét esetben azt jelenti, hogy profi fejlesztők foglalkoznak velük, mégpedig jóval többen, mint egyébként céges kereteken belül maradva lehetséges volna. A nyílt forráskód előnye a rugalmasság: ha valamire szükségünk van, de a rendszer alapból nem tartalmazza, jó eséllyel valaki már lefejlesztett hozzá egy kiegészítőt – ha pedig mégsem, egyszerűen keresnünk kell valakit, aki megteszi ezt nekünk. Mindkét platform mögött erőteljes közösségek állnak. A WooCommerce-t a WordPress felhasználók tábora támogatja, míg a Magento dedikált közösséggel rendelkezik, akik folyamatosan fejlesztik, ellenőrzik a kódot és segítik egymást a keretrendszer újabb és újabb lehetőségeinek meglelésében, a létezőek kiterjesztésében vagy újak létrehozásában. Hasznos ez azért is, mert egy egyszerű supportnál sokkal komolyabb segítséget kaphatunk. Ahelyett, hogy egy kézikönyvet lapozgató call centeres kollégával kellene beszélgetni, felhasználók ezreit tömörítő fórumokon kérdezhetünk, ahol egészen biztosan hasznos, első kézből származó, tapasztalatokra és szaktudásra épülő segítséget kaphatunk. Ami még fontosabb, a termékek és a kommunikáció terén is bír közös jellemvonásokkal a két rendszer. Mind a két estben lehetőségünk van arra, hogy korlátlan számú terméket töltsünk fel és kezeljünk egy helyen, hogy blogot indítsunk az oldalon, ami tartalommarketinges szempontból igen előnyös és a SEO-t is segíti. A Magento-ban ehhez egy bővítmény telepítésére van szükség, míg WooCommerce-nek a WP miatt alapból része. (Bevett gyakori megoldás egyébként, hogy egy WooCommerce-plugin nélküli WordPress céges oldalba webáruház menüpontot illesztenek, ami például a webshop.encegem.hu domainre irányít – ami pedig egy Magento a céges oldalhoz illeszkedő dizájnnal.) Látható, hogy a hasonlóságok elsősorban nagy vonalakban mutatkoznak meg, a lehetőségek terén – most azonban lássuk, miben különbözik egymástól a két rendszer…

Miben különbözik egymástól a Magento és a WooCommerce?

Magento vs WooCommerce

Használhatóság

Ha már eleve WordPress alapú oldalt használsz, és ugyanazon az oldalon akarod kialakítani a webboltot, logikus, hogy a WooCommerce mellett tedd le a voksodat – a kezelése igen egyszerű, ha már hozzászoktál a WP-hez, és tisztességes mennyiségű oktatóvideó is rendelkezésre áll. Ugyanakkor a Magento alapjai szintén könnyen kiismerhetőek. Temérdek oktatóvideó, alapos dokumentációs anyag és dedikált wiki oldal segít, hogy az első lépéseket megtedd, és még kezdő felhasználóként sem ütközöl majd komolyabb akadályokba, az adminisztrációs felület ugyanis rendkívül felhasználóbarát. A helyzet csak akkor kezd igazán bonyolódni, amikor kiegészítéseket kezdesz az oldalhoz adni, amelyek bővíthetik a rendszeren belüli lehetőségeid körét.

Költségek

TANSTAAFL („There Ain’t No Such Thing As A Free Lunch”) Végül mindennek meg kell fizetni az árát, és ha egy olyan rendszert keresel, amelyet komoly üzleti használatra szánsz és a bevételeidet alapozod rá, ez különösen igaz. Alapvetően mind a két rendszer ingyenes (a Magento esetében a Community Edition), költenünk akkor kell rájuk, ha bővíteni akarjuk a funkcionalitást. Mindkét esetben lehetőségünk van arra, hogy ingyenes és fizetős kiegészítőket telepítsünk, ebben nagy különbség nincs. Ha külön fejlesztőt akarunk fogadni, a WooCommerce esetében talán könnyebben találunk ilyet, mivel WP alapú rendszerről van szó. A Magento fejlesztése biztosan drágább, de mivel robusztusabb rendszer, ezért egyedi fejlesztések telepítésekor sok helyen „eltörhet” ezért olyan céget kell választanod, ahol komoly minőségbiztosítással dolgoznak, többszörös teszteléssel. Komoly, összetett funkcionalitást a gyakran szűk határidők miatt érdemes akár több fejlesztővel készíttetni párhuzamosan, ehhez viszont komolyabb fejlesztői infrastruktúra kell, koordinált munka és dedikált, az ügyfelet képviselő projektmenedzser a fejlesztőcégen belül. Bonyolultnak hangzik? Az is. Megéri? Minden bizonnyal. A hosting tekintetében a Magentonak nagyobbak az igényei. A WooCommerce szimpla WP hostinggal is beéri (bár a több ezres termékszám egyidejűleg sok látogatóval azért bőven képes megakasztani), a Magento esetében viszont saját szerveren kell futtatnunk, de még inkább megéri, ha valamilyen felhőalapú rendszerre fizetünk be (amennyiben nemzetközi, vagy nagy terhelés várható, ezt ajánljuk) vagy dedikált szervert bérlünk. Ez azonban azt is jelenti, hogy nagyobb teljesítményt kapunk. A Magento skálázhatósága révén óriási üzlethálózatokat is képes kezelni, egyszerre több webáruházat, ehhez pedig mindenképpen szükség van külön hosting szolgáltatásra – ez az ára annak, hogy minőségi szolgáltatást és magas színvonalú felhasználói élményt nyújthass.

Funkciók és lehetőségek

Az, hogy egy e-kereskedelmi platform képes legyen (legalábbis elméletben) korlátlan számú terméket kezelni, virtuális bevásárlókosarat biztosítani, alapvető – ezt természetesen mind a két rendszer tudja. Fontos azonban az is, hogy mennyire tudod testre szabni a termékeket, az egész folyamatot – és ezen a ponton a Magento egyértelmű győztesként kerül ki az összehasonlításból. A Magento rendszerében lehetőségünk van az upsell és cross-sell lehetőségeket bőségesen kiaknázni, az egyes termékek között összehasonlításokat végezhetünk és nagyon pontosan szűrhetünk arra, amire szükségünk van – a Magento egyik legcsábítóbb feature-je a szűkítő keresési feltételek megadásának lehetősége. A WooCommerce-ben elsősorban az akciókra és kuponokra koncentráltak a fejlesztők, bár a szűkített keresés mára ebben a rendszerben is megjelent, a Magento azonban ennél sokkal komplexebb és sokoldalúbb lehetőségeket kínál. Magento Dashboard   És akkor még csak a felhasználói oldalról beszéltünk. A „túloldalon”, vagyis az adminisztrációs felületen azok, akik szeretik a lehető legalaposabban testre szabni termékeiket, azok jellemzőit, a felhasználói tevékenység alapján az oldalon zajló történéseket – és ez nagyjából a kicsit is tapasztalt webáruház-üzemeltetők 100 százalékát jelenti – magukon kívül lesznek a gyönyörtől. Az adminisztrációs felületen ugyanis elképesztő mennyiségű beállításra nyílik lehetőségünk, többek között arra, hogy tökéletesen szabadon határozzuk meg az egyes kategóriákhoz, termékekhez tartozó attribútumokat. A Magento-ban jellemzőcsoportokat határozhatsz meg (attribute sets),így például megadhatod, hogy az „autógumi” jellemzőcsoportnak van „átmérő” és „évszak” jellemzője, az évszak jellemző értékei közül pedig a felhasználó a szűkítő keresésben kiválaszthatja a téli, nyári, átmeneti opciókat. Erről bővebben itt olvashatsz. A Magento e téren rendkívül rugalmas rendszer, ami óriási előnyére válik, hiszen mindegy, hogy porcelántányérokat, processzorokat vagy paprikát akarunk árulni: a rendszer könnyedén hozzáidomítható a termékhez.

Néhány szó az analitikáról

Ahhoz, hogy hatékony webáruházat üzemeltessünk, mindenképpen szükségünk lesz részletes statisztikai adatbázisokra. Mindkét rendszerben lehetőség van a Google Analytics integrációra (illetve a Magento esetében ennek kiterjesztésére is az Enhanced Ecommerce alkalmazással), így e tekintetben nem maradnak adósok, ez pedig önmagában bőséges adatmennyiséggel lát el minket ahhoz, hogy ennek megfelelően optimalizálhassuk oldalunkat. A Magento ezen kívül saját maga is készít statisztikákat a legnézettebb, legkeresettebb, legtöbbet vásárolt termékekről. Többféle sales jelentés készíttethető vele gyárilag, amelyek .CSV formátumban exportálhatóak. A Magento esetében a funkciók szinte korlátlanul bővíthetőek, tekintve a keretrendszer rugalmasságát, és a Magento Connect adatbázisban több ezer kész kiegészítőt is találunk hozzá (rengeteget ingyenesen letölthetünk), telepítésükhöz azonban nem árt, ha a rendszer kezelésében tapasztalt szakember segítségét vesszük igénybe. Ezzel együtt e kategóriában a Magento gyakorlatilag kiütéssel győz. A WooCommerce egyszerű WordPress pluginként kínál kiegészítéseket, amelyeket egyszerűbb kezelni, lehetőségeink azonban korlátozottabbak is. Nyilvánvaló, hogy egy az alapoktól e-kereskedelemre kihegyezett rendszer más súlycsoportot képvisel e téren, mint egy eredetileg általános célokra (blog, corporate oldal, hírportál stb.) fejlesztett motor, melyet később egészítettek ki egy e-commerce pluginnel. Utóbbi előnye viszont épp ezért a profi blogrendszer a Magentoval szemben – erről mindjárt bővebben olvashatsz. Tény, hogy amennyiben kicsit is profibb webáruházat akarunk építeni, bőven megéri időt, energiát és pénzt is fektetni a Magento fejlesztésébe – nem véletlenül használják a keretrendszert olyan világmárkák is, mint a Nike, a Gant vagy a Samsung.

Dizájn

Reszponzivitás Egy webáruháznak ma mindenekelőtt reszponzívnak kell lennie. Ha nem jelenik meg tökéletesen és könnyen használhatóan minden platformon a mobiloktól az asztali PC-kig, akkor a potenciális vásárlók jelentős hányadáról önként mondunk le. A WooCommerce egyszerűen integrálható a WordPress-szel, így a reszponzivitás jellemzően nem jelent problémát. Számos különféle theme, vagyis előre elkészített téma érhető el hozzá. Ezek legtöbbje pénzbe kerül, az esetek többségében azonban ezek a profi sablonok még mindig olcsóbbak, mintha vázterveket, minden oldalra egyedi dizájnt, front end és back end fejlesztéseket készíttetnél a Magento-hoz. Ha még csak most indulsz az online piacon, befektetés szempontjából WooCommerce-szel jobban jársz – ha pedig már széttépnek a vásárlók, mert annyira nagy az igény, akkor lépj tovább Magentora. Ekkor viszont már a kikristályosodott kereskedelmi modell és egy már bevezetett ügyviteli/számlázó/raktárkezelő rendszer létfontosságú, ezekkel kell majd összekötnöd Magento áruházadat. A Magento 2014 óta (v1.9) teljesen reszponzívnak tekinthető, és hatalmas mennyiségű ingyenes megjelenést tölthetünk le, ezen belül pedig szabadon alakíthatjuk az oldal megjelenését.

Tartalomkezelés

A Magento kifejezetten egy e-kereskedelmi célokra fejlesztett rendszer, így komplex igények esetén sokkal jobban teljesít, mint a WooCommerce, hiszen a WordPress a tartalomszolgáltatásra, portfolió-bemutatásra, corporate oldalak létrehozására és hírszolgáltatásra van kihegyezve. Alapvető funkciókra a Magento rendszerén belül is találhatunk, blogot indíthatunk az oldalon, a tartalommenedzsment azonban valamivel nehézkesebb. Persze olyasmit nem nagyon találunk, amit bármelyik rendszer ne volna képes valamilyen módon elvégezni – minden azon múlik, milyen beállításokat alkalmazunk, hogyan alakítjuk ki saját rendszerünket, milyen kiegészítőket telepítünk. Ha hírlevelet küldenénk, akkor sem a Magento a jó választás. Annak idején a fejlesztők úgy döntöttek, integrálnak egy alapvető funkciókat ellátni képes megoldást, ezen túl azonban nem sokra megyünk vele. Léteznek szegmentálásra képes bővítmények, de még mindig érdemesebb valamelyik komolyabb hírlevélküldő szolgáltatást választani e célra, mint például a MailChimp vagy a Getresponse, hazánkban pedig a Mailmaster vagy a Webgalamb.

Melyiket „szokás” választani?

A Magentot gyakrabban választják nagyvállalatok és olyan cégek, amelyek ügyfeleik webáruházait kezelik, ezeket pedig ügyviteli rendszerhez csatolják a számlázás, készletfrissítés menedzselése végett. Ideális megoldás ugyanis azok számára, akik nagyban gondolkodnak, nagyot álmodnak, de azoknak is, akik már rendelkeznek egy jó menő webáruházzal, csak éppen többre vágynak, mint amit a rendszer nyújtani képes. A WooCommerce inkább a kisvállalkozások körében népszerű, akik már hozzászoktak a WordPresshez. Igen fontos szempont, hogy a Magento kifejezetten e-kereskedelmi célokra készült. Nem csak a WordPress kiegészítése, hanem egy komplett keretrendszer, amelyen belül alig túlozva bármit megoldhatunk, amire csak szükségünk van.

Nézzük a számokat!

Az AheadWorks 2015 nyarán készített egy átfogó tanulmányt, melyben a Magento és a WooCommerce népszerűségét vizsgálták elsősorban, mégpedig különféle piacterületek szerinti bontásban. Mielőtt azonban erre rátérnénk, érdemes megnézni azt is, hogy az Alexa adatai szerinti legnagyobb látogatottsági statisztikákkal bíró egymillió oldal között hogyan oszlanak meg a két rendszer felhasználói. Az adatok azt mutatják, hogy a Magento felhasználóinak oroszlánrésze a 100-300 ezredik helyek közötti oldalak szegmensében található, míg a WooCommerce használói inkább a 900 ezres helyezések birtokosai. Ebből túlságosan messzemenő következtetéseket levonni botorság volna, annyi azonban biztos, hogy a Magentot használó oldalak általánosságban népszerűbbek. A legérdekesebb talán a termékkategóriák szerinti megoszlás. Míg a WooCommerce-t leggyakrabban szoftverek és információs anyagok, illetve konzultációs szolgáltatások, valamint élelmiszerek értékesítésére használják, a Magento esetében a felhasználók legnagyobb arányban ruhák és kiegészítők, bútorok, illetve ékszerek és ajándéktárgyak értékesítésével foglalkoznak. A WooCommerce webboltokban általában nem anyagi javakat, hanem szellemi termékeket értékesítenek, a kézzelfogható termékek eladására a Magento népszerűbb platformnak számít. Egy másik statisztikát is érdemes megnézni, amelyet az egyik legnépszerűbb CMS detektor böngészőplugin, a Wappalyzer készített (2016 januári adatok) Ecommerce CMS Market Share 2016 January

Szóval, melyik a jobb? A Magento vagy a WooCommerce?

Ezt egyértelműen nem jelenthetjük ki, mind a két rendszer más célcsoport számára lehet ideális. Annak azonban, aki egy komolyabb webáruházat akar felépíteni, egyértelmű a választás.

 

Mit tud a Magento?

Évek óta a piac egyik legerősebb, egyik legnépszerűbb self-hosted szereplője, melyet kifejezetten e-kereskedelmi keretrendszernek fejlesztettek. Funkciókban és lehetőségekben gazdag, megfelelő infrastruktúrával megtámogatva gyors, akár egyszerre több webáruházat futtatva is (mert erre is képes), jól keresőoptimalizálható.

Magento eCommerce CMS compared

Könnyen honosítható, a pénznemek állíthatóak, így nemzetközi értékesítésre is kiváló. Viszont komplex megoldás, kezelésének elsajátítása, hogy teljes potenciálját kiaknázhassuk, hosszabb időbe telhet.

 

Mit tud a WooCommerce?

Létező WordPress oldalakba remekül integrálható kiegészítő lehetőség, könnyen kezelhető. Funkciók terén szűkösebben áll, egy kisebb, kevésbé komplex üzleti folyamatokat megvalósító webbolt számára azonban megfelelő megoldás.

Wordpress WooCommerce CMS compared

Ez utóbbi megoldás inkább a kezdők számára megfelelő, akik csak néhány terméket akarnak egy kisebb célközönségnek eladni. Aki viszont növekedésre, fejlődésre számít, aki egyszerre több boltot üzemeltetne, több száz vagy akár több ezer termékkel, és teljesen szabadon akarja alakítani webáruházát, annak a Magento garantálja a sikert. Bármilyen kérdésed merül fel a cikkel vagy a fent említett keretrendszerekkel kapcsolatban, írd meg kommentben és válaszolunk!

 

Hogyan hozd ki a maximumot Magento-ban az oldalbetöltési sebességből?

Webáruházak esetén ez kiemelten súlyos gond lehet, hiszen a konkurens cégek oldalai megelőzik a miénket. Hivatalos mérések szerint, ha rátalálnak is az oldalunkra a látogatók, minden egyes várakozással eltöltött másodperc miatt legalább 7% konverzió csökkenést érhetünk el. Az oldalak sebességét mérhetjük külső eszközökkel, ahol javaslatokat is kaphatunk az optimális cél eléréséhez, ilyen oldalak pl. a következők:

Személyes kedvencünk a New Relic szoftverelemző szoftver, melynek segítségével folyamatosan nyomon tudjuk követni az oldalaink sebességét (és még nagyon sok hasznos dolgot ezen kívül). A fent felsorolt eszközök nagyon sokat segítenek a lassulás tényének megállapításában, de nem látnak bele a Magento-ban zajló belső folyamatokba. Én most ezeknek a belső folyamatoknak a felderítéséről, és javításáról szeretnék írni.

A felderítés

Belső profiler

A belső folyamatok sebesség méréséhez egy belső profilert használhatunk. A profiler segítségével betekintést nyerhetünk a  controller-ek, action-ok, block-ok, observer-ek és egyebek sebesség és memória használatába. Használatához a System / Configuration / Developer / Debug / Profiler szekcióban kell a profilozást engedélyeznünk, és ha publikus oldalon mérünk, akkor a System / Configuration / Developer / Developer Client Restriction szekcióban az IP-címünket is be kell állítanunk. Ezután az index.php fájlban ki kell szednünk a kommentet a következő sor elől:

 Varien_Profiler::enable(); 
Az eredmény hasonlóan fog kinézni:

Magento Code Profiling

A saját moduljainkban a következő sorok beillesztésével használhatjuk a profiler opcióit:

Varien_Profiler::start('egyedi_profil_azonosito');
//... itt vannak a mérendő kódsorok
Varien_Profiler::stop('egyedi_profil_azonosito');

Az SQL lekérdezések profilozásához az app/etc/local.xml-ben kell elvégeznünk a beállításokat:

<default_setup>
     <connection>
         <host><![CDATA[localhost]]></host>
         <username><![CDATA[mage_user]]></username>
         <password><![CDATA[mage_password]]></password>
         <dbname><![CDATA[mage_db]]></dbname>
         <initStatements><![CDATA[SET NAMES utf8]]></initStatements>
         <model><![CDATA[mysql4]]></model>
         <type><![CDATA[pdo_mysql]]></type>
         <pdoType><![CDATA[]]></pdoType>
         <active>1</active>
         <profiler>1</profiler>
     </connection>
 </default_setup>

Ennek a beállításnak az eredménye a következő képen látható:

Magento Code Profiling 2

 

Aoe Profiler

Lássuk be, ezt elég nehéz olvasni, és nem is látszik rajta, milyen struktúrában épülnek fel ezek az adatok, emiatt egy időben használtuk az  Aoe_Profiler nevű plugint. Ez a plugin már hierarchikus struktúrában jeleníti meg az adatokat, szép, átlátható kis diagramokkal, melyek segítségével sokkal pontosabb információt nyerhetünk arról, mik azok a dolgok, amelyek rontják a teljesítményt az oldalunkon.

Aoe Profiler Magento Code

Mi ezek helyett az AionHill saját fejlesztésű modulját használjuk, amellyel még hatékonyabban kideríthetőek, mik azok a dolgok, amik rontják a teljesítményt.

Az AionHill_Profiler bemutatása

Blokkok

Hierarchikus felépítésben megjelenítjük a megjelenített blokkokat, jelezve a megjelenítésükhöz felhasznált időt grafikonon és másodpercben kiírva, listázzuk, hogy az adott blokk használ-e cache-t, és a blokk megjelenítése közben futtatott SQL lekérdezéseket.

Magento Code Profiler by AionHill

 

SQL lekérdezések

A modul megjeleníti az oldalon használt SQL lekérdezéseinket is. Itt is használunk diagramot, valamint másodpercben is kiírjuk az időt, valamint a teljes utat (stack trace), amiből megállapíthatjuk, melyik Magento osztály melyik sorából indult az SQL lekérdezés.

Magento SQL Queries

 

Ismétlődő SQL lekérdezések

A modul figyelmeztet minket, ha vannak teljesen azonos SQL lekérdezések az oldalon belül. Az ábrán jól látható, hogy hány ilyen van, ezek hányszor fordulnak elő, és összesen mennyi időt kellett erre fordítania a MySQL szervernek.

 

Magento SQL Queries Repeats

 

Ciklusba rakott SQL lekérdezések

Végül pedig a ciklusba rakott – de nem feltétlenül azonos – SQL lekérdezéseket derítjük fel:

Magento Loop SQL Queries

 

Megoldási javaslatok

És most lássunk néhány gyakorlati példát, mit tehetünk a felderített problémák javítása érdekében.

Szüntessük meg a ciklusba rakott SQL lekérdezéseket.

Bármilyen gyors is az SQL szerver, felesleges futásidőt visz el a többszöri ok nélküli meghívása. Ha csak tehetjük, kérdezzük le az adatainkat egyben, ne pedig ciklusban egyenként. Példaként mellékeltem 2 függvényt, amik a paraméterként kapott termékazonosítók átlagárával térnek vissza. Az első – hibás – módszer egy ciklusban egyenként betölti a termékeket, majd egy tömbhöz adja az árát, melyből a cikluson kívül kiszámolja az átlagárat, és visszatér vele.

/**
 * get Average Price (bad example)
 *
 * @param array $productIds product ids
 *
 * @return float
 */
public function getAveragePriceBadMethod(array $productIds)
{
 $prices = array();

 foreach ($productIds as $productId) {
 $product = Mage::getModel('catalog/product')->load($productId);
 $prices[] = $product->getPrice();
 }

 return array_sum($prices) / count($prices);
}

Egy példa az egyik lehetséges jó megoldásra: A termékeket nem egyesével, hanem az őket tartalmazó kollekciót kérdezzük le, majd ennek az elemeivel dolgozunk.


/**
 * get Average Price (good example)
 *
 * @param array $productIds product ids
 *
 * @return float
 */
public function getAveragePriceGoodMethod(array $productIds)
{
    if (empty($productIds)) {
        return 0;
    }

    $prices = array();
    $products = Mage::getResourceModel('catalog/product_collection')
        ->addAttributeToSelect('price')
        ->addAttributeToFilter('entity_id', array('in' => $productIds));

    foreach ($products as $product) {
        $prices[] = $product->getPrice();
    }

    return array_sum($prices) / count($prices);
}

Valójában ebben az esetben még ez sem a legoptimálisabb megoldás, hiszen ha csak az árra van szükségünk, felesleges a teljes kollekció betöltése. Ha csak egyetlen mező értékére van szükségünk, használhatjuk a következő módszert:


/**
 * get Average Price (good example)
 *
 * @param array $productIds product ids
 *
 * @return float
 */
public function getAveragePrice(array $productIds)
{
    if (empty($productIds)) {
        return 0;
    }

    $products = Mage::getResourceModel('catalog/product_collection')
        ->addAttributeToSelect('price')
        ->addAttributeToFilter('entity_id', array('in' => $productIds));

    $select = $products->getSelect()
        ->reset(Zend_Db_Select::COLUMNS)
        ->columns('price');

    $prices = $products->getConnection()->fetchCol($select);

    return array_sum($prices) / count($prices);
}

Gyakori probléma szokott lenni a kosárba rakott termékekkel való munka során a termék ismételt lekérdezése adatbázisból. A Quote model gondoskodik róla, hogy az elemekhez kapcsolódó termékek már be legyenek töltve, nincs szükségünk újabb model load-okra.

/**
 * get Quote Weight (bad example)
 *
 * @return float
 */
public function getQuoteWeightBadExample()
{
    $quoteItems = Mage::getSingleton('checkout/cart')->getQuote()->getAllItems();
    $quoteWeight = 0;

    /** @var Mage_Sales_Model_Quote_Item $quoteItem */
    foreach ($quoteItems as $quoteItem) {
        $product = Mage::getModel('catalog/product')->load($quoteItem->getProductId());
        $quoteWeight += $product->getWeight() * $quoteItem->getQty();
    }

    return $quoteWeight;
}

/**
 * get Quote Weight (good example)
 *
 * @return float
 */
public function getQuoteWeight()
{
    $quoteItems = Mage::getSingleton('checkout/cart')->getQuote()->getAllItems();
    $quoteWeight = 0;

    /** @var Mage_Sales_Model_Quote_Item $quoteItem */
    foreach ($quoteItems as $quoteItem) {
        $quoteWeight += $quoteItem->getProduct()->getWeight() * $quoteItem->getQty();
    }

    return $quoteWeight;
}

Szüntessük meg az ismétlődő SQL lekérdezéseket

Természetesen lehet indokolt eset arra, ha ugyanazt a lekérdezést többször kell megismételnünk – pl. módosítás utáni újra betöltés ellenőrzés céljából – de nagyon sokszor tervezési/fejlesztési hiba áll a háttérben. A leggyakoribb hibák a következők szoktak lenni. Többször használt metódus visszatérési értékét nem tároljuk el:


/**
  * get Feature Categories (bad example)
  *
  * @return Mage_Catalog_Model_Resource_Category_Collection
  * @throws Mage_Core_Exception
  */
 public function getFeatureCategoriesBadExample()
 {
     $categories = Mage::getModel('catalog/category')->getCollection()
         ->addAttributeToSelect('*')
         ->addAttributeToFilter('name', array('like' => '%feature%'))
         ->load();
 
     return $categories;
 }

Ha egy oldalon 10 különböző helyen használjuk ezt a metódust, akkor 9 esetben teljesen feleslegesen kérdezzük le újra az adatokat a mySQL szervertől. Az eredményt eltárolhatnánk egy osztályváltozóban, és ezt használhatnánk cache-elésre.


/**
  * Local cache for feature categories
  *
  * @var null|Mage_Catalog_Model_Resource_Category_Collection
  */
 protected $_featureCategories = null;
 
 /**
  * get Feature Categories (good example)
  *
  * @return Mage_Catalog_Model_Resource_Category_Collection
  * @throws Mage_Core_Exception
  */
 public function getFeatureCategories()
 {
     if (!is_null($this->_featureCategories)) {
         return $this->_featureCategories;
     }
 
     $this->_featureCategories = Mage::getModel('catalog/category')->getCollection()
         ->addAttributeToSelect('*')
         ->addAttributeToFilter('name', array('like' => '%feature%'))
         ->load();
 
     return $this->_featureCategories;
 }

Egy másik gyakori probléma, ha singleton helyett model-t használunk. Eleve az is performancia gondot okozhat, ha egy példány helyett egy osztály több példányban létezik, de ha komolyabb műveleteket is végez, akkor a baj csak még nagyobb lehet. A következő példa egy kiterjesztett kosár, melynek a konstruktorában elhelyeztem egy kategória kollekció betöltését.


/**
 * Class My_Module_Model_Checkout_Cart
 */
class My_Module_Model_Checkout_Cart extends Mage_Checkout_Model_Cart
{
    /** @var Mage_Catalog_Model_Resource_Category_Collection  */
    protected $_quoteCategories;

    /**
     * Constructor
     */
    public function __construct()
    {
        parent::__construct();

        $categoryIds = array();
        $quoteItems = $this->getQuote()->getAllItems();

        /** @var Mage_Sales_Model_Quote_Item $quoteItem */
        foreach ($quoteItems as $quoteItem) {
            $product = $quoteItem->getProduct();
            $categoryIds = array_merge($categoryIds, $product->getCategoryIds());
        }

        $this->_quoteCategories = Mage::getModel('catalog/category')->getCollection()
            ->addAttributeToSelect('*')
            ->addAttributeToFilter('entity_id', array('in' => array_unique($categoryIds)))
            ->load();
    }
}

Ezzel még nem is lenne nagy baj, ha megfelelően kezeljük ezt a kiterjesztett osztályt.


// hibás példa 
$productIds = Mage::getModel('my_module/checkout_cart')->getProductIds();
$itemsQty = Mage::getModel('my_module/checkout_cart')->getItemsQty();

// helyes példa
$productIds = Mage::getSingleton('my_module/checkout_cart')->getProductIds();
$itemsQty = Mage::getSingleton('my_module/checkout_cart')->getItemsQty();

A fenti hibás példában több példányban jön létre az osztályunk, és a konstruktorban levő kategória lekérdezés minden esetben le fog futni. Ugyanez a helyzet, ha különböző metódusokban vannak erőforrásigényes dolgok. Ebben az esetben, még ha a korábban látott példa alapján egy osztályváltozót használunk cachelésre, akkor is újra végrehajtódnak az időigényes kódsorok, hiszen a korábbi számításainkat az osztály egy másik példányában tároltuk el. Az alsó, helyes példa esetén az objektum egy példányban jön létre, és nem végzünk felesleges műveleteket. Ha valamilyen okból nem tudunk az singletont használni, akkor használhatjuk a Magento Helper-eket – ezek singleton osztályok -, vagy esetleg a Mage::registry-t átmeneti adatok tárolására. Ezek nagyon egyszerű tippek, de ha nem figyelünk oda rájuk, nagyon könnyen sokszorosára nőhet egy oldalon az SQL lekérdezések száma.

A hosszabb futás-idejű SQL lekérdezések javítása

Megfelelő tábla indexek létrehozása

Sokszor az állhat a háttérben, hogy a kérdéses tábla megfelelő mezői nincsenek indexelve. Ezzel óvatosan kell bánni, mert minél több indexet használunk a tábláinknál, annál lassabb lesz az írás ezekbe a táblákba, a keresés és rendezés viszont lényegesen gyorsabb lesz. Nagyon fontos, hogy optimálisan határozzuk meg a tábla szerkezetet és az indexeket. A tábláinkra a modulban elhelyezett installer segítségével tehetünk indexeket.


$installer = $this;

$installer->startSetup();

$tableName = $installer->getTable('my_module/model');

if ($installer->getConnection()->isTableExists($tableName)) {
    $table = $installer->getConnection();

    try {
        $table->addIndex(
            $installer->getIdxName(
                'my_module/model',
                array(
                    'column1',
                    'column2',
                ),
                Varien_Db_Adapter_Interface::INDEX_TYPE_INDEX
            ),
            array(
                'column1',
                'column2',
            ),
            array('type' => Varien_Db_Adapter_Interface::INDEX_TYPE_INDEX)
        );
    } catch (Exception $e) {
        Mage::logException($e);
    }
}

$installer->endSetup();

A termék flat táblák indexelésének kiterjesztése

Sok termék esetén még a product flat táblákból is lassabbak lehetnek a lekérdezések, ha olyan szűrést vagy rendezést használunk, amire a Magento nem tesz mező indexet. A flat táblákat nem tudjuk installerből indexelni, hiszen ezeket a táblákat eldobja és újra létrehozza indexeléskor a Magento, viszont egy observerrel módosíthatunk a flat tábla alapértelmezett indexein. Ennek a megvalósításához a catalog_product_add_indexes eseményre kell ráakasztanunk egy observert.


<events>
    <catalog_product_flat_prepare_indexes>
        <observers>
            <my_module_catalog_product_flat_prepare_indexes>
                <type>singleton</type>
                <class>my_module/observer</class>
                <method>catalogProductFlatPrepareIndexes</method>
            </my_module_catalog_product_flat_prepare_indexes>
        </observers>
    </catalog_product_flat_prepare_indexes>
</events>

/**
 * Add indexes to product flat table
 *
 * @param Varien_Event_Observer $observer observer
 *
 * @return void
 */
public function catalogProductFlatPrepareIndexes(Varien_Event_Observer $observer)
{
    /** @var Varien_Object $indexesObject */
    $indexesObject = $observer->getIndexes();
    /** @var array $indexes */
    $indexes = $indexesObject->getIndexes();

    $indexes['IDX_MY_ATTRIBUTE'] = array(
        'type' => Varien_Db_Adapter_Interface::INDEX_TYPE_INDEX,
        'fields' => array('my_attribute')
    );

    $indexesObject->setIndexes($indexes);
}

A fenti metódus mindig lefut, mikor újra-indexelés miatt a Magento újra létrehozza a flat táblát.

Nagy erőforrásigényű SQL join-ok mellőzése

Vannak olyan esetek, amikor már nem lehet szimplán indexekkel kezelni egy lassú lekérdezést, mert több nagy táblát kapcsolunk össze, és mindenképp hatalmas adatmennységgel kell megküzdenie a MySQL szervernek. Tételezzük fel pl. a következő esetet: szeretnénk a terméklista oldalon készlet mennyiség, és értékelés szerint rendezést végrehajtani. Ebben az esetben a következő módszert szoktuk használni:


$collection->joinField(
    'quantity',
    'cataloginventory/stock_item',
    'qty',
    'product_id=entity_id',
    '{{table}}.stock_id=1',
    'left'
);

$collection->joinField(
    'rating_summary',
    'review_entity_summary',
    'rating_summary',
    'entity_pk_value=entity_id',
    array(
        'entity_type' => 1,
        'store_id' => Mage::app()->getStore()->getId()
    ),
    'left'
);

$collection->setOrder($attribute, $direction);

Itt a termékek és az értékelések mennyiségétől függően hatalmas mennyiségű adat is összegyűlhet, és ebben a rendezés iszonyú lassúra sikerülhet. Rengeteg praktikát lehet elsajátítani a MySQL lekérdezésekkel kapcsolatban, én itt arra az egyszerű esetre szeretnék rávilágítani, hogy nincs is a join-ra minden esetben szükség, csak amikor tényleg használnánk őket.


if ($attribute == 'quantity') {
    $collection->joinField(
        'quantity',
        'cataloginventory/stock_item',
        'qty',
        'product_id=entity_id',
        '{{table}}.stock_id=1',
        'left'
    );
}

if ($attribute == 'rating_summary') {
    $collection->joinField(
        'rating_summary',
        'review_entity_summary',
        'rating_summary',
        'entity_pk_value=entity_id',
        array(
            'entity_type' => 1,
            'store_id' => Mage::app()->getStore()->getId()
        ),
        'left'
    );
}

$collection->setOrder($attribute, $direction);

Ezzel az apró trükkel máris megakadályoztuk 2 nagy tábla hozzákapcsolását a termék kollekcióhoz, mindig csak annak a táblának a kapcsolása történik meg, amire valóban szükségünk van.

Magento blokkok teljesítményjavítása

Amikor csak lehetséges, használjuk a Magento blokkok cachelését. Ha szükséges, szegmentálhatjuk ezeket a cache adatokat felhasználói csoportonként, és több szegmentációt is kombinálhatunk.


/**
 * construct
 *
 * @return void
 */
protected function _construct()
{
    $this->addData(
        array(
            'cache_lifetime' => 3600,
            'cache_key'      => 'MY_MODULE_' . $this->getExampleModel()->getId(),
            'cache_tags'     => array(My_Module_Model_Example::CACHE_TAG)
        )
    );
}

Használjunk ún. objetum cache-t. Itt azokra a metódusokra gondolok, amelyeket többször is meghívunk, és nem feltétlenül szükséges mindig futtatnunk a benne levő kódokat.


/**
 * get Category Collection
 *
 * @return Mage_Catalog_Model_Resource_Category_Collection|mixed
 * @throws Mage_Core_Exception
 */
public function getCategoryCollection()
{
    if ($this->hasData('category_collection')) {
        return $this->getData('category_collection');
    }

    $collection = Mage::getModel('catalog/category')->getCollection()
        ->addAttributeToSelect('*')
        ->addAttributeToFilter('parent_id', array('eq' => Mage::app()->getStore()->getRootCategoryId()));

    $this->setData('category_collection', $collection);
    return $collection;
}

Egyéb hasznos fejlesztői javaslatok a jobb teljesítmény érdekében

Egyszerűbb SQL lekérdezések

Ha csak pl. azonosítókat szeretnénk egy kollekcióból összegyűjteni, oldjuk meg ciklus nélkül:


// rossz példa
$ids = array();

$products = Mage::getModel('catalog/product')->getCollection()
    ->addAttributeToFilter('sku', array('like' => 'test-%'));

foreach ($products as $product) {
    $ids[] = $product->getId();
}

// helyes példa
$ids = Mage::getModel('catalog/product')->getCollection()
    ->addAttributeToFilter('sku', array('like' => 'test-%'))
    ->getAllIds();

A getAllIds metódust minden Magento kollekció tartalmazza. Ha nem az azonosítókra van szükségünk, hanem másik mezőre, de csak arra az egyre, akkor használhatjuk a következő módszert:


// rossz példa
$result = array();

$products = Mage::getModel('catalog/product')->getCollection()
    ->addAttributeToSelect('my_attribute')
    ->addAttributeToFilter('sku', array('like' => 'test-%'));

foreach ($products as $product) {
    $result[] = $product->getData('my_attribute');
}

// helyes példa
$collection = Mage::getResourceModel('catalog/product_collection')
    ->addAttributeToSelect('test')
    ->addAttributeToFilter('sku', array('like' => 'test-%'));

$select = $collection->getSelect()
    ->reset(Zend_Db_Select::COLUMNS)
    ->columns('test')
    ->group('test');

$result =  $collection->getConnection()->fetchCol($select);

Ha csak ellenőrizni szeretnénk, hogy egy érték létezik-e a táblában:


// hibás példa
$firstItem = Mage::getModel('catalog/product')->getCollection()
    ->addAttributeToFilter('hello', array('gt' => 3))
    ->getFirstItem();

$hasData = $firstItem->getId() != null;

// helyes példa
$size = Mage::getResourceModel('catalog/product_collection')
    ->addAttributeToFilter('hello', array('gt' => 3))
    ->getSize();
$hasData = $size > 0;

Ahol csak tudunk, egyszerűsítsünk

Ezek ugyan csak apróságok, de vihetnek el futásidőt azon túl, hogy a rövidebb kód számunkra is kezelhetőbb. Ha pl. a bejelentkezett felhasználónak csak az azonosítójára van szükségünk:


// kevésbé hatékony
$customerId = Mage::getSingleton('customer/session')->getCustomer()->getId();
// picit rövidebb
$customerId = Mage::getSingleton('customer/session')->getCustomerId();

Hasonlóan a kosárban levő termékek, és azok azonosítói


$quoteItems = Mage::getSingleton('checkout/cart')->getQuote()->getAllItems();

foreach ($quoteItems as $item) {
    // ha csak a termék id-ra van szükségünk
    // ez picit hosszabb
    $productId = $item->getProduct()->getId();

    // ez hatékonyabb
    $productId = $item->getProductId();


    // ha a termékre van szükségünk
    // ez kimondottan rossz megoldás
    $product = Mage::getModel('catalog/product')->load($item->getProductId());

    // ez pedig a megfelelő
    $product = $item->getProduct();
}
Összegzés

Láthattunk néhány hasznos tippet a Magento oldalunk sebességoptimalizálására, és még közel nem mutattunk be minden lehetőséget. Ne felejtsük el, hogy a látogatóink potenciális ügyfelek, és könnyen elveszíthetjük őket, ha nem találják az oldalt használhatónak.  Hiába a szép design, és az ergonómia szempontjából tökéletes elrendezés, egy lassú weboldal alaposan le tudja rombolni a kezdetben pozitív felhasználói élményt. Ma már nem szabad elválasztanunk ezt a fontos kritériumot a többi lényeges szemponttól.

 

Egyedi Magento admin gridek, formok, tabok létrehozása

Tudni szeretnéd, hogyan hozhatsz létre saját webáruházadban egy külön admin menüpontot és abban egy saját lista/form párost? Az is hasznos lenne, ha vásárlóidat egy általad adminisztrált kategória struktúrába szervezhetnéd, melyekkel később külön akciókat tudsz majd végrehajtani? A Magento webáruház keretrendszerben ezeket az igényeket tudjuk egyedi admin menüpontokkal, listákkal (grid) és form-okkal kielégíteni, melyeket az adott megvalósításhoz szabhatunk.

Ebből a cikkből megtudhatod, hogy:

  • Hogyan hozz létre új Magento admin menüpontot.
  • Egy menüponthoz hogyan valósítható meg a lista.
  • Miként lehet űrlapokat létrehozni, azon belül tetszőleges input-ot.
  • A tab-ok hogyan működnek az űrlapokon.

A megoldást két úton közelítettük meg:

  1. Az elsőben létre kell hozni egy új admin menüpontot a kategóriák listázására, ill. szerkesztésére, majd kiegészíteni a vásárló szerkesztést egy új tab-bal, amiben azokat a kategóriákat lehet megadni, melyekben ő szerepel.
  2. A másik megoldás pedig az, hogy a kategória szerkesztést kiegészítjük a felhasználók listájával, ahol magához a kategóriához lehet a vásárlókat kijelölni. A végleges verzióban a második lett megvalósítva, mert így egy helyen lehet kezelni ezeket a beállításokat.

A megvalósítás tervezett lépései:

  1. Adatbázis új elemeinek megtervezése (az adatbázis módosítások megvalósítása nem ennek a cikknek képezik a részét)
  2.  Új modul létrehozása (Customercategory)
    • Könyvtár struktúra létrehozása
    • magento customer category directory structure
    • A szükséges model-, resource model-, helper-, installer létrehozása
    • App/etc/modules/Aion_Customercategory.xml
    • Config.xml létrehozása a modul etc könyvtárába
    • Controller-ek létrehozása
    • Block-ok létrehozása
    • Layout létrehozása
    • Nyelvi file-ok létrehozása (csv)

A Magento modul létrehozása

A Magento-ban egy új modul létrehozásakor a kiválasztott pool-ban (jelen esetben a local) a namespace alá (aion) létre kell hozni a modul nevének szánt könyvtárat (Customercategory), és ezzel együtt az app/etc/modules alá pedig a [modul neve].xml-t a következő tartalommal:


<?xml version="1.0"?>
 <config>
     <modules>
         <!-- namespace_modulename -->
         <Aion_Customercategory>
             <active>true</active>
             <!-- pool -->
             <codePool>local</codePool>
         </Aion_Customercategory>
     </modules>
 </config>

A modul könyvtárstuktúrája:

  • Block – ide kerülnek be a megjelenítéshez szánt form-ok, grid-ek és hasonló osztályok
  • controllers – Ez tartalmazza a controllereket
  • etc – A használt xml file-ok helye (config.xml, adminhtml.xml, …)
  • Helper – a helper file-ok helye
  • Model – A model file-ok helye
  • sql – Az adatbázis installer/update-er file-ok helye

A modulunk etc könyvtárában lévő config.xml-ben be kell állítanunk az alapokat ahhoz, hogy a modulunk működőképes legyen:


<?xml version="1.0"?>
 <config>
     <modules>
         <Aion_Customercategory>
             <version>0.1.0</version>
         </Aion_Customercategory>
     </modules>
     <global>
         <models>
             <aion_customercategory>
                 <class>Aion_Customercategory_Model</class>
                 <resourceModel>aion_customercategory_resource</resourceModel>
             </aion_customercategory>
             <aion_customercategory_resource>
                 <class>Aion_Customercategory_Model_Resource</class>
                 <entities>
                     <category>
                         <table>aion_customercategory_category</table>
                     </category>
                     <customer>
                         <table>aion_customercategory_customer</table>
                     </customer>
                 </entities>
             </aion_customercategory_resource>
         </models>
         <blocks>
             <aion_customercategory>
                 <class>Aion_Customercategory_Block</class>
             </aion_customercategory>
         </blocks>
         <helpers>
             <aion_customercategory>
                 <class>Aion_Customercategory_Helper</class>
             </aion_customercategory>
         </helpers>
         <resources>
             <aion_customercategory_setup>
                 <setup>
                     <class>Mage_Core_Model_Resource_Setup</class>
                     <module>Aion_Customercategory</module>
                 </setup>
             </aion_customercategory_setup>
         </resources>
     </global>
 </config>

Miután az alapokkal megvagyunk, létre kell hoznunk az adminban egy menüpontot, az elemek kezelésére. Mi ezt a Customer főmenüpont alá hozzuk létre, ezért a következőket kell a config.xml-be beágyaznunk:

 </global>

     <adminhtml>
         <menu>
             <customer>
                 <children>
                     <aion_customercategory>
                         <title>Customer Categories</title>
                         <sort_order>9999</sort_order>
                         <action>adminhtml/customercategory/index</action>
                     </aion_customercategory>
                 </children>
             </customer>
         </menu>
     </adminhtml>
 </config>

Látható, hogy úgy kell az XML struktúrát megadni, hogy az adminban (<adminhtml>) szeretnénk egy menüpontot definiálni (<menu>), azon belül a customer alá (<customer>) egy almenüt (<children>), ahol megadjuk a beállításainkat:

  • title – mi legyen a menüpont neve
  • sort order – a menüpont hányadik legyen a sorban
  • action – Melyik controller melyik metódusa hivódjon meg a menüpontra való kattintáskor

Most ha megnézzük az admin felületünket, akkor a következő fogad (Nagyon fontos, hogy minden xml-ben történő módosítás után ürítenünk kell a Magento cache-t, hogy újra beolvassa):

Magento admin grid customization

Ezek után meg kell írnunk a controller-t, hogy le is kezeljük a hívást:

Létre kell hoznunk az xml-ben action-ként megadott osztály/metódus párost a controllers könyvtár alá (minden controller végződése triviálisan Controller, és a metódusok pedig Action végződést kell, hogy kapjanak). Mivel ez egy admin controller lesz, ezért a Mage_Adminhtml_Controller_Action ősosztályból kell származnia

controllers/Adminhtml/CustomercategoryController.php

class Aion_Customercategory_Adminhtml_CustomercategoryController
    extends Mage_Adminhtml_Controller_Action
 {
     public function indexAction()
     {
         die('ok');
     }
 }


Ahhoz, hogy a Magento tudja, hogy az általunk megírt controllereket is használja, a config.xml-be a következő elemet kell beírnunk:

</adminhtml>
<admin>  
    <routers> 
        <adminhtml> 
            <args>  
                <modules> 
                    <Aion_Customercategory before="Mage_Adminhtml">Aion_Customercategory_Adminhtml</Aion_Customercategory>  
                </modules>     
            </args>    
        </adminhtml> 
    </routers>
</admin>

Vagyis az általunk megadott útvonalakat a Magento-s router elött kezelje. Meg lehet adni after-rel is, ami ebben az esetben irreleváns, viszont ha egy system url-t akarunk mi magunk lekezelni, akkor a before a megfelelő property, hogy a default elött fusson le a mi controller/action párosunk (természetesen a módosítás után szintén cache-t kell ürítenünk, hogy a változásokat beolvassa a Magento). Most már lefut az általunk megírt metódus, de definiálni kell a layout-ot, hogy az milyen formában renderelődjön ki. Ezt szintén xml formátumban kell megadnunk, viszont pár dolog kell hozzá:

  • meg kell adnunk a config.xml-ben az adminhtml tag alatt, hogy melyek azok a layout.xml-ek, amiket szeretnénk használni:

...
</menu>
     <layout>
         <updates>
             <aion_customercategory>
                 <file>aion/customercategory.xml</file>
             </aion_customercategory>
         </updates>
     </layout>
 </adminhtml>
...

– Magát az indexAction-ünkben be kell tölteni a layout-tot, majd kirenderelni:

class Aion_Customercategory_Adminhtml_CustomercategoryController
    extends Mage_Adminhtml_Controller_Action
 {
     public function indexAction()
     {
         $this->loadLayout();
         $this->renderLayout();
     }
 }

  • létre kell hoznunk ezeket az app/design/adminhtml/default/default/layout könyvtár alá (vagyis a modulunk layout xml leírója a /app/design/adminhtml/default/default/layout/aion/customercategory.xml file lesz).
    
    

<?xml version="1.0"?>
 <layout version="0.1.0">
     <adminhtml_customercategory_index>
         <reference name="menu">
             <action method="setActive">
                 <menupath>customer/customercategory</menupath>
             </action>
         </reference>
         <reference name="content">
             <block
                type="aion_customercategory/adminhtml_category"
                name="category_index"
            />
         </reference>
     </adminhtml_customercategory_index>
 </layout>

A fenti példában definiáljuk az adminhtml/customercategory/index (<adminhtml_customercategory_index>) útvonal layout-ját, ahol megadjuk, hogy a kiválasztott menü a customer/customercategory, és a content-je pedig egy általunk létrehozandó adminhtml/category block lesz.

Index block létrehozása

Triviálisan, amikor a felhasználó a menüpontunkra kattint, akkor egy listát szeretne látni azokkal az elemekkel, amiket meg felvitt, illetve szeretne szerkeszteni/létrehozni/törölni elemeket. A fenti layoutban megadtuk, hogy a block-unk az adminhtml_category lesz, ezért létre kell hoznunk az app/code/local/Aion/Customercategory/Block/Adminhtml/Category.php-t, ami kezeli a layout-ban megadott content-tet:

class Aion_Customercategory_Block_Adminhtml_Category

extends Mage_Adminhtml_Block_Widget_Grid_Container
{

public function __construct()
{
$this->_blockGroup = 'aion_customercategory';
$this->_controller = 'adminhtml_category';

parent::__construct();

$this->_headerText = $this->__('Customer Categories');
$this->_addButtonLabel = $this->__('Add New');

}
}

  Látható, hogy az osztályunk a Mage_Adminhtml_Block_Widget_Grid_Container leszármazottja, mert itt egy grid-et szeretnénk majd megjeleníttetni. A konstruktorban meg kell adnunk mindenképpen a _blockGroup-ot és a _controller-t, amivel megmondjuk a magento-nak, hogy a grid block-kunkat az Aion_Customercategory_Block_Adminhtml_Category_Grid-ből kell, hogy létrehozza. Amikor az ősosztály kirendereli a layout-ot, a következő függvény fut le:

$this
->getLayout()
->createBlock(
$this->_blockGroup.'/' . $this->_controller . '_grid',
$this->_controller . '.grid'
)

Grid block

Létre kell hoznunk a fent megadott grid osztályunkat az app/code/local/Aion/Customercategory/Block/Adminhtml/Category/Grid.php alatt:

class Aion_Customercategory_Block_Adminhtml_Category_Grid
extends Mage_Adminhtml_Block_Widget_Grid
 {
public function __construct()
 {
 parent::__construct();
 }
protected function _prepareCollection()
 {
 return parent::_prepareCollection();
 }
protected function _prepareColumns()
 {
 return parent::_prepareColumns();
 }
 }

Az osztályunk a Mage_Adminhtml_Block_Widget_Grid-ből származik, viszont 3 metódust mindenképpen felül kell írnunk, hogy működni tudjon a saját modulunkban:

  • __construct – A példányosításkor bizonyos alapbeállításokat eszközölnünk kell
  • _prepareCollection – Honnan szedje a collection-t
  • _prepareColumns – Milyen oszlopok legyenek a grid-ben

Kiegészítve a mi megoldásainkkal így néz ki az osztály:

class Aion_Customercategory_Block_Adminhtml_Category_Grid extends Mage_Adminhtml_Block_Widget_Grid
 {
public function __construct()
 {
 parent::__construct();
 $this->setId('category_id');
 $this->setDefaultSort('category_id');
 $this->setDefaultDir('asc');
 $this->setSaveParametersInSession(true);
 }
protected function _prepareCollection()
 {
 $collection = Mage::getModel('aion_customercategory/category')
->getCollection();
 $this->setCollection($collection);
 return parent::_prepareCollection();
 }
protected function _prepareColumns()
 {
 $this->addColumn(
 'category_id',
 array(
 'header' => $this->__('ID'),
 'align'  => 'right',
 'width'  => '50px',
 'type'   => 'number',
 'index'  => 'category_id',
 )
 );
$this->addColumn(
 'name',
 array(
 'header' => $this->__('Name'),
 'index'  => 'name',
 )
 );
$this->addColumn(
 'active',
 array(
 'header'   => $this->__('Active'),
 'index'    => 'active',
 'type'     => 'options',
 'options'  => array(
 1 => Mage::helper('adminhtml')->__('Yes'),
 0 => Mage::helper('adminhtml')->__('No')
 ),
 )
 );
return parent::_prepareColumns();
 }
 }

Ha ezeket megvalósítottuk, akkor már az oldalon is megjelenik valami:

Magento admin grid modification

Látható, hogy már van egy grid-ünk, amit még ki kell egészíteni.

Magento Admin Form megvalósítása

Az általános tervezési/megvalósítási követelményeknek megfelelően célszerű az új létrehozása és meglévő elem módosítása form-okat egy közös osztállyal lekezelni. Ennek megfelelően a controllerben a következő módosításokat kell eszközölni:

class Aion_Customercategory_Adminhtml_CustomercategoryController
extends Mage_Adminhtml_Controller_Action
 {
...
 public function editAction()
 {
 $id    = $this->getRequest()->getParam('id');
 $model = Mage::getModel('aion_customercategory/category');
if ($id) {
 $model->load($id);
 if (!$model->getId()) {
 $this->_getSession()->addError(
 $this->__('This Category no longer exists.')
 );
 $this->_redirect('*/*/');
 return;
 }
 }
$data = $this->_getSession()->getFormData(true);
 if (!empty($data)) {
 $model->setData($data);
 }
Mage::register('current_model', $model);
$this
 ->loadLayout()
 ->renderLayout();
 }
 public function newAction()
 {
 $this->_forward('edit');
 }
...
 }

Vagyis az új létrehozásakor irányítson át a szerkesztésre, és ott van levizsgálva, hogy ha van ID paraméter, akkor betölti a szükséges adatokat. Viszont ahogy az az indexAction esetében is kellett, itt is szükség van a layout xml-ben definiálni, hogy hogyan épül fel az oldal:

<?xml version="1.0"?>
 <layout version="0.1.0">
...
<adminhtml_customercategory_edit>
 <update handle="editor"/>
 <reference name="menu">
 <action method="setActive">
 <menupath>customer/customercategory</menupath>
 </action>
 </reference>
 <reference name="content">
 <block
type="aion_customercategory/adminhtml_category_edit"
name="category_edit"
/>
 </reference>
 <reference name="left">
 <block
type="aion_customercategory/adminhtml_category_edit_tabs"
name="category_tabs"
/>
 </reference>
 </adminhtml_customercategory_edit>
...
 </layout>

A szerkesztő felületen a tartalom az a kategória szerkesztő lesz (reference name=”content”), a baloldalon pedig a tab-ok (reference name=”left”). Ahhoz, hogy valami megjelenjen az oldalon, ezt a két blockot meg kell valósítanunk. Az első block az adminhtml_category_edit, amit definiálnunk kell az app/code/local/Aion/Customercategory/Block/Adminhtml/Category/Edit.php alatt:

class Aion_Customercategory_Block_Adminhtml_Category_Edit
extends Mage_Adminhtml_Block_Widget_Form_Container
 {
 protected function _getHelper()
 {
 return Mage::helper('aion_customercategory');
 }
public function __construct()
 {
 parent::__construct();
 $this->_blockGroup = 'aion_customercategory';
 $this->_controller = 'adminhtml_category';
 $this->_mode       = 'edit';
 $this->_updateButton(
'save',
'label',
$this->_getHelper()->__('Save Category')
);
 $this->_addButton(
'saveandcontinue',
array(
 'label'   => $this->_getHelper()->__(
'Save and Continue Edit'
),
 'onclick' => 'saveAndContinueEdit()',
 'class'   => 'save',
 ), -100);
$this->_formScripts[] = "
 function saveAndContinueEdit(){
 editForm.submit($('edit_form').action+'back/edit/');
 }
 ";
 }
 }

Ez egy Mage_Adminhtml_Block_Widget_Form_Container, és magát a form-ot a _blockGroup, _controller, _mode alapján az Aion_Customercategory_Adminhtml_Category_Edit_Form osztályból tölti be. Létrehozzuk ezt az osztályt az app/code/local/Aion/Customercategory/Block/Adminhtml/Category/Edit/Form.php file-ban:

class Aion_Customercategory_Block_Adminhtml_Category_Edit_Form
extends Mage_Adminhtml_Block_Widget_Form
 {
 protected function _prepareForm()
 {
 $form = new Varien_Data_Form(array(
 'id'      => 'edit_form',
 'method'  => 'post',
 'enctype' => 'multipart/form-data',
 'action'  => $this->getUrl('*/*/save'),
 )
 );
 $form->setUseContainer(true);
 $this->setForm($form);
 return parent::_prepareForm();
 }
 }

Már van egy üres form-unk, meg kell valósítani a tab-ok kezelésére szánt osztályt. A block-nak az adminhtml_category_edit_tabs-ot adtuk meg a layout.xml-ben, ezért az osztály neve Aion_Customercategory_Block_Adminhtml_Category_Edit_Tabs kell, hogy legyen. Ebből következik, hogy a file az app/code/local/Aion/Customercategory/Block/Adminhtml/Category/Edit/Tabs.php kell, hogy legyen:

class Aion_Customercategory_Block_Adminhtml_Category_Edit_Tabs
extends Mage_Adminhtml_Block_Widget_Tabs
 {
 public function __construct()
 {
 parent::__construct();
 $this->setId('category_tabs');
 $this->setDestElementId('edit_form');
 $this->setTitle(
Mage::helper('aion_customercategory')->__('Details')
);
 }
protected function _beforeToHtml()
 {
 $this->addTab(
 'category_section',
 array(
 'label' => Mage::helper('aion_customercategory')
->__('Category'),
 'title' => Mage::helper('aion_customercategory')
->__('Category'),
 'content' => $this->getLayout()
->createBlock(
'aion_customercategory/adminhtml_category_edit_category_form'
)->toHtml(),
 )
 );
 return parent::_beforeToHtml();
 }
 }

Látható, hogy a __consturctor-nál lehet megadni azt, hogy mi az azonosítója, váltáskor melyik form-ba töltse az elemeket, mi legyen a cím a tab-ok felett. A _beforeToHtml-ben adjuk meg a tab-okat dinamikusan, vagyis amennyi addTab() található benne, annyi lesz a felsorolásban. Most létre kell hoznunk az adminhtml_category_edit_category_form block-ot, ami a Aion_Customercategory_Block_Adminhtml_Category_Edit_Category_Form osztályt jelenti, ami pedig az app/code/local/Aion/Customercategory/Block/Adminhtml/Category/Edit/Category/Form.php file-ban lesz megtalálható:

class Aion_Customercategory_Block_Adminhtml_Category_Edit_Category_Form
extends Mage_Adminhtml_Block_Widget_Form
 {
 protected function _getModel()
 {
 return Mage::registry('current_model');
 }
protected function _getHelper()
 {
 return Mage::helper('aion_customercategory');
 }
protected function _prepareForm()
 {
 $model = $this->_getModel();
 $form  = new Varien_Data_Form(array(
 'id'     => 'edit_form',
 'action' => $this->getUrl('*/*/save'),
 'method' => 'post'
 ));
$fieldset = $form->addFieldset('base_fieldset', array(
 'legend' => $this->_getHelper()->__('Category Information'),
 'class'  => 'fieldset-wide',
 ));
if ($model && $model->getId()) {
 $modelPk = $model->getResource()->getIdFieldName();
 $fieldset->addField($modelPk, 'hidden', array(
 'name' => $modelPk,
 ));
 }
$fieldset->addField('name', 'text', array(
 'name'     => 'name', 'required' => true,
 'label'    => $this->_getHelper()->__('Name'),
 'title'    => $this->_getHelper()->__('Name'),
 )
 );
$fieldset->addField('active', 'select', array(
 'name'     => 'active', 'required' => true,
 'label'    => $this->_getHelper()->__('Active'),
 'title'    => $this->_getHelper()->__('Active'),
 'options'  => array(
 '1' => Mage::helper('adminhtml')->__('Yes'),
 '0' => Mage::helper('adminhtml')->__('No'),
 ),
 )
 );
if ($model) {
 $form->setValues($model->getData());
 }
 $this->setForm($form);
return parent::_prepareForm();
 }
 }

A segéd metódusok mellett a _prepareForm() függvényben adjuk a felülethez a field-eket, amelyekre szükségünk van. Most már egy látható felületünk is van, ha megtekintjük az oldalt:

Magento admin custom form development

Ezzel megoldottuk az új létrehozása, elem módosítása felületet, viszont tudnunk kell elmenteni is a form-on felvitt adatokat. Nincs másra szükségünk, mint a controller-ben (CustomercategoryController) egy saveAction() metódust definiálni, ami ezt meg is teszi:

...
public function saveAction()
 {
 $redirectBack = $this->getRequest()->getParam('back', false);
 if ($data = $this->getRequest()->getPost()) {
 $id    = $this->getRequest()->getParam('id');
 $model = Mage::getModel('aion_customercategory/category');
 if ($id) {
 $model->load($id);
 if (!$model->getId()) {
 $this->_getSession()->addError(
 $this->__('This Category no longer exists.')
 );
 $this->_redirect('*/*/index');
 return;
 }
 }
try {
 $model->addData($data);
 $this->_getSession()->setFormData($data);
 $model->save();
 $this->_getSession()->setFormData(false);
 $this->_getSession()->addSuccess(
 $this->__('The Category has been saved.')
 );
 } catch (Mage_Core_Exception $e) {
 $this->_getSession()->addError($e->getMessage());
 $redirectBack = true;
 } catch (Exception $e) {
 $this->_getSession()->addError(
$this->__('Unable to save the Category.')
);
 $redirectBack = true;
 Mage::logException($e);
 }
if ($redirectBack) {
 $this->_redirect('*/*/edit', array('id' => $model->getId()));
 return;
 }
 }
 $this->_redirect('*/*/index');
 }
...

A mentés után már a listában is megtalálhatóak azok az elemek, amiket felvittünk:

Magento custom admin form save data

Az általános grid funkciók a magento-ból származtatott osztály miatt már így is működnek:

  • szűrés
  • sorrendezés
  • lapozás

Meg kell adnunk, hogy ha egy-egy sorra kattintunk, akkor milyen url-re dobjon az oldal. Ezt az Aion_Customercategory_Block_Adminhtml_Category_Grid osztályban kell megtennünk a következő metódus segítségével:

public function getRowUrl($row)
 {
 return $this->getUrl('*/*/edit', array('id' => $row->getId()));
 }

Ahhoz, hogy a teljes funkcionalitást megvalósítsuk, a törlésre is szükség van, amit a szerkesztő form-ról érhetünk el, és automatikusan egy megerősítő popup után átirányít a deleteAction() függvényre, vagyis a controllerben ezt is meg kell valósítanunk:

public function deleteAction()
 {
 if ($id = $this->getRequest()->getParam('id')) {
 try {
 $model = Mage::getModel('aion_customercategory/category');
 $model->load($id);
 if (!$model->getId()) {
 Mage::throwException($this->__('Unable to find a Category to delete.'));
 }
 $model->delete();
 $this->_getSession()->addSuccess(
 $this->__('The Category has been deleted.')
 );
 $this->_redirect('*/*/index');
 return;
 } catch (Mage_Core_Exception $e) {
 $this->_getSession()->addError($e->getMessage());
 } catch (Exception $e) {
 $this->_getSession()->addError(
 $this->__('An error occurred while deleting Category data. Please review log and try again.')
 );
 Mage::logException($e);
 }
 $this->_redirect('*/*/edit', array('id' => $id));
 return;
 }
 $this->_getSession()->addError(
 $this->__('Unable to find a Category to delete.')
 );
 $this->_redirect('*/*/index');
 }

Ezzel már szerkeszteni tudjuk a kategóriákat, ha módosítani kell a szerkezetet, akkor elég csak a form-ban elvenni vagy hozzáadni field-eket egyszerűen kitörölve, vagy az addField() metódust használni. Ahhoz, hogy vásárlókat tudjunk a kategóriához adni a tervezési fázisban az ajax-os tab megoldás mellett döntöttünk. Egy új tab-ot kell felvenni a Aion_Customercategory_Block_Adminhtml_Category_Edit_Tabs osztályban, ami ajaxosan tölti be a customer grid-et:

protected function _beforeToHtml()
 {
 ...
 $this->addTab('customers', array(
 'label'     => $this->__('Customers'),
 'title'     => $this->__('Customers'),
 'url'       => $this->getUrl(
'*/*/customerstab',
array('_current' => true)
),
 'class'     => 'ajax'
 ));
return parent::_beforeToHtml();
 }

Az url kulcs alatt látható, hogy a már megvalósított controller-ünk customerstabAction metódusát hívja meg, amiben elvégezzük a szükséges műveleteket:

public function customerstabAction()
 {
 $saved_customer_ids = array();
 //Your load logic
 $this
 ->loadLayout()
 ->getLayout()
 ->getBlock('category.customer.tab')
 ->setSelectedCustomers($saved_customer_ids);
$this->renderLayout();
 }

Viszont fontos, hogy mint minden admin elemnek, ennek is kell a layout.xml-ben egy leíró blokk, hogy miket tartalmazzon:

...
<adminhtml_customercategory_customerstab>
 <block type="core/text_list" name="root" output="toHtml">
 <block type="aion_customercategory/adminhtml_category_edit_customer_grid" name="category.customer.tab"/>
</block>
 </adminhtml_customercategory_customerstab>
...

Viszont fontos, hogy mint minden admin elemnek, ennek is kell a layout.xml-ben egy leíró blokk, hogy miket tartalmazzon:

...
<adminhtml_customercategory_customerstab>
 <block type="core/text_list" name="root" output="toHtml">
 <block type="aion_customercategory/adminhtml_category_edit_customer_grid" name="category.customer.tab"/>
</block>
 </adminhtml_customercategory_customerstab>
...

Létre kell hoznunk a szükséges block-ot, ami ebben a példában az adminhtml_category_edit_customer_grid -> Aion_Customercategory_Block_Adminhtml_Category_Edit_Customer_Grid -> app/code/local/Aion/Customercategory/Block/Adminhtml/Category/Edit/Customer/Grid.php Ahogy azt már az előző grid-ünknél is megtettük, a __construct(), _prepareCollection(), _prepareColumns() metódusokat meg kell adni:

class Aion_Customercategory_Block_Adminhtml_Category_Edit_Customer_Grid extends Mage_Adminhtml_Block_Widget_Grid
 {
 public function __construct()
 {
 parent::__construct();
 $this->setId('customerGrid');
 $this->setUseAjax(true);
 $this->setSaveParametersInSession(true);
 }
protected function _prepareCollection()
 {
 $collection = Mage::getResourceModel('customer/customer_collection')
 ->addNameToSelect();
$this->setCollection($collection);
 return parent::_prepareCollection();
 }
protected function _prepareColumns()
 {
 $this->addColumn('selected_customers', array(
 'header'    => $this->__('Select'),
 'type'      => 'checkbox',
 'index'     => 'entity_id',
 'align'     => 'center',
 'field_name'=> 'selected_customers[]',
 'values'    => $this->getSelectedCustomers(),
 ));
$this->addColumn('customer_name', array(
 'header'    => $this->__('Name'),
 'index'     => 'name',
 'align'     => 'left',
 ));
$this->addColumn('email', array(
 'header'    => $this->__('E-mail'),
 'index'     => 'email',
 'align'     => 'left',
 ));
return parent::_prepareColumns();
 }
 }

A constructorban ha setUseAjax(true), akkor értelemszerűen ajax-osan próbálja majd lekérni a grid-et, viszont ehhez meg kell adni még ebben az osztályban a gridUrl-t is:

public function getGridUrl()
 {
 return $this->getUrl('*/*/customersgrid', array('_current' => true));
 }
Azonban triviálisan ez egy controller/action hívás, ezért azt is meg kell valósítani a controllerben:
public function customersgridAction()
 {
 $this
 ->loadLayout()
 ->getLayout()
 ->getBlock('category.customer.tab')
 ->setSelectedCustomers(
$this->getRequest()->getPost('customers', null)
);
$this->renderLayout();
 }

Ahhoz, hogy ez az ajax-os oldal is kirenderelődjön, és ne kapjunk hibát, természetesen a layout.xml-ben meg kell adni a szükséges adatokat:

...
<adminhtml_customercategory_customersgrid>
<block type="core/text_list" name="root" output="toHtml">
<block type="aion_customercategory/adminhtml_category_edit_customer_grid" name="category.customer.tab"/>
</block>
</adminhtml_customercategory_customersgrid>
...

  Ha ezeket megvalósítottuk, akkor már láthatjuk az ajax-osan betöltött customer grid-ünket:

 

magento admin customer grid

 

A következő lépés, hogy a kiválasztott customer entitásokat el tudjuk tárolni a kategóriához, vagyis egy hidden inputba be kell az ID-kat rakni, hogy a mentéskor ezeket eltárolhassuk. Ez azért kell, mert ha csak a grid-ben kijelölt checkbox-okat vizsgálnánk, akkor a lapozáskor vagy szűréskor a már kiválasztott checkbox lehet, hogy nem jelenik meg, így nem tudnánk elküldeni a mentési folyamat részeként. Szerencsére a Magento rendelkezik megoldással erre a problémára, a tab-unkat ki kell egészíteni egy új block-kal (widget_grid_serializer), ami ezt lekezeli, és csak a legfontosabb beállításokat/módosításokat kell a kódunkban elvégezni:

...
<adminhtml_customercategory_customerstab>
<block type="core/text_list" name="root" output="toHtml">
<block type="aion_customercategory/adminhtml_category_edit_customer_grid" name="category.customer.tab"/>
<block type="adminhtml/widget_grid_serializer" name="category.customer.serializer">
<action method="initSerializerBlock">
<grid_block_name>category.customer.tab</grid_block_name>
<data_callback>getSelectedCustomerIds</data_callback>
<hidden_input_name>customer_ids</hidden_input_name>
<reload_param_name>customers</reload_param_name>
</action>
</block>
    </block>
</adminhtml_customercategory_customerstab>
...

  Látszik, hogy meghívja az initSerializerBlock() metódust, aminek a paraméterei:

  • grid_block_name – melyik grid-re vonatkozik a szerializálás
  • data_callback – milyen általunk írt metódus adja vissza a már kiválasztott azonosítókat
  • hidden_input_name – mi legyen a neve az inputnak (később a post során ezzel hivatkozhatunk rá)
  • reload_param_name – melyik az a paraméter, ami a már tárolt elemeket tartalmazza

Most meg kell valósítanunk az Aion_Customercategory_Block_Adminhtml_Category_Edit_Customer_Grid osztályban a getSelectedCustomerIds() függvényt, ami visszaadja a kategóriához már megadott azonosítókat:

public function getSelectedCustomerIds()
 {
 $returnArray = array();
 //Your getter logic
 return $returnArray;
 }

Ezzel megvalósítottuk a betöltést, most a mentési procedúrát kell kiegészíteni a kiválasztott azonosítók letárolásával. Fontos, hogy az inputban szerializálva vannak az adatok, vagyis vissza kell fejteni, hogy azt el is tudjuk tárolni. Természetesen ezt a CustomercategoryController saveAction()-ben kell megvalósítani:

public function saveAction()
 {
 $redirectBack = $this->getRequest()->getParam('back', false);
 if ($data = $this->getRequest()->getPost()) {
 ...
if ($customersIds = $this->getRequest()->getParam('customer_ids', null)) {
 $customersIds = Mage::helper('adminhtml/js')
->decodeGridSerializedInput($customersIds);
 //Your save logic
 }
if ($redirectBack) {
 $this->_redirect('*/*/edit', array('id' => $model->getId()));
 return;
 }
 }
 ...
}

Végezetül egy dolog maradt még hátra, hogy teljes értékű felületet kapjunk, az, hogy az admin felhasználó tudjon szűrni a listában azokra a felhasználókra, akik ki vannak már jelölve, illetve akik nincsenek.

magento admin customer grid filter

 

Ezt úgy lehet megoldani,hogy kiegészítjük az  Aion_Customercategory_Block_Adminhtml_Category_Edit_Customer_Grid-et egy általunk létrehozott metódussal amit megadhatunk az oszlop hozzáadásánál, hogy mi legyen a szűrés függvénye:

$this->addColumn('selected_customers', array(
 ...
'filter_condition_callback' => array($this, '_selectedCustomerFilter'),
 ));

Vagyis a selected_customers oszlopban a szűrést a _selectedCustomerFilter() valósítsa meg:

protected function _selectedCustomerFilter($collection, $column)
 {
 $filter = $this->getRequest()->getParam('filter', null);
 $filter_data = Mage::helper('adminhtml')->prepareFilterString($filter);
 if (!$filter_data || !isset($filter_data['selected_customers'])) {
 return $this;
 }
$selectedCustomers = $this->getSelectedCustomers();
 if (!$selectedCustomers || !is_array($selectedCustomers)) {
 return $this;
 }
if ($filter_data['selected_customers'] == '1') {
 $operator = 'IN';
 } else {
 $operator = 'NOT IN';
 }
 $collection->getSelect()->where('e.entity_id ' . $operator . ' (' . implode(',', $selectedCustomers) . ')');
return $this;
 }

Összegzés

Ezzel a példával könnyedén meg tudunk valósítani olyan ügyféligényeket, amikor új menüpontot, új formot, új gridet vagy dinamukus tab-okat kell létrehoznunk. Dolgozhatunk meglévő collection-ökkel vagy custom adatbázis modellekkel is. A Magento nagyon sok segítséget nyújt a megvalósítás során, rengeteg core-szinten megvalósított osztálya van, amiket csak használnunk kell, illetve kiegészíteni. Ha úgy gondolod, ez a cikk hasznos lehet másoknak is, kérjük, oszd meg. Bármilyen kérdéssel, kéréssel fordulj hozzánk bizalommal kommentben.

 

9 ok, amiért a Magento a Te tökéletes e-kereskedelmi platformod

Egy ideális szoftver lehetővé teszi, hogy ne csak az oldal megjelenésén módosíthassunk saját kívánalmainknak megfelelően, de a termékek megjelenését, a „kirakatot”, a kereséseket és a háttérfolyamatokat is részletekbe menően befolyásolhassuk. Másként elképzelhetetlen volna, hogy meg tudjon felelni a változatos igényeknek – akár egyetlen vállalkozáson belül is, hiszen ezek az igények idővel jelentősen módosulhatnak is. Nem kis szó tehát, ha egy rendszerre a legváltozatosabb területeken tevékenykedő vállalatok és online marketingesek, a KKV-któl a multinacionális mamutvállalatokig rámondják, hogy a legjobb választás.

Nos, a Magento pontosan ilyen rendszer. Legfontosabb jellemzői közé tartozik a bővíthetőség, skálázhatóság, rugalmasság. Egy olyan e-kereskedelmi platformról beszélünk, amely valóban egy keretrendszert biztosít – méghozzá egy olyat, amelyen belül a lehető legnagyobb mozgásterünk nyílik arra, hogy saját igényeinkre szabjuk. Feltéve, hogy hajlandóak vagyunk a számunkra túl nehéznek bizonyuló feladatokat képzett szakemberre bízni. Bemutatjuk, miért ideális választás ez a platform – és persze azt is elmondjuk, hogy kik azok, akiknek a legtöbb hasznot hajthatja.

„Sokan Magento-t használnak”

Igen, tudjuk, hogy ez az érvelés általában hibás következtetésekhez vezet – attól még, hogy a többség egyetért valamiben, az nem biztos, hogy helyes. Most azonban az e-kereskedelemről és üzleti eredményekről beszélünk. Tény, hogy jelenleg a 30 legnépszerűbb e-kereskedelmi platform között a Magento elképesztően magas, 29,8 százalékos részesedést mondhat a magáénak – alig akad e tekintetben értékelhető versenytársa a piacon. De nem csak a tömegek kedvelik…

tips Példa: A Magento rendszerét olyan világmárkák használják, mint a Nike, a Ford, a Samsung, a Gant vagy az Olympus. Olyan brandek ezek, amelyek nem a legolcsóbb vagy legegyszerűbb megoldásokat keresik. Ha egy platform ilyen körökben is népszerű, az garantálja, hogy egy biztonságos értékesítési rendszerről van szó, amely képes hatékonyan eladni a termékeinket online.

Globális statisztikákért kattints ide.

 

Profi technikai támogatás, hatalmas háttértudás

 

A Magento rendszert megalkotó lelkes informatikusok egy olyan rendszert hoztak létre önkéntesek segítségével, ami ténylegesen képes megoldást találni a felhasználók egyedi igényeire. Rugalmassága, nyíltsága elsősorban ennek a filozófiának köszönhető. Néhány évvel ezelőtt a céget és ezzel magát a platformot is felvásárolta az eBay.

Ez nem vált kárára a Magento-nak: megmaradt ugyanolyan nyílt platformnak, eközben azonban a nagyvállalat profijainak irdatlan tudásanyaga is fejlődését szolgálta. Nemrég a Magento függetlenedett az eBay-től, az évek során – már jóval a felvásárlás előtt – azonban kialakult körülötte egy olyan erős közösség, amely folyamatosan szenvedélyből fejleszti a platformot.

 

Az e-commerce svájci bicskája

A rendszer egy rendkívül részletes adminisztrációs felületet kínál fel, amely lehetőséget ad arra, hogy mindent a saját igényeikhez képest módosítsunk a termékkategóriáktól kezdve egészen a különféle vevőcsoportoknak megjelenített tartalmakig. A Magento nagyon sokat tud, robosztus rendszer, bár tény, hogy kezelése helyenként egyszerű, helyenként viszont igen bonyolult lehet.

Hogy példát is mondjunk: beállíthatjuk például azt, hogy egyes vevőcsoportok (mondjuk kis- és nagykereskedések) más és más árakat lássanak felületeinken annak függvényében. Ez a személyre szabhatóság a rendszer egyik legnagyobb előnye: olyan webáruházat hozhatunk létre, amely nem egyszerűen csak a vásárló elé tárja a termékeket, de aktívan képes a konverzió felé terelni.

A kedvezményrendszer kezelése is kifejezetten nagyszerű, ha megtanulod a trükkjeit, programozói segítség nélkül magad is összelegózhatod a kedvezményeket. Ha pedig speciális igényeid volnának, azokat (lévén nyílt forráskódú szoftver) lefejleszthetik rendszeredhez a szakemberek. Adottak olyan lehetőségek is, elősegítendő a rendszer kezelését, hogy a kategóriákat például fanézetben rendezzük el, kiegészítő modulok segítségével pedig még könnyebbé tehetjük a folyamatot (drag&drop műveletekkel például).

 

Gazdag termékinformációk

 

A Magento nem véletlenül olyan népszerű: a 2015-ös adatok szerint a legszélesebb körben használt e-kereskedelmi platformok körében közel 30 százalékos a részesedése. Ekkora piacot lehetetlen volna rugalmasság nélkül kiszolgálni. Abból azonban nincs hiány. A rendszerben gyakorlatilag bármilyen termékjellemzőt beállíthatsz, amilyet csak szeretnél: az adminisztrációs felületen teljesen szabadon szerkesztheted az attribútumokat, így semmi fontosat nem kell kihagynod: a rendszert a termékhez idomíthatod.

Kivételesen rugalmas a kedvezményrendszer is, megadhatod például azt, hogy ha a vásárló egy adott termékkategóriából kettőt is elhelyez a kosarában, bizonyos mértékű kedvezményt kapjon ezekre, esetleg ingyenes kiszállítást és így tovább. A Magento-ban rengeteg kombinációt állíthatsz be, óriási a szabadságod e téren.

 

Gyönyörű reszponzív dizájn

 

Természetes, hogy a Magento webáruház megjelenését olyanra szabhatjuk, amilyenre csak szeretnénk. Nem is lehetne másképpen, hiszen az egy kaptafára készült webáruházak meglehetősen kevés értéket adnának hozzá brandünk építéséhez. Az sem baj, ha nem értesz a webdizájnhoz, a Magento ugyanis több ezer testre szabható template-et kínál. Ezek telepítését viszont jobb szakemberre bízni.

A lényeg azonban nem is ez, hanem a reszponzivitás. Sok olyan rendszer található a piacon, amely „elfelejtett” alkalmazkodni a piac legújabb igényeihez. 2014 óta a legtöbb felhasználó már mobilról, illetve különféle okoseszközökről internetezik, a vásárlások tekintélyes hányada is mobileszközökön történik.

Egy webáruháznak csakis akkor van esélye egy ilyen környezetben érvényesülni, ha képes reszponzívan megjelenni, vagyis minden platformon a mobiloktól a tableteken át az asztali gépekig egy könnyen kezelhető felületet a felhasználó elé tárni.

tips Példa: A reszponzivitás a SEO-ban is előnyt biztosít: a Google algoritmusa ma már aktívan vizsgálja, hogy egy weboldal mobilbarát-e, és csak azokat szerepelteti a találati listák előkelő helyein mobileszközökről indított keresések esetében, amelyeknél ez a feltétel megvalósul. Vagyis, ha olyan webáruházat használunk, amely desktopon nagyon szépen megjelenik, de mobilon szétesik a kezelőfelülete, elbúcsúzhatunk az egyre növekvő számú felhasználótól, akik mobilon szeretnek vásárolni.

Magento eCommerce platform

 

Segíti a SEO-t

A Magento rendszere egy sor alaplehetőséget kínál arra, hogy keresőbarát oldalt építhess. Keresőbarát URL-eket, oldaltérképeket generálhatsz (például domainneved.com/terméknév módon), megadhatod a metaadatokat és így tovább. Ki kell térnünk ehelyett a webáruházon belüli keresésre is, amely a Magento rendszer egyik legerősebb jellemzője.

A felhasználók szűkítő kereséseket végezhetnek – felhasználói szempontból ez jó, SEO szempontból viszont nem. Azzal jár ugyanis, hogy a megadott keresési feltételek alapján a webáruház minden alkalommal új és új terméklistákat, oldalakat generál le – amelyeket a Google duplikált tartalomként is értékelhet. Ezen a negatívumon egyedi fejlesztésekkel lehet enyhíteni.

tips Példa: A Magento fejlesztői minden más téren úgy igyekeztek a rendszert megalkotni, hogy nem csak könnyen kereshető, de könnyen megtalálható is legyen, hogy az algoritmus szemében egy erős, keresőbarát oldal jelenjen meg. Széles körben elfogadott vélemény, hogy az e-kereskedelmi platformok közül ez biztosítja a legerősebb SEO-eszköztárat, ugyanakkor a technikai SEO továbbfejlesztése erősen javasolt – így például a Robots.txt beállítása, amely a szűkítő keresés által generált oldalakat és más e tekintetben felesleges aloldalakat (kosár, felhasználói fiók stb.) kizárhat a Google kereséséből, előnyödre.

 

A Magento biztonságos

 

Egy olyan környezetben, mikor a különféle adatbázisokat napi szinten igyekeznek feltörni az adatokra éhes hekkerek, kiemelten fontos szempont a biztonság. Szinte naponta hallhatunk olyan nagyvállalatokról, amelyek rendszereibe bejutottak, adatbázisokról, amelyeket elloptak – egy webáruháznak tehát különösen fontos szempont, hogy rendszerét ne törhessék fel akármikor.

Szerencsére a Magento rendszerét folyamatosan fejlesztők tömegei vizsgálják és tartják szemmel. Az egész rendszert folyamatosan profik fésülik át gyengeségek után kutatva (például etikus hekkerek), a sebezhetőségeket pedig szinte azonnal javítják a nyilvánosan elérhetővé tett patch-ek révén. Persze nem kell magadnak kutatnod a frissítések után.

A Magento alapesetben mindig szól, amikor valamilyen frissítés elérhetővé válik, így valóban azonnal tudomást szerzel a fejleményekről. (A frissítést viszont már érdemes fejlesztővel végeztetni, főleg ha egyedi fejlesztések is vannak a webáruházban.) A rendszer nem lehet tökéletes – egyetlen rendszer sem az, és amely mégis ezt állítja, attól kell a legjobban óvakodni. A Magento esetében azonban a közösség villámgyorsan képes felfedni a hibákat, a biztonsági frissítések telepítésével pedig ki is küszöbölhetjük azokat, mielőtt gondot okoznának.

 

Adatok!

 

Ha kicsit is otthon vagy az online marketingben, tudod azt, hogy mindennek az alapja az adat. Ha bármilyen weboldalt üzemeltetsz, és ebből pénzt is remélsz, adatbázisokat kell építened és következtetéseket levonnod azok alapján. Tudnod kell, hányan látogatnak, hogyan találnak meg, mennyi időt töltenek az oldaladon és azon belül hol, és így tovább.

Rendkívül sok olyan tényező van, amit szemmel kell tartanod, hogy oldaladat folyamatosan a felhasználói szokásoknak és preferenciáknak megfelelően tudd optimalizálni. A Magento lehetővé teszi azt, hogy a legpraktikusabb adatgyűjtő rendszert, a Google Universal Analytics-et integráld oldaladba. Ami még ennél is jobb megoldás, a kifejezetten e-kereskedelmi alkalmazásokra kifejlesztett Enhanced Ecommerce – az Analytics e kiegészítéséhez ugyan fejlesztés szükséges, azonban sokkal részletesebb adatokkal lát el.

Így rengeteg információt gyűjthetsz össze vásárlóidról, hogy mit kedvelnek, hogyan cselekednek. Persze magát a rendszert is figyelned, felügyelned kell. Tudnod kell, hogyan teljesít az oldalad, hogyan működik, mi okozza az esetleges hibákat. A Magento support eszközei segítségével átfogó jelentéseket kaphatsz kézhez, amelyekből a profik könnyedén ki tudják deríteni az esetleges gond okát. Ha lehetőséged van rá, tanácsos a fejlesztő cégedtől automata tesztszolgáltatást kérni, ami egy egészen új szintre emelheti a hibaelhárítást.

 

Teljes e-kereskedelmi eszköztár

  • Bevásárlókosár: a Magento a teljes vásárlási folyamaton képes gond nélkül végigvezetni a vásárlókat. Használható regisztrált felhasználóként és vendégként is, és természetesen többféle fizetési lehetőséget kínál fel.
  • Felhasználói fiók: a felhasználók azonnal hozzáférhetnek vásárlási előzményeikhez, láthatják, hogyan állnak leadott rendeléseik, elmenthetnek olyan termékeket, amelyeket később akarnak megvásárolni. Emellett információkat is tárolhatnak a rendszerben, hogy a későbbi fizetések még gyorsabban menjenek, a korábbi szállítási és számlázási címeket például a regisztrált felhasználók pár kattintással kiválaszthatják, amikor újból rendelnek.
  • Menedzsment: az adminisztrációs felületen kezelhetjük a tranzakciókat, megindíthatjuk és teljesíthetjük a szállítást, panaszokat kezelhetünk kényelmesen. Toplistát kapsz például arról, hogy az emberek milyen termékeket keresnek a gyorskeresőbe gépelve (ez esetben a beírt konkrét kifejezések listáját kapod), hogy melyek a legkelendőbb termékek, vagy éppen arról, hogy melyik felhasználó milyen terméket tett a kosarába anélkül, hogy megrendelte volna.

 

Magento admin panel

 

  • Termékkezelés: egyszerre akár több ezer terméket importálhatunk, exportálhatunk és módosíthatunk, képeket tölthetünk fel, egyedi árazási feltételeket szabhatunk, megadhatjuk, mi hogyan jelenjen meg a „kirakatban”.
  • Marketing: promóciókat futtathatunk, egyedi ajánlatokat hozva létre, ingyenes szállítást kínálva vagy hasonló akciókat adva a vásárlóknak. Upsell és cross-sell lehetőségeink is vannak, termékvéleményeket és összehasonlításokat jeleníthetünk meg, vagy éppen a mostanában megtekintett termékek listáját, és lehetőséget adhatunk arra is, hogy a termékeket a felhasználók könnyen és gyorsan megosszák egymással, akár a közösségi oldalakon keresztül.
  • Több weboldal: a Magento egyszerre több, szinte korlátlan számú webáruház kezelésére képes. Egyetlen felhasználói fiókkal egyszerre több iterációt futtathatunk, így rendkívüli módon leegyszerűsítve ezek kezelését. Mit jelent ez pontosan? Ha például van egy központi webáruházad egy tucatnyi márkával, mellette „konkurenseket” futtathatsz – egy-egy márka dedikált, a központitól független webáruházát más domain alatt, ahol beállíthatod, hogy más árak, kedvezmények jelenjenek meg és így tovább. Mindezt egyetlen felületről kezelve.

 

Milyen Magento verziókból válogathatsz?

 

A Magento rendszernek jelenleg két verziója érhető el: a Community és Enterprise kiadások. A Comminity Edition a modern online platformok két igen fontos jellemzőjével bír: ingyenes és nyílt forráskódú. Esetében ha nagyobb webáruházat akarunk üzemeltetni, már érdemes sebességoptimalizálást is használni.

 

Magento enterprise edition

 

Technikai támogatás a CE-nél nem áll rendelkezésedre, a közösségre ugyanakkor biztosan számíthatsz. A Magento rendszerével számtalan fórumon rengeteg kezdő és szakértő foglalkozik. Ha egy komolyabb, nagyvállalati webáruházban gondolkodsz, akkor az Enterprise Edition-ben lelheted meg a megoldást.

Olyan rendszer ez, amely hatékonyan képes kezelni hatalmas weboldalakat is, különféle technikákkal oldva meg azt, hogy a felhasználók mindig pozitív élménnyel látogassák – az oldal komplexitása és méretei dacára a Magento képes egy gyorsan, zökkenőmentesen működő rendszert elénk tárni.

A gyorsaság egyébként mindkét kiadás nagy előnye – a CE esetében arra is lehetőség van, hogy egyedi fejlesztésekkel javíts ezen, így javítva a felhasználó élményt. Lehetőségeid még ennél is számosabbak. Rengeteg third-party kiegészítő modul és szolgáltatás közül választhatsz (melyek közül sok ingyenesen elérhető), hogy így bővítsd rendszered lehetőségeit.

 

Összegezzük a Magento CMS előnyeit:

A Magento nem olyan rendszer, amelyet a Te igényeidre szabtak. Olyan, amelyet Te magad alakíthatsz, hogy számodra tökéletes legyen. Nagyon sokrétű funkcionalitást kínál, ami ma létfontosságú az e-kereskedelemben. Egy végtelenül rugalmas keretrendszer, amelyen belül szinte bármit megtehetsz, hogy kihozd a maximumot online üzletedből. Éppen ezért érdemes kipróbálnod.

Ha egyszer elkezded használni, magadtól is gyorsan rájössz majd, hogy soha többé nem kell majd a neked éppen megfelelő megoldások után kutatnod, mert akkora szabadsághoz és annyi lehetőséghez jutsz, amilyet és amennyit hiába is keresnél bármilyen más e-kereskedelmi rendszerben. Persze ehhez azért meg kell fizetned a fejlesztőket is.

Egy olyan vállalkozás, amelynek még csak nagy vonalakban vannak elképzelései saját jövőjéről, amely még azt sem tudja pontosan, hogy mit árulna a neten, jobb választás lehet egy másik, ingyenes platform, például a WooCommerce. A Magento esetében meg kell értenünk azt, hogy akármilyen remek rendszer is, azért tőkeigényes vállalkozás belekezdeni, költségekkel jár, amelyek csak akkor térülnek meg, ha képesek vagyunk komoly e-kereskedelmi tevékenységet folytatni.

Olyan cégeknek javasoljuk a Magentot, akiknek már világos az irány, hogy mit és hogyan értékesítenek. Van például offline boltjuk vagy boltjaik, nem pedig éppen induló vállalkozások, amelyeknél még az sem biztos, hogy lesz-e vevő a termékre. Egy webáruház sikerességét meghatározza, hogy milyen felhasználói élményt biztosít a látogatóinak.

Ezt az élményt az váltja ki, ahogyan a felhasználó tevékenységére a rendszer válaszol, legnagyobb hatással azonban úgy lehetünk rá, hogy az oldal használatát optimalizáljuk, perszonalizáljuk. Minél személyesebb az ajánlat, kényelmesebb a vásárlásig vezető út, annál jobb véleménnyel távozik a vásárló. A Magento esetében sincs ez másképp, hacsak nem annyiban, hogy gyakorlatilag minden más rendszernél több tered nyílik az ilyen optimalizálásra a funkciók, bővítmények és egyedi fejlesztések révén.

 

De mire is kell figyelned?

 

Adunk néhány tippet, mely pontokon meghatározó a felhasználó élményszerzése. Nem csak tippelgetünk – ezt a listát a Forbes állította össze e-kereskedelmi veteránok segítségével.

 

  • Mi az első benyomása a felhasználónak, amikor az oldaladra érkezik?
  • Mit lát a felhasználó, amikor a keresőmezőbe kezd gépelni?
  • Milyen e-mailt kap a felhasználó, amikor regisztrál, amikor átállítja jelszavát, feliratkozik vagy rendel?
  • Hogyan köszönöd meg a felhasználónak, amikor regisztrál, vásárol, feliratkozik?
  • Mi történik, ha a felhasználó egy olyan termék oldalára érkezik, amely éppen nem rendelhető?
  • Mi történik, ha olyan termékre keres rá, amely nem létezik?
  • Mit lát a felhasználó, ha valótlan e-mail címet ad meg a regisztrációnál?
  • Mennyi információt kell megadnia, hogy lezárja a vásárlást?
  • Hogyan nyeri el áruházad a vásárlók bizalmát?
  • Hogyan érzékelteted, hogy képes vagy időben teljesíteni a megrendeléseket?

 

Ha elkezded használni a Magentot, egyik első dolgod legyen, hogy alaposan átgondolod ezt a listát. A rendelkezésedre álló lehetőségek biztosan elégségesek, hogy garantáld: nem kellemetlen élményekkel gazdagodnak majd látogatóid, vásárlóid.

… 3, 2, 1, Indulás!

Büszkén jelentjük be, hogy az AionHill új küldetésre indult. A stratégiai irány meghatározása, a komoly kiképzőmunka és a csapatbővítések után készen állunk rá, hogy összevont erőkkel szálljunk szembe a kihívásokkal.

Célunk egészen tiszta: a lehető legjobbat nyújtani ügyfeleinknek. Elszántak vagyunk. Évek kemény munkája után eljutottunk arra a szintre, hogy büszkén állíthassuk:

a Magento-ban nem ismerünk lehetetlent!

 

Hadseregünk magját elit Magento fejlesztőcsapatunk alkotja. Nem dolgozunk zsoldosokkal, nem adjuk ki a munkát, mindent a saját fedélzetünkön oldunk meg. Így a leghatékonyabb és legbiztonságosabb. Nemcsak nekünk, hanem ügyfeleinknek is.

Szolgáltatások A Magento projektek sikerének érdekében teljes körű szolgáltatást nyújtunk. A hosztingmegoldásoktól a kódauditon keresztül az oldalbetöltési idő optimalizálásig mindent lefedünk, ami a kifogástalan webshopfejlesztéshez és -üzemeltetéshez szükséges.

Mentőalakulatunk a válságba jutott projekteket karolja fel és vezeti győzelemre. Senkit sem hagyunk hátra. Támogatási szolgáltatásainkkal e-kereskedő partnereink mindig bízhatnak benne, hogyha segélyhívást indítanak, gyorsan elhárítjuk majd az akadályokat.

Szemünket mindig a terepen tartjuk. Figyeljük az e-kereskedelmi trendeket és fejlesztéseket, és mivel minden mindig mozgásban van, mi sem állunk le. Alkalmazkodunk, tanulunk, sőt, úttörő megoldásokat is kidolgozunk.

Informálunk és tanácsot adunk. E-kereskedelmi blogunkban folyamatosan olyan témákról írunk majd, amelyek hasznos tudnivalókat, tippeket adnak a Magento fejlesztői és üzemeltetői közösségnek. Publikálni fogunk konverziónövelési lehetőségekről, Magento fejlesztési praktikákról, online marketingről, webáruház tervezésről, felhasználói élményről, e-kereskedelmi újdonságokról és még sok minden másról.

Igaz, hogy egy olyan küldetést vállaltunk, amelynek jövőjét pontosan nem ismerjük. Azt viszont tisztán látjuk, hogy jó irányba indultunk el.