Pozwól, że wyjaśnię przetwarzanie żądania przez WordPress oraz metodę zmiany zachowania WordPress, aby odpowiednio zrealizować twoje cele.
Przetwarzanie żądania
Kiedy WordPress otrzymuje żądanie, rozpoczyna proces jego analizy i przekształcenia w stronę. Rdzeń tego procesu rozpoczyna się, gdy WP::main()
wywoływana jest główna metoda zapytania WordPress . Ta funkcja analizuje zapytanie, jak poprawnie zidentyfikowano, w parse_request()
(in includes/class-wp.php
). Tam WordPress próbuje dopasować adres URL do jednej z reguł przepisywania . Gdy adres URL jest dopasowany, tworzy ciąg zapytania z części URL i koduje te części (wszystko między dwoma ukośnikami) za pomocą urlencode()
, aby zapobiec wprowadzaniu przez znaki specjalne, takie jak &
bałagan zapytania. Te zakodowane znaki mogły sprawić, że pomyślałeś, że problem tam występował, ale w rzeczywistości zostały one przekształcone w odpowiadające im „prawdziwe” znaki podczas analizowania ciągu zapytania.
Uruchomienie zapytania związanego z żądaniem
Po przeanalizowaniu adresu URL WordPress ustawia główną klasę zapytania WP_Query
, co odbywa się w tej samej main()
metodzie WP
klasy. Wołowinę WP_Query
można znaleźć w jej get_posts()
metodzie, w której wszystkie argumenty zapytania są analizowane i odkażane, a rzeczywiste zapytanie SQL jest konstruowane (i ostatecznie uruchamiane).
W metodzie tej w wierszu 2730 wykonywany jest następujący kod:
$q['name'] = sanitize_title_for_query( $q['name'] );
To dezynfekuje post za pobranie go z tabeli postów. Wyprowadzanie informacji o debugowaniu w pętli pokazuje, że na tym polega problem: nazwa posta my-permalink~
zostaje przekształcona na my-permalink
, która jest następnie używana do pobrania postu z bazy danych.
Funkcja odkażania tytułu postu
Funkcja sanitize_title_for_query
wywołuje sanitize_title
odpowiednie parametry, które następnie odkażają tytuł. Teraz rdzeniem tej funkcji jest zastosowanie sanitize_title
filtra:
$title = apply_filters( 'sanitize_title', $title, $raw_title, $context );
Filtr ten ma w natywnej WordPress, jedna funkcja z nim związane: sanitize_title_with_dashes
. Napisałem obszerny przegląd działania tej funkcji, który można znaleźć tutaj . W tej funkcji linia powodująca problem to
$title = preg_replace('/[^%a-z0-9 _-]/', '', $title);
Ta linia usuwa wszystkie znaki oprócz znaków alfanumerycznych, spacji, łączników i znaków podkreślenia.
Rozwiązywanie problemu
Jest więc zasadniczo jeden sposób rozwiązania problemu: usunięcie sanitize_title_with_dashes
funkcji z filtra i zastąpienie jej własną funkcją. Nie jest to wcale takie trudne, ale :
- Gdy WordPress zmieni wewnętrzny proces odkażania tytułów, będzie to miało duży wpływ na twoją stronę.
- Inne wtyczki podpinające się do tego filtra mogą niepoprawnie obsługiwać nową funkcjonalność.
Co najważniejsze : WordPress używa wyniku sanitize_title
funkcji bezpośrednio w zapytaniu SQL w tym wierszu:
$where .= " AND $wpdb->posts.post_name = '" . $q['name'] . "'";
Jeśli kiedykolwiek zastanowisz się nad zmianą filtru, upewnij się, że właściwie unikniesz tytułu przed użyciem go w zapytaniu!
Wniosek: rozwiązanie problemu nie jest konieczne ze względów bezpieczeństwa, ale jeśli chcesz to zrobić, zamień na sanitize_title_with_dashes
własną funkcjonalność i zwróć uwagę na ucieczkę SQL.
Uwaga: wszystkie nazwy plików i numery linii odpowiadają plikom WordPress 4.4.2.