Z góry uprzedzam, że poradnik nie jest w języku łopatologicznym. Osoby nie znające PHP (strukturalnie i choć trochę obiektowo) przed przeczytaniem poradnika zapraszam do księgarni po jakąś książkę celem edukacji wstępnej
Pluginy w MyBB potrafią rządzić danymi latającymi na drodze forum-użytkownik w tę i z powrotem za pomocą hooków. Hook (ang. hak) jak sama nazwa wskazuje pozwala nam "zahaczyć" się w jakimś miejscu forum, zrobić małe fiki-miki biegającym wokół tego miejsca danym, i wypuścić je w dalszą drogę.
Pluginem jest plik *.php o odpowiedniej strukturze. Postaram się ją nieco omówić.
Nazwa - nazwa pliku z pluginem nie może być przypadkowa. Swojemu pluginowi musimy wymyślić nazwę "surową", a więc bez kalafiorów w postaci spacji, kropek itp.; spełniającą kryteria nazywania funkcji w PHP - na przykład "uczesie". Taki plugin zapiszemy w pliku "uczesie.php". Nazwą "uczesie" będziemy też zaczynać wszystkie funkcje plugina. Oczywiście, dystrybuować plugin możemy pod nazwą bardziej marketingowo poprawną, np. "Uczę się 1.1 XP Beta"
Pierwsze, co plugin powinien robić, to sprawdzić, czy nie został brutalnie wyciągnięty za fraki z reszty mechanizmu. Sprawdzamy więc, czy stała, która jest definiowana gdzieś w plikach jądra forum, jest zdefiniowana - niech to będą pierwsze linijki plugina.
Plugin musi umieć się przedstawić użytkownikowi w Panelu Admina. Będzie to robił za pomocą funkcji nazwaplugina_info(). Funkcja zawsze ma zwracać tablicę asocjacyjną o takiej samej strukturze:
Nasz plik musi też zawierać funkcje, które będą wywoływane w momencie aktywacji i dezaktywacji. Przydaje się to, jeśli plugin tworzy sobie jakieś dodatkowe tabelki albo kolumny w bazie danych - dzięki temu sam może sobie uwić gniazdko, a później po sobie posprzątać. Póki co - niech te funkcje u nas będą puste.
Przechodzimy do sedna sprawy. W tym momencie musimy już wiedzieć, co nasz plugin ma robić. W przykładzie zajmiemy się najpierw doklejaniem jakiejś frazy do każdego wysyłanego posta, a później zmodyfikujemy kod i będziemy ją doklejać do co drugiego posta użytkownika.
Skoro mamy wprowadzać zmiany w wysyłanym poście, odszukajmy hook, którym zahaczymy się w miejscu, gdzie nowy post jest dodawany do bazy. W tym celu przyda się troszkę intuicji i umiejętności czytania cudzego kodu.
Wszystko, co jest dodawane do bazy w MyBB, jest najpierw filtrowane przez klasę DataHandler i jej rozszerzenia. Postami zajmuje się klasa
umieszczona w pliku inc/datahandlers/post.php. Otwórzmy go.
Używając wbudowanej w swój edytor kodu wyszukiwarki, znajdźmy miejsca, w których są jakieś miejsca na hooki. Po prostu wyszukajmy wywołania metod run_hooks i run_hooks_by_ref. W okolicach 654 linijki znajdziemy ciąg znaków
Po nazwie hooka (datahandler_post_insert_post) możemy wywnioskować, że jest on wywoływany w momencie dodawania posta do bazy. To chyba to, czego szukaliśmy!
W tym momencie warto wspomnieć o dwóch sposobach wywoływania hooków. Jeden, to run_hooks() - uruchamia funkcje pluginów tutaj zaczepionych bez przekazywania im żadnych argumentów. Drugi to run_hooks_by_ref(), przekazujący wybraną zmienną jako argument do funkcji obsługującej hooka. W naszym przykładzie przekazywane jest $this, czyli obiekt klasy PostDataHandler.
Dodajemy hooka do naszego pluginu. Po pierwsze, tworzymy funkcję nazwaplugina_nazwa_hooka(), pamiętając o tym, że dostajemy coś w argumencie.
Następnie rejestrujemy hook. Odbywa się to przez wywołanie metody add_hook(string nazwaHooka, string nazwaFunkcjiKtoraGoObsluguje) z obiektu $plugins.
Dodajemy więc linijkę
Mając przekazany obiekt klasy PostDataHandler, możemy z nim zrobić co się nam żywnie podoba, na przykład dopisać coś do niesionej przezeń wiadomości; ta jest przechowywana pod indeksem 'message' tablicy asocjacyjnej post_insert_data będącej polem klasy, jaką stanowi przekazany w argumencie obiekt:
Jak widać, możemy tu stosować MyCode - wiadomości są z niego parsowane w momencie wyświetlania, a nie zapisu. Funkcja przetwarzająca hook nie musi nic zwracać.
W czasie tworzenia pluginów warto posługiwać się funkcjami PHP takimi jak var_dump() czy print_r() w celu wyśledzenia sposobu zapisu danych i otwarcia sobie drogi do manipulacji nimi.
Warto pamiętać, że hook datahandler_post_insert_post jest wywoływany tylko w momencie odpowiedzi na temat; gdy wysyłany post jest pierwszym w temacie, wywołuje się datahandler_post_insert_thread_post.
Nie jesteśmy jednak ograniczeni do operowania na przekazywanych nam argumentach. Możemy bowiem wyciągnąć dla siebie zmienne, które w okolicy naszego hooka biegają, za pomocą słówka global. Mamy też możliwość wykorzystywania funkcji wbudowanych w MyBB. Dzięki temu możemy na przykład uzależnić to, czy dopiszemy coś do posta, czy nie, od liczby postów użytkownika. W tym celu zglobalizujemy sobie zmienną $post zaobserwowaną gdzieś przy 643 linijce pliku inc/datahandlers/post.php
Pobierzemy z niej ID piszącego (co prawda moglibyśmy je pobrać z przekazanego nam argumentu, ale dla edukacji udajmy, że o tym nie wiemy), a następnie na podstawie ID zapoznamy się z informacjami na temat użytkownika.
Na koniec przypomnę, że pliki z polskimi ogonkami w MyBB należy zapisywać w kodowaniu UTF-8 bez BOM, co umożliwia na przykład edytor Notepad++.
W załączniku plik uczesie.php, który powstał w poradniku
1 Czym są hooki?
Pluginy w MyBB potrafią rządzić danymi latającymi na drodze forum-użytkownik w tę i z powrotem za pomocą hooków. Hook (ang. hak) jak sama nazwa wskazuje pozwala nam "zahaczyć" się w jakimś miejscu forum, zrobić małe fiki-miki biegającym wokół tego miejsca danym, i wypuścić je w dalszą drogę.
2 Nazywanie pluginów
Pluginem jest plik *.php o odpowiedniej strukturze. Postaram się ją nieco omówić.
Nazwa - nazwa pliku z pluginem nie może być przypadkowa. Swojemu pluginowi musimy wymyślić nazwę "surową", a więc bez kalafiorów w postaci spacji, kropek itp.; spełniającą kryteria nazywania funkcji w PHP - na przykład "uczesie". Taki plugin zapiszemy w pliku "uczesie.php". Nazwą "uczesie" będziemy też zaczynać wszystkie funkcje plugina. Oczywiście, dystrybuować plugin możemy pod nazwą bardziej marketingowo poprawną, np. "Uczę się 1.1 XP Beta"
3 Bezpieczeństwo
Pierwsze, co plugin powinien robić, to sprawdzić, czy nie został brutalnie wyciągnięty za fraki z reszty mechanizmu. Sprawdzamy więc, czy stała, która jest definiowana gdzieś w plikach jądra forum, jest zdefiniowana - niech to będą pierwsze linijki plugina.
if(!defined("IN_MYBB"))
{
die("Direct initialization of this file is not allowed.<br /><br />Please make sure IN_MYBB is defined.");
}
4 "Kim ja jestem?" - Opis wtyczki
Plugin musi umieć się przedstawić użytkownikowi w Panelu Admina. Będzie to robił za pomocą funkcji nazwaplugina_info(). Funkcja zawsze ma zwracać tablicę asocjacyjną o takiej samej strukturze:
function uczesie_info()
{
return array(
"name" => "Uczę się",
"description" => "Miejsce na opis plugina. Ja się uczę, więc wiele pisał nie będę.
Ale warto wiedzieć, że <b>można tu używać HTMLa</b>!",
"website" => "http://adres.strony.plugna.com/moze-pozostac-pusty",
"author" => "twój nick",
"authorsite" => "http://adres.twojej.strony.domowej.com/moze-pozostac-pusty",
"version" => "wersja 1.2",
);
}
5 Aktywacja i dezaktywacja wtyczki
Nasz plik musi też zawierać funkcje, które będą wywoływane w momencie aktywacji i dezaktywacji. Przydaje się to, jeśli plugin tworzy sobie jakieś dodatkowe tabelki albo kolumny w bazie danych - dzięki temu sam może sobie uwić gniazdko, a później po sobie posprzątać. Póki co - niech te funkcje u nas będą puste.
function uczesie_activate()
{
}
function uczesie_deactivate()
{
}
6 Hooki
Przechodzimy do sedna sprawy. W tym momencie musimy już wiedzieć, co nasz plugin ma robić. W przykładzie zajmiemy się najpierw doklejaniem jakiejś frazy do każdego wysyłanego posta, a później zmodyfikujemy kod i będziemy ją doklejać do co drugiego posta użytkownika.
Skoro mamy wprowadzać zmiany w wysyłanym poście, odszukajmy hook, którym zahaczymy się w miejscu, gdzie nowy post jest dodawany do bazy. W tym celu przyda się troszkę intuicji i umiejętności czytania cudzego kodu.
Wszystko, co jest dodawane do bazy w MyBB, jest najpierw filtrowane przez klasę DataHandler i jej rozszerzenia. Postami zajmuje się klasa
class PostDataHandler extends DataHandler
Używając wbudowanej w swój edytor kodu wyszukiwarki, znajdźmy miejsca, w których są jakieś miejsca na hooki. Po prostu wyszukajmy wywołania metod run_hooks i run_hooks_by_ref. W okolicach 654 linijki znajdziemy ciąg znaków
$plugins->run_hooks_by_ref("datahandler_post_insert_post", $this);
Po nazwie hooka (datahandler_post_insert_post) możemy wywnioskować, że jest on wywoływany w momencie dodawania posta do bazy. To chyba to, czego szukaliśmy!
W tym momencie warto wspomnieć o dwóch sposobach wywoływania hooków. Jeden, to run_hooks() - uruchamia funkcje pluginów tutaj zaczepionych bez przekazywania im żadnych argumentów. Drugi to run_hooks_by_ref(), przekazujący wybraną zmienną jako argument do funkcji obsługującej hooka. W naszym przykładzie przekazywane jest $this, czyli obiekt klasy PostDataHandler.
Dodajemy hooka do naszego pluginu. Po pierwsze, tworzymy funkcję nazwaplugina_nazwa_hooka(), pamiętając o tym, że dostajemy coś w argumencie.
function uczesie_datahandler_post_insert_post($it)
{
}
Następnie rejestrujemy hook. Odbywa się to przez wywołanie metody add_hook(string nazwaHooka, string nazwaFunkcjiKtoraGoObsluguje) z obiektu $plugins.
Dodajemy więc linijkę
$plugins->add_hook("datahandler_post_insert_post", "uczesie_datahandler_post_insert_post");
Linię dodajemy gdzieś w ciągu pliku (nie w żadnej z funkcji, oczywiście). Dla porządku - umieśćmy ją nad deklaracją funkcji uczesie_info()
Mając przekazany obiekt klasy PostDataHandler, możemy z nim zrobić co się nam żywnie podoba, na przykład dopisać coś do niesionej przezeń wiadomości; ta jest przechowywana pod indeksem 'message' tablicy asocjacyjnej post_insert_data będącej polem klasy, jaką stanowi przekazany w argumencie obiekt:
function uczesie_datahandler_post_insert_post($it)
{
$it->post_insert_data['message'] .= "\nA ja się [b]uczę[/b]!";
}
Jak widać, możemy tu stosować MyCode - wiadomości są z niego parsowane w momencie wyświetlania, a nie zapisu. Funkcja przetwarzająca hook nie musi nic zwracać.
W czasie tworzenia pluginów warto posługiwać się funkcjami PHP takimi jak var_dump() czy print_r() w celu wyśledzenia sposobu zapisu danych i otwarcia sobie drogi do manipulacji nimi.
Warto pamiętać, że hook datahandler_post_insert_post jest wywoływany tylko w momencie odpowiedzi na temat; gdy wysyłany post jest pierwszym w temacie, wywołuje się datahandler_post_insert_thread_post.
Nie jesteśmy jednak ograniczeni do operowania na przekazywanych nam argumentach. Możemy bowiem wyciągnąć dla siebie zmienne, które w okolicy naszego hooka biegają, za pomocą słówka global. Mamy też możliwość wykorzystywania funkcji wbudowanych w MyBB. Dzięki temu możemy na przykład uzależnić to, czy dopiszemy coś do posta, czy nie, od liczby postów użytkownika. W tym celu zglobalizujemy sobie zmienną $post zaobserwowaną gdzieś przy 643 linijce pliku inc/datahandlers/post.php
"uid" => $post['uid'],
function uczesie_datahandler_post_insert_post($it)
{
global $post; // globalizacja zmiennej
$user = get_user($post['uid']); // get_user(int IdUzykownika) to funkcja wbudowana w jadro MyBB
if ($user['postnum']%2) $it->post_insert_data['message'] .= "\nA ja się [b]uczę[/b], w co drugim poście!"; // jesli liczba postow parzysta, to dopisujemy cos do wiadomosci
}
7 Podsumowanie
Na koniec przypomnę, że pliki z polskimi ogonkami w MyBB należy zapisywać w kodowaniu UTF-8 bez BOM, co umożliwia na przykład edytor Notepad++.
W załączniku plik uczesie.php, który powstał w poradniku