Tutorial: Jak znaleźć wolne meta_query i przepisać je na filtr taksonomii

Management Summary
Filtry produktów pomagają znaleźć artykuły według cech, takich jak kolor lub materiał. W WordPressie sposób przechowywania tych cech może niepotrzebnie spowalniać wyszukiwanie. Taksonomie, czyli uporządkowane kategorie przypisane produktom, bywają lepszym rozwiązaniem niż wiele osobnych pól dodatkowych. Artykuł wyjaśnia tę przebudowę i powód, dla którego szybkość ma wartość tylko przy zachowaniu właściwych produktów, kolejności i dostępności. Istniejące struktury WooCommerce również wpływają na zasadność zmiany.
Spis treści
Taksonomia przypisuje produkty do nazwanych cech, takich jak kolor lub materiał. Wolny filtr produktów wymaga pomiaru przed zmianą modelu danych. meta_query może być właściwym rozwiązaniem, a taksonomia może pomóc przy filtrowaniu kategorii. Sama liczba złączeń ani różnych wartości nie wskazuje szybszego wariantu. Najpierw nowa kwerenda musi nadal wybierać te same produkty.
1. Zachowanie całego filtra
Przykład wyszukuje opublikowane produkty o kolorze blau, materiale eiche i dostępności 1. Oba warianty muszą zachować trzy warunki, kolejność i podział na strony. Dostępność pozostaje tutaj warunkiem metadanych.
<?php
$base = [
'post_type' => 'produkt',
'post_status' => 'publish',
'posts_per_page' => 20,
'paged' => 1,
'orderby' => ['date' => 'DESC', 'ID' => 'DESC'],
];
$before = new WP_Query($base + [
'meta_query' => [
'relation' => 'AND',
['key' => 'farbe', 'value' => 'blau'],
['key' => 'material', 'value' => 'eiche'],
['key' => 'verfuegbar', 'value' => '1'],
],
]);
$after = new WP_Query($base + [
'tax_query' => [
'relation' => 'AND',
['taxonomy' => 'farbe', 'field' => 'slug',
'terms' => ['blau'], 'include_children' => false],
['taxonomy' => 'material', 'field' => 'slug',
'terms' => ['eiche'], 'include_children' => false],
],
'meta_query' => [
['key' => 'verfuegbar', 'value' => '1'],
],
]);
// SQL: $before->request and $after->request
Kod zakłada istniejący własny typ wpisu produkt oraz obie taksonomie z poprawnymi przypisaniami. Nie jest to zapytanie WooCommerce. Porównanie wykonuje dwa zapytania; aplikacja korzystałaby z wybranego wariantu. Kontrola zgodności musi obejmować wszystkie istotne strony i kombinacje filtrów, a nie tylko pierwszych dwadzieścia wyników.

