5 wtyczek dla edytora Atom, które przydadzą się przy projektach związanych z WordPressem

W zależności od rozmiaru projektu używam różnych narzędzi – do większych projektów używam WebStorm, natomiast w mniejszych używałem najczęściej Sublime Text albo Espresso. Od jakiegoś czasu te dwa edytory zeszły u mnie na dalszy plan, gdyż po bardzo pozytywnych opiniach mojego znajomego – Janka Starzaka zainteresowałem się edytorem Atom. Czytaj dalej 5 wtyczek dla edytora Atom, które przydadzą się przy projektach związanych z WordPressem

Jak zarządzam swoimi projektami z użyciem Trello?

Temat zarządzania swoim czasem zawsze był dla mnie bardzo ważny i podchodziłem do niego na wiele sposobów. W ostatnim czasie wypracowałem chyba w końcu metodę wykorzystania aplikacji Trello, która mnie satysfakcjonuje i rozwiązuje wiele pomniejszych problemów oraz wad poprzednich podejść. Czytaj dalej Jak zarządzam swoimi projektami z użyciem Trello?

Joomla! czy WordPress?

Ponieważ intensywnie pracuję zarówno z Joomla! jak i WordPressem tytułowe pytanie jest zadawane mi bardzo często. Tak często, że chciałbym raz na zawsze obalić kilka mitów zwłaszcza, że zazwyczaj na ten temat wypowiadają się ludzie, którzy „kiedyś zainstalowali WordPress/Joomla”. Opiszę swoje przemyślenia z perspektywy człowieka, który zainstalował i modyfikował każdy z tych CMS-ów kilkaset razy.

TL;DR

Gdy zadawane jest mi tytułowe pytanie, to odpowiedź zawsze jest podobna – „To zależy – a do jakiego zastosowania?”. I jest to jedyna słuszna odpowiedź – wciskanie ludziom wszędzie WordPressa/Joomla! to duży błąd, bo zastosowania i cechy tych CMS-ów mocno się rozmijają. Więcej szczegółów w poniższym wpisie.

Czytaj dalej Joomla! czy WordPress?

Pobieranie produktu WooCommerce na bazie jego SKU z uwzględnieniem wielojęzyczności (WPML)

Dzisiaj krótki kawałek kodu, który może się przydać osobom posiadającym wielojęzyczne sklepy oparte na WooCommerce i WPML.

Otóż typowy kod zwracający produkt z WooCommerce na bazie jego SKU wygląda następująco:

function get_product_by_sku( $sku ) {
    global $wpdb;
    $product_id = $wpdb->get_var($wpdb->prepare("SELECT post_id FROM $wpdb->postmeta WHERE meta_key='_sku' AND meta_value='%s' LIMIT 1", $sku));
    if ($product_id) {
        return new WC_Product($product_id);
    }
    return null;
}

Niestety nie uwzględnia on faktu iż WPML dla każdego produktu tworzy oddzielny rekord w tabeli postów, zatem otrzymamy produkty w jednym języku. Na szczęście możemy to naprawić i to w relatywnie prosty sposób, bo wystarczy zmodyfikować zapytanie:

function get_product_by_sku($sku) {
    global $wpdb;

    $product_id = $wpdb->get_var($wpdb->prepare("SELECT pm.post_id FROM ".$wpdb->postmeta." AS pm LEFT JOIN ".$wpdb->prefix."icl_translations AS tr ON pm.post_id = tr.element_id WHERE pm.meta_key='_sku' AND pm.meta_value='%s' AND tr.language_code = '".ICL_LANGUAGE_CODE."'", $sku));

    if($product_id) {
        return new WC_Product($product_id);
    }
    return null;
}

Powyższy kod działa podobnie do poprzedniego tylko podczas zapytania pobierane są dane z tabeli icl_translations, które pozwalają określić język wpisów powiązanych ze zwracanymi ID. Oczywiście najważniejszy jest ostatni warunek, który wybiera tylko ten rekord, który powiązany jest z obecnie wykorzystywanym językiem na stronie.

add_theme_support(‚widget-customizer’) Ci nie działa w WordPress 3.9 RC?

WordPress 3.9 zostanie najpewniej wydany w tym tygodniu więc testom kompatybilności nie ma końca. Tym razem dał o sobie znać problem z wyświetlaniem widżetów w widoku personalizacji motywu.

