Wzorzec projektowy Adapter – klucz do dostosowania interfejsu do Twoich potrzeb

Wzorzec projektowy Adapter w PHP – jak go zastosować w swoim projekcie?

Zobacz jak wzorzec projektowy Adapter może Ci pomóc dostosować interfejs do potrzeb Twojego projektu w PHP. Przeczytaj nasz przewodnik i poznaj przykłady jego zastosowania w praktyce.

Adapter to wzorzec projektowy, który pozwala na dostosowanie interfejsu jednej klasy do interfejsu innej klasy. Jest to użyteczne, gdy chcesz użyć już istniejącej klasy, ale jej interfejs nie pasuje do Twoich potrzeb. Wzorzec Adapter pozwala na ukrycie różnic między interfejsami, dzięki czemu można je łatwo połączyć i użyć razem.

Jakie zastosowania ma wzorzec Adapter?

Wzorzec Adapter jest często stosowany w następujących sytuacjach:

  • Integracja z istniejącymi klasami: Adapter może być użyty do integracji z już istniejącymi klasami, których interfejs jest niezgodny z twoimi potrzebami.
  • Zmiana interfejsu: Adapter pozwala na zmianę interfejsu klasy bez ingerencji w jej kod źródłowy.
  • Rozszerzanie funkcjonalności: Adapter może być użyty do rozszerzenia funkcjonalności istniejącej klasy poprzez dodanie dodatkowych funkcji.
  • Łączenie różnych systemów: Adapter może być użyty do łączenia różnych systemów i ukrywania różnic między nimi.
  • Współpraca z różnymi bibliotekami: Adapter może być użyty do współpracy z różnymi bibliotekami i frameworkami, które mają różne interfejsy.

Wzorzec projektowy Adapter – przykład implementacji

interface Target {
    public function request();
}
 
class Adaptee {
    public function specificRequest() {
        return "Specific request";
    }
}
 
class Adapter implements Target {
    private $adaptee;
 
    public function __construct(Adaptee $adaptee) {
        $this->adaptee = $adaptee;
    }
 
    public function request() {
        return "Adapter: (TRANSLATED) " . $this->adaptee->specificRequest();
    }
}
 
$adaptee = new Adaptee();
$adapter = new Adapter($adaptee);
 
echo $adapter->request();

W powyższym kodzie mamy interfejs Target, który zawiera sygnaturę metody request(), którą chcemy użyć. Klasa Adaptee jest klasą, która posiada funkcjonalność, ale interfejs jest niezgodny z naszymi wymaganiami. Klasa Adapter jest naszym adapterem i jest on implementacją interfejsu Target. Wewnątrz klasy Adapter używamy obiektu Adaptee, aby wykonać żądane zadanie.

Wzorzec projektowy Adapter w Laravel

Wzorzec projektowy Adapter jest często używany w frameworku Laravel. Laravel posiada wiele mechanizmów, które pozwalają na łatwe dostosowanie interfejsu i implementacji do potrzeb projektu.

Na przykład, można dostosować dostarczone przez framework adaptery bazy danych, aby użyć innej niż domyślna biblioteki do komunikacji z bazą danych. W ten sposób wzorzec Adapter jest wykorzystywany w Laravel do dostosowywania interfejsu do potrzeb projektu.

Rozbicie routes na kilka plików w Laravel

Gdy aplikacja robi się coraz większa dla czytelności można chcieć podzielić plik routes/web.php na kilka mniejszych.

Aby to zrealizować moją pierwszą myślą było po prostu include wydzielonych plików z trasami:

// routes/web.php

require_once 'web/redirects.php';
require_once 'web/website.php';
require_once 'web/admin.php';

Mimo iż to jest złe podejście to po tej zmianie aplikacja działała całkowicie poprawnie.

