Naš redesign proces (Custom WordPress)
Za potrebe našeg tima trebao nam je novi website kao landing page za naše web development usluge, blog funkcionalnost i LMS (learning menagment system) za naše kurseve. Naravno, najbolji alat za ovaj projekat je bio WordPress.
Kada se kaže “WordPress sa online kursem”, mnogi odmah pomisle na neku generičnu temu i gotov LMS plugin. Naš je pristup drugačiji: klasični WordPress sajt (stranice, meni, custom tema) proširen je custom pluginom koji dodaje kompletan “academy” sloj: kurs, lekcije, progres, zaključavanje lekcija i prikaz dashboarda, dok je login riješen preko provjerenog social login plugin-a.
Ovaj pristup daje dvije velike prednosti:
- Sajt ostaje “standardan WordPress” (teme, stranice, editor, SEO), a kurs logika je izolovana u pluginu.
- Academy dio se može razvijati i mijenjati bez mijenjanja teme, i bez vezivanja za teške LMS ekosisteme.
U nastavku je objašnjeno kako su povezani tema, stranice i plugin, i kako teče korisnički flow.
Arhitektura: tema radi “marketing”, plugin radi “academy”
1) Custom tema (ili prilagođena tema)
Tema služi za:
- javne stranice: Home, About, Services, Blog…
- UI/branding: header, footer, tipografija, globalni stil
- “landing” stranicu kursa (
/kurs/) koja je obična WP page i uređuje se kroz Block Editor
Tema uređuje design i layout cijele web stranice da i sve bilo konzistentno. Tema ne mora znati ništa o “lekcijama”, progresu ili zaključavanju kursa. To sve radi plugin.
2) Custom plugin: “SynergyAcademy”
Plugin implementira:
- Custom Post Types (Course i Lesson)
- relaciju lekcija → kurs (preko meta polja)
- rute za “academy” sekciju (npr.
/academy/<kurs>/i/academy/<kurs>/lesson/<lekcija>/) - server-side render dashboarda i lekcija (koristi theme header/footer, ali “content” generiše plugin)
- progres (mark complete, % napretka)
- sekvencijalno otključavanje lekcija
Ovo je klasičan pattern: tema je prezentacija sajta i uređivanje bloga, plugin je aplikaciona logika kursa.
Tema je “javni sloj” sajta: sve što korisnik vidi prije logina (home, navigacija, sadržajne stranice, landing za kurs), i okvir (header/footer) koji se koristi i kada plugin renderuje Academy dashboard/lekcije. WordPress to radi kroz template hijerarhiju: zavisno od tipa zahtjeva (page, post, archive…), WordPress bira najkonkretniji template fajl i fallbackuje do index.php.
Struktura teme (šta gdje živi)
U klasičnoj (PHP) temi, najbitniji fajlovi su:
style.css(deklaracija teme + osnovni CSS)functions.php(setup + registracija menija + enqueue CSS/JS)header.phpifooter.php(globalni layout; bitno je da imajuwp_head()iwp_footer()da bi pluginovi i tema mogli ubacivati skripte/stilove).- Template fajlovi (
front-page.php,page.php,single.php,archive.php,404.php…) koje WordPress bira preko template hijerarhije.
Ako je tema block-theme (Full Site Editing), onda umjesto header.php/footer.php često ima theme.json + templates/*.html + parts/*.html, gdje theme.json definiše globalne stilove, tipografiju, spacing, palete, i “template parts”.
Kako tema služi landing stranici /kurs/
Naša/kurs/ stranica je običan WordPress Page, pa je tema tu zadužena za:
- layout i grid (širine, spacing)
- tipografiju, boje, dugmad
- render glavnog sadržaja (poziv
the_content()upage.php) - prikaz Nextend shortcode-a (Google login dugme), koji se renderuje unutar sadržaja stranice.
Praktično: mi u editoru slažemo sekcije (hero, benefiti, FAQ…), a tema osigurava dosljedan dizajn kroz globalne stilove i CSS klase.
Kako tema “oblači” Academy plugin
Iako Academy dashboard i lekcije generiše plugin, naš plugin ih ubacuje između get_header() i get_footer() (što znači: tema i dalje daje okvir, meni, fontove, globalne skripte). To je dobar pattern jer Academy dio izgleda kao dio istog sajta, a ne kao “druga aplikacija”. template_redirect se koristi da se zahtjev presretne prije nego WordPress pokuša standardni template, a onda plugin sam renderuje sadržaj ali koristi teme header/footer.
Stilovi: podjela odgovornosti (theme CSS vs plugin CSS)
Tipično imamo dva sloja CSS-a:
- Theme CSS: globalni (body font, colors, header, footer, button sistem, spacing utiliti klase) i sve za marketing stranice.
- Plugin CSS: namespace-ovan (npr.
.sa ...) i pokriva isključivo Academy UI (kartice, progress bar, lista lekcija, QA sekcija).
Ovaj pristup minimizira konflikte: tema može mijenjati dizajn sajta, a Academy ostaje stabilan jer koristi svoje prefiksirane klase.
Primjer (ilustracija, ne produkcija):
css/* theme */
.btn { border-radius: 12px; }
/* plugin */
.sa .sa-btn { border-radius: 10px; }
Navigacija i UX: meni “Kurs” mijenja ponašanje po stanju logina
U temi je meni “Kurs” normalno linkovan na /kurs/ (WP Page). Logika “ako je user ulogovan, ne ostaj na /kurs/ nego idi na academy dashboard” nije u temi nego u pluginu, jer je to aplikaciono pravilo. Ovaj redirect se najstabilnije radi u template_redirect (server-side), prije outputa.
To daje čist UX:
- guest klikne “Kurs” → vidi landing + Google login
- logged-in klikne “Kurs” → odmah je na dashboardu kursa (outline + lekcije)
URL struktura i routing: “virtual pages” unutar WordPressa
Academy dio izgleda kao posebna aplikacija unutar WP-a, ali tehnički se i dalje izvršava kroz WordPress request lifecycle.
Tipični URL-ovi:
/kurs/– landing page (WP Page)/academy/<course-slug>/– dashboard kursa (outline + lista lekcija)/academy/<course-slug>/lesson/<lesson-slug>/– prikaz lekcije
Da bi WordPress razumio ove URL-ove, plugin registruje rewrite pravila i query varove i presreće zahtjev prije nego što tema pokuša render standardni page template.
U blog postu je dovoljno znati:
- WordPress dobije URL
- plugin “prepozna” da je to academy ruta
- plugin umjesto standardne WP stranice renderuje svoj view (ali i dalje koristi header/footer iz teme)
Content model: Course i Lesson kao custom post types
Kurs (Course)
Kurs je jedan “glavni” entitet. On ima:
- naslov (ime kursa)
- thumbnail/cover (slika kursa)
- excerpt ili content (kratki opis i/ili outline)
Lekcija (Lesson)
Lekcije su zasebni postovi koji imaju:
- naslov i sadržaj
- meta polje koje kaže kojem kursu pripada (
_sa_course_id) - meta polje za redoslijed (
_sa_order) - opcionalno meta polja poput “procijenjeno vrijeme” ili “YouTube link”
Ovaj model je fleksibilan:
- lekcije se uređuju kao WP postovi
- može se dodavati više kurseva ili mijenjati redoslijed bez promjene koda
Progres: kako se pamti “mark as complete”
Progres se čuva per-user, najčešće u usermeta tabeli:
- ključ tipa
sa_progress_<course_id> - vrijednost je lista ID-eva lekcija koje su završene (npr. JSON array)
Kada korisnik klikne “Završi lekciju”:
- browser pošalje POST na custom action endpoint (npr.
/academy/action/complete/) - plugin validira nonce (sigurnost)
- upiše lesson_id u user meta
- odluči gdje da redirecta:
- ako postoji sljedeća unlocked lekcija → ide tamo
- ako je zadnja lekcija → vraća na dashboard/outline
Ovo je važan UX detalj: na zadnjoj lekciji “complete” treba vratiti na outline, ne na istu lekciju.
Primjer pseudo-koda (ilustracija):
phpif (has_next_lesson()) {
redirect(next_lesson_url);
} else {
redirect(course_dashboard_url);
}
Zaključavanje lekcija: sekvencijalni unlock
Sistem je “sequential”:
- prva lekcija je uvijek dostupna
- svaka naredna se otključava tek kada je prethodna završena
Logika se zasniva na _sa_order i listi completed lekcija:
- pronađe se “prethodna” lekcija
- ako je prethodna u completed listi → current je unlocked
Ovaj pristup je jednostavan i robustan, i može se kasnije proširiti (drip, datumi, kvizovi, uslovi itd.).
Login: zašto je Google login prebačen na Nextend
Prvobitno se razmatralo da plugin ima vlastiti Google OAuth flow, ali se u praksi pokazalo da:
- custom OAuth endpointi u WordPressu često upadnu u konflikte sa rewrite pravilima, redoslijedom ruta, i cachingom
- na shared hostingu i uz caching (LiteSpeed) OAuth callback i redirecti znaju praviti “čudna ponašanja”
Zato je praktičnije i stabilnije koristiti provjeren plugin:
- Nextend Social Login odradi OAuth proces sa Google-om
- plugin automatski kreira WP user nalog pri prvom login-u (ako se uključi membership u Nextend-u)
- login proces radi i za guest korisnike bez custom ruta
Ključni detalj:
- Nextend shortcode se prikazuje samo korisnicima koji nisu ulogovani (zato se u adminu ili kad si ulogovan dugme ne vidi).
Flow korisnika: “Guest ide na /kurs/, logged-in ide na /academy/”
Ovo je najvažniji dio UX-a:
1) Guest korisnik
- klikne “Kurs” u meniju → ide na
/kurs/ - vidi Google login dugme
- nakon logina treba da završi na dashboardu kursa
2) Ulogovan korisnik
- klikne “Kurs” u meniju → ne smije ostati na
/kurs/ - automatski se preusmjerava na
/academy/<course>/
Ovaj redirect je najstabilnije raditi u template_redirect (server-side, prije outputa), a ne u shortcode-u.
Primjer pseudo logike:
phpif (is_page('kurs') && is_user_logged_in()) {
redirect(academy_dashboard_url);
}
Cache i “nsl_bypass_cache” parametar
Kod social login-a često postoji problem: cache može servirati “guest” verziju stranice i nakon što se user uloguje.
Zato Nextend ponekad dodaje parametar poput nsl_bypass_cache=... kako bi URL bio “unikatan” i zaobišao keširani HTML.
To je normalno i uglavnom nije greška, samo mehanizam da se login stanje pravilno reflektuje na frontendu.
Admin bar i wp-admin: “student” korisnici ne trebaju WordPress backend
Za kurs korisnike je obično cilj:
- da nikad ne vide WordPress admin bar
- da nemaju pristup wp-admin
To se rješava na nivou plugina ili malog snippet-a:
- sakrije se admin bar za sve osim admina
- blokira se wp-admin za non-admin
Primjer (ilustracija):
phpif (!is_admin_user()) {
hide_admin_bar();
block_wp_admin();
}
Zašto je ova kombinacija dobra
Ova implementacija je “lakša” od LMS-a, a mnogo prilagodljivija od klasičnih membership rješenja:
- WordPress stranice i tema = marketing dio sajta
- custom plugin = academy aplikacija (kurs, lekcije, progres)
- Nextend = pouzdan Google login bez custom OAuth komplikacija
Ako se kasnije poželi:
- više kurseva, više “academy” sekcija
- napredniji Q&A, drip content, testovi
- integracija plaćanja ili membership
… plugin se može proširivati postepeno, bez rušenja ostatka sajta.