Pomimo dodania w motywie linijki:

add_theme_support('widget-customizer');

W widoku personalizacji motywu po panelach bocznych nie było nawet śladu. Po chwili odkryłem korelację pomiędzy ich pojawianiem się tam a dodawaniem jednego z widżetów na ekranie zarządzania widżetami. Okazuje się, że po prostu WordPress 3.9 RC zawiera błąd załatany wczoraj. Także jeżeli chcecie na spokojnie potestować sobie tą funkcjonalność to wystarczy podmienić sobie plik wp-includes/js/customize-preview-widgets.min.js na najnowszą wersję z repozytorium.

Problem występuje wtedy gdy motyw lub wtyczka tworzy panele boczne gdzie parametry before_widget, after_widget, before_title oraz after_title są puste – wtedy skrypt z wersji RC po prostu napotyka błąd i kończy działanie.

WordPress 3.8 i dostosowanie wyglądu opcji wtyczek i motywów

Dzisiaj ukazał się WordPress 3.8 RC. Jak pewnie wszyscy zainteresowani wiedzą, wersja ta niesie duże zmiany w wyglądzie kokpitu. Zmiany te oznaczają pewien problem – nawet jeżeli korzystaliście z natywnych kontrolek UI kokpitu, to i tak czasem coś może w opcjach Waszej wtyczki czy motywu wyglądać nie tak jak sobie wymarzyliście 😉

Dodatkowo pojawia się jeszcze jeden problem – nie każdy użytkownik WordPressa będzie korzystał od razu z wersji 3.8. Zatem teoretycznie wtyczki i motywy powinny zawierać style CSS dla kokpitu, które zadziałają w zależności od używanej wersji WordPressa.

Na szczęście rozwiązanie tego problemu w CSS jest bardzo proste. WordPress w elemencie body kokpitu dodaje dużo różnych klas CSS – wśród tych klas znajdują się klasy o nazwach branch-* i version-*. I to właśnie te klasy uratują nam skórę 🙂

Klasa branch-* zmienia się z każdym dużym wydaniem WordPressa – w wersji 3.7.1 nazywa się ona branch-3-7, natomiast w 3.8 ma już nazwę branch-3-8. Klasa version-* zmienia się przy każdej aktualizacji WordPressa więc w wypadku wersji 3.7.1 ma ona nazwę version-3-7-1 a w wypadku wersji 3.8 ma nazwę version-3-8.

Jak widać z naszego punktu widzenia klasa branch-* będzie bardziej wygodna niż klasa version-*, gdyż ta druga zmieni swoją nazwę przy najbliższej aktualizacji WordPressa.

Jak możecie się domyslić aby stworzyć kod CSS działający tylko w WordPressie 3.8, wystarczy poprzedzić modyfikowane selektory zapisem:

.branch-3-8

Zatem aby na przykład zmodyfikować wygląd paragrafów tylko w WordPressie 3.8 wystarczy selektor:

.branch-3-8 p

Dzięki temu paragrafy w starszych wersjach WordPressa się nie zmienią.

Co bardziej zapobiegliwi mogą od razu zaaplikować następujący kod:

.branch-3-8 p,
.branch-3-9 p

Ale wtedy muszą liczyć na to, że w panelu WordPressa 3.9 za wiele się nie zmieni 😉

Własne filtry obrazu (sepia, greyscale) w WP_Image_Editor

Standardowo implementacja klasy WP_Image_Editor nie udostępnia nam żadnych filtrów dla obrazów takich jak sepia czy skala odcieni szarości (greyscale). Na szczęście klasa ta została zaimplementowana w bardzo elastyczny sposób, przez co umożliwia dodanie własnych metod. Pokażę więc w jaki sposób można stworzyć własne filtry obrazu.

Idea stojąca za WP_Image_Editor