Problemy zaczęły się gdy wykonałem testy PHPUnit

    public function test_home()
    {
        $response = $this->get('/');

        $response->assertStatus(200);
    }

    public function test_posts()
    {
        $response = $this->get('/posts');

        $response->assertStatus(200);
    }

Pierwszy test zawsze przechodził jednak następne (bez względu czy w tym samym czy innym pliku) zwracały błąd:

Route [home] not defined.

Okazuje się, że mechanika testująca Laravela wczytuje jedynie plik routes/web.php

Aby poprawnie rozbić routes na kilka plików zamiast includów w samym pliku trzeba dostarczyć ścieżki w Provoderze.

Poprawne rozbicie routes na wiele plików

// App\Providers\RouteServiceProvider.php;

Route::middleware('web')
    ->namespace($this->namespace)
    ->group(
        [
            base_path('routes/web.php'),
            base_path('routes/web/redirects.php'),
            base_path('routes/web/website.php'),
            base_path('routes/web/admin.php'),
        ]
    );

Wzorzec projektowy Strategy. Elastyczność i niezależność w twoim kodzie.

Wzorzec projektowy Strategy przydaje się do definiowania rodziny zachowań, algorytmów lub strategii, które mogą być wymieniane przez aplikację. Umożliwia to programowanie do interfejsu, a nie konkretnej implementacji.

Do konkretnych zastosowań wzorca Strategy należą:

  • Abstrakcja algorytmów: Strategy pozwala na oddzielenie logiki algorytmu od klienta, co pozwala na łatwą zmianę implementacji algorytmu bez konieczności modyfikacji kodu klienta.
  • Elastyczność: Aplikacja może zmienić strategię w trakcie działania, co pozwala na dostosowanie działania aplikacji do różnych potrzeb czy sytuacji.
  • Łatwe testowanie: oddzielenie algorytmów od reszty aplikacji pozwala na łatwe testowanie poszczególnych implementacji algorytmów.
  • Skalowalność: rozdzielenie algorytmów

Wzorzec projektowy Strategy – przykład implementacji

Poniżej przedstawiam przykład implementacji wzorca projektowego Strategy w PHP:

interface SortStrategy {
    public function sort(array $data): array;
}

class BubbleSort implements SortStrategy {
    public function sort(array $data): array {
        // implementacja sortowania bąbelkowego
        return $data;
    }
}

class quickSort implements SortStrategy {
    public function sort(array $data): array {
        // implementacja sortowania szybkiego
        return $data;
    }
}

class Sorter {
    protected $sortStrategy;

    public function __construct(SortStrategy $sortStrategy) {
        $this->sortStrategy = $sortStrategy;
    }

    public function setSortStrategy(SortStrategy $sortStrategy) {
        $this->sortStrategy = $sortStrategy;
    }

    public function sort(array $data): array {
        return $this->sortStrategy->sort($data);
    }
}

Kod powyżej zawiera interfejs SortStrategy, który zawiera metodę sort(array $data): array. Klasy bubbleSort i quickSort implementują ten interfejs i zwracają posortowane dane.

Klasa Sorter jest klasą klienta, która przyjmuje obiekt implementujący interfejs SortStrategy w konstruktorze, a następnie używa tego obiektu do wywołania metody sort(array $data) .

$data = [5, 1, 3, 8, 2, 9];

$sorter = new Sorter(new bubbleSort());
$sorter->sort($data);

$sorter->setSortStrategy(new quickSort());
$sorter->sort($data);

W powyższym przykładzie tworzymy instancję klasy Sorter z podaną implementacją sortowania, która jest przypisana do pola sortStrategy. W kolejnym kroku dzięki metodzie setSortStrategy zmieniamy implementację sortowania na inną.

Wzorzec strategy pozwala nam na dynamiczne zmienienie implementacji algorytmu, pozwala na oddzielenie logiki algorytmu od klienta oraz umożliwia tworzenie nowych implementacji bez konieczności modyfikacji kodu klienta.

