Date Queries pojawią się w WordPressie 3.7

Uwaga! Wpis ten dotyczy ciągle rozwijanej funkcjonalności WordPressa 3.7 – jej działanie może ulec zmianie w toku prac nad nowym wydaniem WordPressa.

Wygląda na to, że WordPress 3.7 przyniesie nową, bardzo ciekawą funkcjonalność związaną z tworzeniem zapytań zwracających wpisy – możliwość określenia ram czasowych dla pobieranych danych. Otwiera to wiele ciekawych możliwości np. wyświetlanie wpisów z konkretnego miesiąca, prezentacja wpisów opublikowanych tylko po godzinie 18 itd.

Sama obsługa tego typu zapytań wygląda przyjaźnie i warto o tej zmianie pamiętać oraz ją uwzględnić w swoich planach – może to pozwolić na uniknięcie tworzenia własnych, wyszukanych zapytań z pominięciem warstwy abstrakcji jaką oferuje nam natywna klasa obsługi bazy danych.

W klasie WP_Query dochodzi nam nowy argument – date_query, który posiada następujące parametry:

'date_query' => array( // Wszystkie parametry są opcjonalne
    'column' => 'post_date', // określa kolumnę wykorzystywaną do porównań
    'compare' => '=', // operator porównania, możliwe wartości: '=', '!=', '>', '>=', '<', '<=', 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN'     
    'relation' => 'AND', // określa jak będą łączone argumenty z podtablic - możliwe warotści: 'OR', 'AND'
    array(
        'column' => 'post_date', // j.w. można łączyć porównania różnych kolumn
        'compare' => '=', // j.w. można zmieniać operator dla każdej z podtablic
        'after' => '', // ciąg znaków lub tablica, pozwala określić zakres dat
        'before' => '', // ciąg znaków lub tablica, pozwala określić zakres dat
        'inclusive' => false, // wartość logiczna określa czy daty z after i before będą włączane w zakres badanego przedziału
        'year' => '', // liczba 4-cyfrowa lub tablica, określa lata
        'month' => ''. // liczba z zakresu 1-12 lub tablica, określa miesiące
        'week' => '', // liczba z zakresu 0-53 lub tablica, określa tygodnie
        'day' => '', // liczba z zakresu 1-31 lub tablica, określa dni
        'hour' => '', // liczba z zakresu 0-23 lub tablica, określa godziny
        'minute' => '', // liczba z zakresu 0-59 lub tablica, okresla minuty
        'second' => '', // liczba z zakresu 0-59 lub tablica, określa sekundy
        'dayofweek' => '', // liczba z zakresu 1-7 lub tablica, określa dni tygodnia
        'dayofyear' => '' // liczba z zakresu 1-366 lub tablica, określa dni roku
    ),
    array(
        ...
    ),
    ..
)

Garść przykładów

Zacznijmy od prostego przypadku – pobranie wpisów utworzonych po godzinie 12:

'date_query' => array(
        array(
            'hour' => 12,
            'compare' => '>'
        )
)

Jak widać musimy jedynie okreslić godzinę oraz operator porównania. Dodajmy to tego teraz warunek, że wpisy będą utworzone po godzinie 12 ale NIE później niż o godzinie 18:

'date_query' => array(
        array(
            'hour' => 12,
            'compare' => '>'
        ),
        array(
            'hour' => 18,
            'compare' => '<='
        )
)

Dodaliśmy kolejny warunek, który korzysta z faktu, że parametr relation ma domyślnie wartość AND – dla odmiany zmieńmy zakres: niech zapytanie pobierze tylko te wpisy, które powstały przed godziną 12 LUB po godzinie 18:

'date_query' => array(
        'relation' => 'OR',
        array(
            'hour' => 12,
            'compare' => '<'
        ),         
        array(
            'hour' => 18,
            'compare' => '>'
        )
)

Jak widać musieliśmy nie tylko zmienić operatory porówania, ale też i sposób łączenia argumentów z koniunkcji na alternatywę. Rozbudujmy nasz przykład jeszcze bardziej – do poprzedniego ograniczenia dodajmy jeszcze ograniczenie roku (chcemy wpisy tylko z roku 2013) oraz dni tygodnia (chcemy tylko wpisów z dni poniedziałek-piątek):

'date_query' => array(
        'relation' => 'OR',
        array(
            'hour' => 12,
            'compare' => '<'
        ),         
        array(
            'hour' => 18,
            'compare' => '>'
        ),
        array(
            'year' => 2013
        ),
        array(
            'dayofweek' => array(1,5),
            'compare' => 'BETWEEN'
        )
)

I tutaj pojawia się mały problem – nie możemy w trakcie definiowania data query zmienić operatora – w powyższym wypadku pokazany byłby każdy wpis, który spełniałby wspomniane warunki, podczas gdy my chcielibyśmy aby warunek wyglądał tak:

(godzina < 12 LUB godzina > 18) I rok = 2013 I dzień tygodnia z zakresu 1-5

Na szczęście możemy się uratować poniższym zapisem:

'date_query' => array(
        array(
            'hour' => array(12, 18),
            'compare' => 'NOT BETWEEN'
        ),
        array(
            'year' => 2013
        ),
        array(
            'dayofweek' => array(1,5),
            'compare' => 'BETWEEN'
        )
    ),

Wykorzystaliśmu tutaj fakt iż parametry typu godzina, minuta itd. przyjmują też jako argument tablice, które możemy porównywać z użyciem operatora podanego w compare, dodatkowo przywróciliśmy domyślny operator porównania AND usuwając wartość arugmentu relation.

Na koniec przykład użycia argumentów before i after.

Jak już zostało opisane w kodzie na początku – oba argumenty przyjmują tablicę lub ciąg znaków jako wartość. Przykładowo określmy ramy czasowe na dni pomiędzy 28 a 29 września z użyciem ciągów znaków:

'date_query' => array(
        array(
            'before' => '2013-9-29',
            'after' => '2013-9-28'
        )
    ),

Warto zauważyć, że zastosowaliśmy skrócone daty, zatem zostaną one rozwinięte odpowiednio do postaci:

2013-09-29 00:00:00
2013-09-28 00:00:00

Pamiętajmy, że jeżeli nie musimy stosować parametrów inclusive lub compare o różnych wartościach to nie musimy rozdzielać naszych warunków na oddzielne tablice.

Pora na dłuższą składnię, wykrzystującą tablice:

array(
    'before' => array(
                        'year' => 2013,
                   	'month' => 9,
                   	'day' => 29
                     ),
    'after' => array(
                   	'year' => 2013,
                   	'month' => 9,
                   	'day' => 28
                     )
)

Ktoś może zapytać czy jest w ogóle sens stosować drugi dłuższy zapis? Otóż istnieje pewna subtelna różnica pomiędzy podaniem jako argumentu ciągu znaków a podaniem tablicy – w drugim wypadku wartość określona w argumencie after jest rozwijana do postaci:

2013-09-28 23:59:59

Wynika to z faktu iż kod parsujący argumenty na tą chwilę nie sprawdza w wypadku ciągu znaków czy określono godzinę i nie korzysta z drugiego argumentu metody build_mysql_datetime, który określa czy ma być ustawiona minimalna czy maksymalna wartość poszczególnych elementów daty.

Podsumowanie

Warto pamiętać, że opisywana funkcjonalność może w mniejszym lub większym stopniu ulec jeszcze zmianom przed wydaniem WordPressa 3.7, myślę jednak, że warto o niej wiedzieć i znać jej możliwości by móc już teraz uwzględnić jej potencjał w przyszłych wersjach swoich rozszerzeń dla WordPressa.