Klasa WP_Image_Editor jest klasą abstrakcyjną – czyli najprościej mówiąc służy za wzór dla innych, bardziej szczegółowych implementacji operacji na obrazie z wykorzystaniem różnych bibliotek graficznych. Stąd też w WordPressie znajdziemy takie klasy jak WP_Image_Editor_Imagick czy WP_Image_Editor_GD. Obie wspomniane klasy odpowiadają za implementację operacji na obrazie z użyciem dwóch popularnych bibliotek graficznych: ImageMagick i GD. Trzeba o tym pamiętać gdyż fakt ten ma bardzo ważną implikację – implementując jakiś efekt powinniśmy zadbać o jego wsparcie w obu wypadkach (no chyba, że robimy projekt na własne potrzeby i pod konkretną konfigurację serwera).

Implementacja nowych metod operujących na obrazie

Jak można dodać własne metody operujące na obrazie? Trzeba stworzyć klasy potomne dla klas WP_Image_Editor_Imagick i WP_Image_Editor_GD. Poniżej znajduje się moja implementacja metod dziudek_greyscale i dziudek_sepia:

class Dziudek_Imagick_Filters_Editor extends WP_Image_Editor_Imagick {
  public function dziudek_sepia($arg = 100) {
    $this->image->sepiaToneImage($arg);
    return true;
  }
  public function dziudek_greyscale() {
    $this->image->modulateImage(100,0,100);
    return true;
  }
}
class Dziudek_GD_Filters_Editor extends WP_Image_Editor_GD {
  public function dziudek_sepia() {
    imagefilter($this->image, IMG_FILTER_GRAYSCALE);
    imagefilter($this->image, IMG_FILTER_COLORIZE, 90, 60, 40);
    return true;
  }

  public function dziudek_greyscale() {
    imagefilter($this->image, IMG_FILTER_GRAYSCALE);
    return true;
  }
}

Jak widać stworzyliśmy dwie klasy potomne. Teoretycznie mógłbym metody nazwać sepia i greyscale ale niedługo wyjaśni się czemu lepiej zastosować prefiks.

Najprawdopodobniej będziemy musieli też dołączyć wszystkie potrzebne klasy do naszego pliku z nowymi klasami potomnymi:

require_once(ABSPATH . WPINC . '/class-wp-image-editor.php');
require_once(ABSPATH . WPINC . '/class-wp-image-editor-imagick.php');
require_once(ABSPATH . WPINC . '/class-wp-image-editor-gd.php');

Mamy już prawie wszystko czego nam potrzeba – pora sprawić, żeby nasz kod był dostępny w WordPressie w metodzie wp_get_image_editor – w tym celu wykorzystamy filtr wp_image_editors:

function dziudek_add_image_filters_editors( $editors ) {
  array_unshift( $editors, 'Dziudek_Imagick_Filters_Editor' );
  array_unshift( $editors, 'Dziudek_GD_Filters_Editor' );

  return $editors;
}

add_filter( 'wp_image_editors', 'dziudek_add_image_filters_editors' );

Powyższa funkcja spowoduje dodanie naszych klas potomnych do listy dostępnych edytorów obrazu.

Pora użyć naszego kodu

Wyprodukowaliśmy już sporo kodu, zatem pora z niego zrobić użytek 🙂

Aby wykorzystać nasze własne klasy, musimy skorzystać z drugiego parametru metody wp_get_image_editor:

$img_editor = wp_get_image_editor( 
    $path_to_file, 
    array( 'methods' => array( 'dziudek_sepia', 'dziudek_greyscale' ) ) 
);

Pierwszy argument to oczywiscie ścieżka do pliku na którym będziemy działać, natomiast ten drugi argument pozwala nam określić jakich dodatkowych metod oczekujemy po edytorze obrazu. Słowo klucz to „oczekujemy” – może się okazać, że żaden z dostępnych edytorów obrazu nie oferuje pożądanej przez nas funkcjonalności – wtedy zmienna $img_editor będzie zawierać obiekt klasy WP_Error z informacją „No image editor”. W naszym wypadku jednak wszystko powinno zadziałać i WordPress powinien zwrócić instancję klasy Dziudek_GK_Filters_Editor lub Dziudek_Imagick_Filters_Editor zależnie od tego, która z tych bibliotek zainstalowana jest u nas na serwerze.

Dzięki temu będziemy mogli wykonać następujący kod:

$img_editor->dziudek_greyscale();

lub:

$img_editor->dziudek_sepia();