Wzorzec projektowy Strategy w Laravel

W Laravelu wzorzec Strategy jest używany w kilku miejscach, w tym:

Obsługa różnych formatów danych – Laravel używa strategii do obsługi różnych formatów danych, takich jak json, xml czy też csv. Dzięki temu możemy łatwo dostosować format danych który jest zwracany przez API.

Obsługa różnych metod płatności – Laravel używa strategii do obsługi różnych metod płatności, takich jak PayPal czy też Stripe. Dzięki temu możemy łatwo dostosować system płatności do potrzeb naszej aplikacji.

Obsługa różnych metod wysyłki – Laravel używa strategii do obsługi różnych metod wysyłki, takich jak Poczta Polska czy też DHL. Dzięki temu możemy łatwo dostosować system wysyłki do potrzeb naszej aplikacji.

Widać więc, że wzorzec strategy jest ważnym elementem w Laravelu, ponieważ pozwala na dynamiczne dostosowywanie działania aplikacji do różnych potrzeb i sytuacji, co wpływa na elastyczność i skalowalność aplikacji. Dzięki temu, logika działania jest oddzielona od reszty aplikacji, co pozwala na łatwe testowanie oraz rozwijanie poszczególnych modułów.

Wzorzec projektowy Fabryka. Twoja szansa na zwiększenie czytelności i testowalności kodu.

Wzorzec projektowy Fabryka to Twoja przepustka do projektowania modularnego i skalowalnego kodu.

Wzorzec projektowy Fabryka jest przydatny do tworzenia obiektów. Głównym celem tego wzorca jest oddzielenie logiki tworzenia obiektów od reszty aplikacji oraz umożliwienie łatwego tworzenie różnych typów obiektów.

Do konkretnych zastosowań wzorca Fabryka należą:

  • Abstrakcja tworzenia obiektów – fabryka jest odpowiedzialna za tworzenie obiektów, a nie klient, dlatego logika tworzenia obiektów jest oddzielona od reszty aplikacji.
  • Tworzenie różnych typów obiektów – fabryka może tworzyć różne typy obiektów, które implementują tę samą klasę bazową lub interfejs. To pozwala na łatwe rozszerzanie aplikacji o nowe funkcjonalności.
  • Tworzenie obiektów z danymi testowymi – fabryki często są używane do tworzenia obiektów z danymi testowymi, co jest przydatne przy tworzeniu testów jednostkowych.
  • Elastyczność – Wzorzec fabryka umożliwia na dynamiczne tworzenie różnych implementacji tej samej klasy bazowej czy interfejsu.

Wzorzec projektowy Fabryka – przykład implementacji

Poniżej przedstawiam przykład implementacji wzorca projektowego Fabryka w PHP:

interface Vehicle {
    public function getType(): string;
}

class Car implements Vehicle {
    public function getType(): string {
        return "Car";
    }
}

class Bike implements Vehicle {
    public function getType(): string {
        return "Bike";
    }
}

class VehicleFactory {
    public static function createVehicle(string $type): Vehicle {
        switch ($type) {
            case "car":
                return new Car();
            case "bike":
                return new Bike();
            default:
                throw new Exception("Invalid vehicle type");
        }
    }
}

Kod powyżej zawiera interfejs Vehicle, który zawiera metodę getType(). Klasy Car i Bike implementują ten interfejs i zwracają odpowiedni typ pojazdu. Klasa VehicleFactory jest fabryką, która posiada statyczną metodę createVehicle(), która jest odpowiedzialna za tworzenie obiektów klas Car i Bike. Metoda ta przyjmuje jako argument typ pojazdu, a następnie w zależności od tego jaki typ jest podany zwraca odpowiedni obiekt.

$car = VehicleFactory::createVehicle("car");
echo $car->getType(); // "Car"

$bike = VehicleFactory::createVehicle("bike");
echo $bike->getType(); // "Bike"