2. Kontrola rzeczywistego SQL i planu
$query->request zawiera wygenerowany SQL. Trzy dodatnie warunki metadanych połączone przez AND zwykle wymagają w tym przykładzie trzech złączeń. Nie istnieje jednak uniwersalna zasada „jedna klauzula, jedno złączenie”: zgodne klauzule OR mogą współdzielić alias. Logiczne aliasy nie są fizycznymi kopiami tabeli bazy danych.
Standardowy schemat WordPressa indeksuje post_id i prefiks meta_key, lecz nie meta_value. Konkretna instalacja może mieć dodatkowe indeksy. Optymalizator może rozpocząć od tabeli wpisów lub innej ścieżki dostępu; nie zawsze przegląda wszystkie wiersze danego klucza. Powielone metadane mogą zwiększać wyniki pośrednie.
W chronionym wywołaniu deweloperskim SAVEQUERIES zapisuje SQL, czas wykonania i informacje o wywołaniu. Zwiększa zużycie pamięci i obciążenie; logi mogą zawierać poufne wartości. Dziennik wolnych zapytań bazy daje inną perspektywę i nie dostarcza tej samej ścieżki wywołań PHP. Włączenie wymaga odpowiednich uprawnień, ograniczonego czasu pomiaru i oceny ilości logów. Zmiana globalnej wartości domyślnej sesji nie aktualizuje wszystkich istniejących połączeń.
EXPLAIN przedstawia plan szacunkowy. rows i filtered wymagają wspólnej interpretacji z kolejnością złączeń, typem dostępu i wybranymi indeksami. Duże oszacowanie nie dowodzi nieskuteczności filtra. Using filesort oznacza dodatkowe sortowanie, niekoniecznie na dysku. Using temporary samo w sobie nie dowodzi złego zapytania. MySQL EXPLAIN ANALYZE rzeczywiście wykonuje instrukcję; składnia i zachowanie MariaDB wymagają osobnej kontroli.
meta_value_num sortuje liczbowo. WordPress używa wyrażenia numerycznego, a nie porównania tekstu. Wyrażenia i duże wyniki pośrednie mogą zwiększać koszt, lecz wcześniejsze twierdzenie o zwykle większym koszcie sortowania niż wszystkich filtrów nie miało podstawy pomiarowej.
3. Rejestracja obu cech kategorialnych
<?php
add_action('init', function () {
foreach (['farbe', 'material'] as $taxonomy) {
register_taxonomy($taxonomy, ['produkt'], [
'hierarchical' => false,
'public' => false,
'publicly_queryable' => false,
'show_ui' => true,
'show_admin_column' => true,
'show_in_rest' => false,
'query_var' => false,
'rewrite' => false,
]);
}
});
Rejestrowane są zarówno farbe, jak i material. Przykład wyłącza publiczne zapytania taksonomii i reguły adresów, zachowując zarządzanie. Nie tworzy to kontroli dostępu. Edytor blokowy wymaga odpowiedniej konfiguracji REST, w tym show_in_rest; udostępnianie danych i uprawnienia REST wymagają osobnej decyzji.
term_relationships zawiera identyfikator obiektu, identyfikator terminu taksonomii i kolejność terminu. Złożony klucz główny zaczyna się od ID obiektu, a osobny indeks od ID terminu taksonomii. Te ścieżki dostępu mogą pomagać w dokładnym dopasowaniu kategorii. Indeks złożony nie działa automatycznie równie dobrze od obu końców. Cecha tak–nie nie jest z zasady nieodpowiednia dla taksonomii. Status publikacji nie powinien zmieniać znaczenia wyłącznie po to, by oznaczać dostępność magazynową.
4. Plan migracji przed zapisem
Poniższy plan.php wyłącznie odczytuje dane. Zawiera dwa przykładowe ID i jawne mapowanie wartości; obie listy wymagają dostosowania do faktycznych danych. Docelowe terminy muszą już istnieć. Nieznane, puste, powielone lub złożone metadane zatrzymują plan zamiast cicho gubić informacje. Puste wartości wymagają określonej polityki: zachowania przypisania, usunięcia albo skierowania do kontroli.
<?php
// Read-only example for reviewed IDs, not a complete migration runner.
$ids = [101, 102];
$mapping = [
'farbe' => ['blau' => 'blau', 'rot' => 'rot'],
'material' => ['eiche' => 'eiche', 'buche' => 'buche'],
];
$plan = [];
foreach ($ids as $id) {
if (get_post_type($id) !== 'produkt') {
throw new RuntimeException("Unexpected post type: $id");
}
foreach ($mapping as $taxonomy => $values) {
if (!taxonomy_exists($taxonomy)) {
throw new RuntimeException("Missing taxonomy: $taxonomy");
}
$raw = get_post_meta($id, $taxonomy, false);
if (count($raw) !== 1 || !is_string($raw[0])
|| !array_key_exists($raw[0], $values)) {
throw new RuntimeException("Unmapped or ambiguous value: $id/$taxonomy");
}
$term = get_term_by('slug', $values[$raw[0]], $taxonomy);
if (!$term || is_wp_error($term)) {
throw new RuntimeException("Missing target term: $id/$taxonomy");
}
$old = wp_get_object_terms($id, $taxonomy, ['fields' => 'ids']);
if (is_wp_error($old)) {
throw new RuntimeException($old->get_error_message());
}
$plan[] = [
'post_id' => $id,
'taxonomy' => $taxonomy,
'source_value' => $raw[0],
'old_term_ids' => array_map('intval', $old),
'new_term_ids' => [(int) $term->term_id],
];
}
}
echo wp_json_encode($plan, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
wp eval-file plan.php wypisuje proponowane przypisania. Nie zmienia terminów ani metadanych. Pełna migracja wymaga ponadto ograniczonych partii, kopii wartości źródłowych i starych przypisań, przerwy w zapisie albo synchronizacji wszystkich źródeł zmian oraz sprawdzonego wznawiania.
Po kontroli planu i ponownym porównaniu bieżących wartości oraz starych przypisań poniższy fragment API stosuje jeden wiersz. Całkowite ID terminów zapobiegają pomyleniu z nazwami składającymi się z cyfr. Argument false zastępuje przypisania w tej taksonomii, więc dotychczasowe terminy mogą zniknąć.
<?php
// Fragment for one previously reviewed and revalidated plan row.
$result = wp_set_object_terms(
(int) $row['post_id'],
array_map('intval', $row['new_term_ids']),
$row['taxonomy'],
false
);
if (is_wp_error($result)) {
throw new RuntimeException($result->get_error_message());
}
// Read back term IDs and compare them with new_term_ids.
Fragment nie wykonuje wszystkich zmian jako jednej operacji, która albo kończy się w całości, albo zostaje w całości cofnięta. Każdy zapis wymaga ponownego odczytu i obsługi błędów; późniejsza awaria nie cofa automatycznie wcześniejszych wierszy. Stary plan może nadpisać nowsze zmiany taksonomii. Automatyczna normalizacja slugu może połączyć różne wartości źródłowe, dlatego mapowanie jest jawne.
5. Weryfikacja przed wycofaniem metadanych
Porównanie obejmuje ID wyników, kolejność, liczby trafień, brakujące wartości, powielone metadane, szkice i wpisy zaplanowane w zakresie migracji oraz ewentualne przypisania wielojęzyczne. Pomiar czasu wymaga porównywalnych danych, indeksów, pamięci podręcznej i obciążenia. Dla wcześniejszych liczb 480 000 wobec 2 100 przeglądanych wierszy na grafice nie ma odtwarzalnego pomiaru.
Wcześniejsze polecenie wp post meta delete --all --keys=farbe --dry-run było niepoprawne dla tego zadania. Udokumentowane polecenie wymaga ID obiektu; --all oznacza wszystkie metadane tego obiektu, a taki przełącznik dry-run nie jest udokumentowany. Stare metadane powinny pozostać do wyjaśnienia zapisów, porównań i możliwości powrotu. Czyszczenie wymaga osobnego, jawnego zakresu oraz kopii danych.
Pytania i odpowiedzi
Kiedy inny model danych jest korzystniejszy?
Zakresy liczbowe mogą korzystać z typowanych indeksowanych kolumn lub istniejącej tabeli pomocniczej. Małe lub selektywne zapytania metadanych mogą już działać szybko. Ani tysiące terminów, ani kilka pasujących wierszy nie wyznaczają uniwersalnego progu. Indeksy pełnotekstowe dzielą tekst na tokeny i nie obsługują automatycznie dowolnych fragmentów słowa.
Co zmienia WooCommerce?
Najpierw potrzebna jest kontrola istniejących atrybutów, reguł widoczności i tabel pomocniczych. Typ produktu i interfejsy danych WooCommerce różnią się od fikcyjnego przykładu. Równoległa własna taksonomia nie może omijać magazynu, widoczności, tłumaczeń ani działania rozszerzeń.