Wracając do prefiksów w nazwach tych metod. Teoretycznie dla skrócenia kodu można by je pominąć, ale pamiętajmy – autor jakiejś wtyczki może dodać własne funkcjonalności różniące się efektami od naszych i wtedy pojawi się problem, gdyż taka implementacja może zostać wczytana zamiast naszej jako edytor obrazu ze względu na spełnienie naszych potrzeb odnośnie funkcjonalności (polecam w tym miejscu analizę metody _wp_image_editor_choose). Zatem osobiście polecam jednak używać prefiksów w nazwach metod lub używanie bardziej wyszukanych nazw metod 🙂

Podsumowanie

Jak widać implementacja klasy WP_Image_Editor jest bardzo elastyczna i pozwala na łatwe dodawanie funkcjonalności. Z mojego punktu widzenia najwygodniejsze jest to, że nie muszę się martwić o wykrywanie poszczególnych bibliotek graficznych – kod WordPressa robi to za mnie. Polecam własne eksperymenty z filtrami obrazu 🙂

Nadawanie instancjom widżetów różnych stylistyk

Ostatnio tworząc widżety natrafiłem na problem nadawania instancjom widżetów różnych stylistyk. Jak w skrócie wyglądały moje wymagania:

  • Widżet musi posiadać kilka stylów w oddzielnych plikach CSS (dla łatwiejszego zarządzania nimi) – każdy styl powiązany jest z unikalną klasą CSS definiowaną w głównym kontenerze widżetu.
  • W zależności od konfiguracji instancji widżetów, wczytywane są tylko potrzebne pliki CSS (jeżeli w przyszłości widżet będzie posiadał 10 różnych dostępnych stylów to bez sensu byłoby wczytywać je wszystkie niezależnie od tego czego potrzebuje użytkownik)

Na czym polegał problem?

Otóż akcja dodawania styli CSS do sekcji <head> witryny (wp_enqueue_style) wykonywana jest wcześniej niż renderowanie widżetów, a co za tym idzie funkcja, która ma wybrać CSS do wczytania, nie ma dostępu do opcji w danej instancji widżetu.

Na szczęście rozwiązanie okazało się być bardzo proste:

Wystarczy wczytać parametry widżetu z tabeli opcji i sprawdzić jakie style CSS są potrzebne do wyświetlenia wszystkich instancji:

$instances = get_option('WIDGET_OPTION_NAME');
$loaded_files = array();
foreach($instances as $instance) {
    if(!in_array($instance['style'], $loaded_files)) {
       wp_register_style( 'WIDGET_PREFIX-' . $instance['style'], home_url() . '/wp-content/plugins/WIDGET_NAME/styles/'. $instance['style'] .'.css', array(), false, 'all');
        wp_enqueue_style('WIDGET_PREFIX-' . $instance['style']);
        array_push($loaded_files, $instance['style']);
    }
}

Jak widać powyższy kod wczytuje zawartość opcji widżetu (parametr style przechowuje nazwę pliku CSS do wczytania) oraz tworzy tablicę wczytanych już raz stylów CSS. Następnie sprawdzane są wszystkie instancje widżetu oraz wczytywane są brakujące pliki. Dzięki temu nie są wykonywane zbędne operacje kolejkowania już raz dodanych plików CSS.

Mała wada

Opisywane rozwiązanie ma jedną małą wadę – jeżeli niektóre instancje widżetu są wyświetlane tylko na określonych podstronach to i tak zostaną wczytane style dla wszystkich wykorzystywanych instancji. Teoretycznie można by to wszystko sprawdzić, przy czym takie sprawdzenie zależałoby od metody wykorzystywanej do wyświetlania widżetów na różnych podstronach. Dodatkowo zawsze nadmiar zapytań HTTP i kodu można zniwelować poprzez cache CSS (oczywiście zakładam tutaj scenariusz w którym użytkownik nie korzysta z wszystkich styli jak popadnie a jedynie z góra kilku wybranych).

Opcje widżetu i problem z json_decode przy poprawnej strukturze JSON

Opisywany problem przytrafił mi się już kilka razy i za każdym razem straciłem dobre pół godziny zanim sobie przypomniałem co robiłem źle. Dlatego w ramach utrwalenia sobie w pamięci tworzę ten wpis 😉

Czytaj dalej Opcje widżetu i problem z json_decode przy poprawnej strukturze JSON