W powyższym przykładie używamy metody createVehicle z klasy VehicleFactory by utworzyć instancję klasy Car lub Bike.

Warto zauważyć, że zwiększa to abstrakcję i oddziela logikę tworzenia obiektów od reszty aplikacji. Dzięki temu w razie potrzeby, możemy łatwo zmienić sposób tworzenia obiektów bez wpływu na pozostałą część aplikacji.

Warto wspomnieć że wzorzec Fabryka jest często używany w połączeniu z innymi wzorcami projektowymi takimi jak np. Wzorzec projektowy Strategia czy też Wzorzec projektowy Builder. Dzięki temu połączeniu, tworzą one skomplikowany system, który jest bardziej elastyczny i łatwy w utrzymaniu.

Wzorzec projektowy Fabryka w Laravel

W Laravelu wzorzec fabryka jest używany w kilku miejscach, w tym:

Tworzenie obiektów modeli – Laravel używa fabryk do tworzenia obiektów modeli, które reprezentują rekordy z bazy danych. Fabryki pozwalają na łatwe utworzenie obiektów z danymi testowymi, co jest bardzo przydatne przy tworzeniu testów jednostkowych.

Tworzenie migracji – Laravel używa fabryk do generowania danych testowych do migracji, które pozwalają na przetestowanie aplikacji przed uruchomieniem jej na produkcji.

Tworzenie przykładowych danych – Laravel udostępnia także API do tworzenia przykładowych danych, które są generowane przez fabryki.

Tworzenie modeli w kontrolerach – Fabryki Laravel pozwalają także na proste tworzenie modeli bezpośrednio w kontrolerach, w związku z tym użycie konstruktora nie jest konieczne.

Widać więc, że fabryki są istotnym elementem w Laravelu, ponieważ pozwalają na generowanie danych testowych, tworzenie modeli i migracji, co wpływa na poprawienie przetestowalności aplikacji. Dzięki fabrykom kod jest bardziej czytelny, ponieważ logika tworzenia obiektów jest oddzielona od reszty aplikacji.

Wzorzec projektowy Fabryka w Symfony

W Symfony możemy również użyć fabryki do tworzenia instancji usług zależnie od określonych warunków lub konfiguracji.

Na przykład, możemy stworzyć fabrykę, która na podstawie parametru konfiguracyjnego utworzy odpowiednią instancję usługi do obsługi operacji na plikach.

class FileServiceFactory {
    public static function create(string $storageType): FileServiceInterface {
        switch ($storageType) {
            case 'local':
                return new LocalFileService();
            case 'cloud':
                return new CloudFileService();
            default:
                throw new \InvalidArgumentException('Invalid storage type');
        }
    }
}

// Użycie fabryki
$fileService = FileServiceFactory::create('cloud');
$fileService->uploadFile($file);

Pluginy do WordPress

Uwaga: post oryginalnie został opublikowany w 2014, ale lista pluginów jest stale aktualizowana.

Poniżej prezentuję moją subiektywną listę najlepszych pluginów przydatnych do tworzenia i utrzymywania serwisu opartego o platformę WordPress.

Jeżeli znasz przydatny plugin podziel się tym w komentarzu.

Budowanie serwisu

Advanced Custom Fields – najlepszy plugin do budowania intuicyjnego interfejsu w panelu admina dla użytkowników serwisu postawionego na WordPress’ie. ACF bazuje na WordPress’owych custom_fields, nawet początkujący developer WP jest w stanie stworzyć przyjazdy interfejs z dedykowanymi polami pod konkretne dane dla każdego typu postu czy strony.  Integracja z Gravity: Gravityforms Add-on, i NinjaFormsImage Crop Add-on, Advanced Custom Fields: Image Aspect Ratio Crop Field (chyba lepszy) – do wymuszenia konkretnych rozmiarów zdjęć (nie trzeba add_image_size), Advanced Custom Fields: Table Field.

ACF better search – wyszukiwanie po polach ACF

WPgraphQL dla ACF – rest api dla pól ACF

Custom Post Type UI – plugin do tworzenia własnych typów danych i taksonomii, współpracuje z ACF.

Posts 2 Posts – Najlepszy plugin do tworzenia relacji pomiędzy typami postów. To poniekąd analogia do typu Relationship z ACF.

Debug Bar – plugin dodaje do wordpressowego toolbara informacje o wykonanych zapytaniach SQL, pobranych danych z cache, warningach i noticeach phpowych, listuje zmienne GET, POST, COOKIE oraz inne przydatne informacje. Aby skorzystać z wszystkich możliwości plugina należy ustawić w wp-config.php zmienne WP_DEBUG i SAVEQUERIES na true.

Query Monitor – dużo lepsza wtyczka od Debug Bar. Wyświetla więcej danych w bardziej przystępny sposób.

Regenerate Thumbnails – niezastąpiony plugin do aktualizowania plików graficznych z biblioteki mediów po zmianie rozmiaru miniaturek (Ustawienia->media) lub po dodaniu dodatkowych niestandardowych rozmiarów poprzez funkcję add_image_size.

Polylang – bardzo dobry plugin do obsługi wielojęzykowych serwisów, w przeciwieństwie do WPML jest darmowy.

https://github.com/KLicheR/wp-polylang-translate-rewrite-slugs/blob/master/polylang-translate-rewrite-slugs.php

JSON API – RESTful API dla WordPressa. Przydatne gdy w prosty sposób chcemy dostarczyć dane z WP do aplikacji zewnętrznych lub interfejsów JavaScriptowych.

rest-filter – Przywraca możliwość filtrowania w REST API, dzięki temu poprzez &filter[lang]=en można filtrować języki w Polylang.

WordPress REST API – oficjalny plugin REST API od WP

Add From Server – jeżeli potrzebujesz wgrywać do WP duże pliki to zrobisz to dzięki Add From Server. Schemat działania jest prosty, wgrywasz duży plik poprzez FTP do określonego katalogu a następnie z poziomu WP dodajesz do biblioteki mediów. Prosto i intuicyjnie. Jeżeli potrzebujesz wgrywać pliki o niestandardowych rozszerzeniach to pamiętaj o wyłączeniu natywnego filtrowania.

Loco Translate – plugin do tłumaczeń, korzysta z plików PO.

Post Type Archive Link – plugin dodaje linki do menu dla stron list custom post type. Dzięki temu można w prosty i automatyczny sposób dodawać do menu linki do stron z listami custom posts.

Breadcrumb NavXT – plugin do generowania okruszków, breadcrumbs

Simple Share Buttons Adder – przyjazny plugin do social ikon.

Social Media Feather – chyba jeszcze lepszy plugin do social media ikon.

SVG Support – plugin umożliwiający wgrywanie do WP plików SVG. Dodaje też pogląd SVG w bibliotece mediów.

WP-DB-Table-Editor – plugin umożliwiający odczyt/zapis/eksport danych z customowych tabel z bazy danych.

WP Crontrol – plugin umożliwiający dodawanie i zarządzeni wbudowanymi do WP zadaniami crona

Permalink manager – nieoceniony plugin do zaawansowanej zamiany permalinków, prosty interface i świetne działanie.

WP better permalinks – łatwe zarządzanie permalinkami dla custom posts i taxonomies

Shortcake (Shortcode UI) – plugin zapewniający przyjazny interface do tworzenia i wyświetlania shortcode’ów. Posiada niemrawą dokumentacje ale robi fajną robotę. Dodatek wp-shortcode-ui-richtext umożliwiający zamianę textarea na edytor wyswig.

Contextual Related Posts – powiązane posty

Yasr – Yet Another Stars Rating – ocena gwiazdkowa postów

pipDisqus – Lightweight Disqus Comments – plugin zamieniające natywne WP komentarze na disqus. Lepszy od oficjalnego plugina dla WP od disqus.

Czytaj dalej „Pluginy do WordPress”

Wysyłka SMS w aplikacjach internetowych

Tworząc aplikacje internetowe często zachodzi potrzeba implementacji modułu do wysyłki SMS.

Może to być informacja o zmianie statusu zamówienia złożonego w sklepie internetowym, może to być jakiś ważny komunikat systemowy dotyczący konta w serwisie, może to być powiadomienie o wystąpieniu jakiegoś zdarzenia, które monitoruje klient (np. pojawienie się oferty spełniającej ustawione kryteria) lub po prostu mechanizm weryfikacji wysyłający kod na telefon. Potrzeby wdrożeń powiadomień SMS’owych z pewnością można mnożyć.

Wdrażając moduł powiadomień SMS należy mieć na uwadze, że komunikacja SMS’owa nadaje przekazywanej wiadomości dużo większy priorytet niż e-mail czy powiadomienie w aplikacji na smartfona, nic bardziej nie irytuje użytkownika niż spam w SMS’ach.

Obecnie w internecie znaleźć można bardzo wiele bramek/serwisów oferujących mniej lub bardziej zaawansowane systemy do obsługi powiadomień sms.

Jak to działa?

Wdrożenie modułu SMS jest na prawdę proste i nieskomplikowane, opiera się na 3 krokach:

  • Rejestrujesz się w serwisie obsługującym wysyłki SMS. Ściągasz klienta API czyli bibliotekę przez którą łączysz się z systemem obsługującym wysyłkę.
  • Wprowadzasz namiary autoryzacyjne (login/hasło/hash autoryzujący) tak aby system mógł zidentyfikować żądanie wysyłki.
  • Wdrażasz wywołanie API do aplikacji.

Należy w tym miejscu rozróżnić bramkę sms od usługi sms api. Zwykła bramka sms jedynie umożliwia ręczne wprowadzenie wiadomości natomiast w aplikacji potrzebujemy mechanizmu automatycznego, czyli dostęp przez API.

Który serwis do wysyłki SMS wybrać?

Jak wspomniałem wcześniej, serwisów do wysyłki SMS jest wiele, zdecydowana większość jest płatna a ceny wahają się w granicach od kilku do kilkunastu groszy za SMS, czyli w budżecie np. 100 zł dostępnych jest 1428 smsów w cenie 0,07 zł każdy. Myślę, że przy takim niskim koszcie wysyłki nie opłaca się szukać na siłę darmowych niekoniecznie sprawdzonych i dobrze działających alternatyw.

Ja w projekcie wybrałem SMSAPI.pl. Dlaczego?

  • Profesjonalnie napisany klient php, dostępny od ręki w composerze.
  • Bardzo dobrze przygotowany dział dla developera (smsapi.pl/dev) z wieloma gotowymi modułami i przykładowymi integracjami.
  • Mnogość opcji wysyłki wiadomości ECO, PRO, ze zdefiniowanym nadawcą lub bez, MMS, VMS, odbiór wiadomości.
  • Szybkość działania, większość wiadomości dostarczane jest w czasie do 10 sekund.
  • Przejrzysty serwis internetowy i panel klienta, możliwość wysyłki bezpośrednio z panelu klienta.

Przykład użycia API

<?php

require_once 'smsapi/Autoload.php';

$client = new \SMSApi\Client('login');
// Ustawiamy hasło, w panelu klienta możemy wygenerować hasło różne od hasła do panelu klienta, wysyłkę można też zabezpieczyć IPkami.
$client->setPasswordHash( 'haslo w md5' );

// Inicjalizujemy klienta API
$smsapi = new \SMSApi\Api\SmsFactory();
$smsapi->setClient($client);

try {

    $actionSend = $smsapi->actionSend();

    $actionSend->setTo('600xxxxxx');
    $actionSend->setText('Hello World!!');
    //Pole nadawcy lub typ wiadomość 'ECO', '2Way'
    $actionSend->setSender('Info');

    $response = $actionSend->execute();

    foreach( $response->getList() as $status ) {
        echo  $status->getNumber() . ' ' . $status->getPoints() . ' ' . $status->getStatus();
    }
}
// Przechwytujemy ewentualne błędy, będą one automatycznie widoczne w panelu klienta.
catch( \SMSApi\Exception\SmsapiException $e ) {
    echo 'ERROR: ' . $e->getMessage();
}

Kombinacje bez powtórzeń zbioru liczb – zapytanie SQL

Pytanie zgłoszone przez czytelnika. W jaki sposób z zestawu liczb będących w osobnych rekordach wyświetlić kombinacje bez powtórzeń. Dla przykładu wyświetlimy kombinacje bez powtórzeń zbioru 3 elementowego ze zbioru 6 elementowego. n!/k!(n-k)!

Tworzymy tabelę testową:

create table test(
id serial primary key,
  number float
);

insert into test(number) values(2.49);
insert into test(number) values(5.11);
insert into test(number) values(10);
insert into test(number) values(20);
insert into test(number) values(27.4);
insert into test(number) values(75);

W zapytaniu nasze dane złączamy 3 krotnie bo takiej wielkości zbiór unikalnych liczb chcemy uzyskać, złączamy z warunkiem na różne IDki aby uniknąć zduplikowanych liczb. Następnie w zapytaniu nadrzędnym odfiltrowujemy powtarzające się rekordy.

W przypadku gdybyśmy chcieli uzyskać zbiory 4 elementowe należy złączyć 4 krotnie, stworzyć kolumnę number4 i dodać na nią warunek w zapytaniu zewnętrznym.

SELECT 
*
FROM 
  (SELECT
    T1.number AS number1, 
    T2.number AS number2, 
    T3.number AS number3 
  FROM test AS T1 
  JOIN test AS T2 ON T1.id != T2.id
  JOIN test AS T3 ON T2.id != T3.id AND T1.id != T3.id
  ORDER BY number1, number2, number3
  ) AS sub
WHERE 
  sub.number1 <  sub.number2
AND
  sub.number2 <  sub.number3

Wynik zapytania:

 number1 | number2 | number3
---------+---------+---------
    2.49 |    5.11 |      10
    2.49 |    5.11 |      20
    2.49 |    5.11 |    27.4
    2.49 |    5.11 |      75
    2.49 |      10 |      20
    2.49 |      10 |    27.4
    2.49 |      10 |      75
    2.49 |      20 |    27.4
    2.49 |      20 |      75
    2.49 |    27.4 |      75
    5.11 |      10 |      20
    5.11 |      10 |    27.4
    5.11 |      10 |      75
    5.11 |      20 |    27.4
    5.11 |      20 |      75
    5.11 |    27.4 |      75
      10 |      20 |    27.4
      10 |      20 |      75
      10 |    27.4 |      75
      20 |    27.4 |      75
(20 rows)

Masz problem SQL do rozwiązania? Napisz.

Jak usunąć klasę „hentry” z WordPress?

W wordpress’owym szablonie single.php, który odpowiada za wyświetlenie pojedynczego wpisu używana często jest funkcja

post_class();

Funkcja ta generuje szereg klas typu:

class="post-395 post type-post status-publish format-standard hentry category-sample category-wyroznione"

Konflikt Rich Snippets

Klasy te często są przydatne i na części z nich z pewnością opierają się definicje CSS. Problem w tym, że jeżeli na blogu posiadamy zaimplementowane Google Rich Snippets w formacie innym niż microformats to klasa „hentry” będzie powodować błędy widoczne na screenie. Czytaj dalej „Jak usunąć klasę „hentry” z WordPress?”