Вопрос или проблема
У меня есть пользовательский тип записи с названием ‘Real estate’, который имеет (среди прочего) две разные таксономии:
- ‘Purpose’ (иерархическая; используемые термины: ‘Living’, ‘Working’ и ‘Holidays’) и
- ‘Location’ (неиерархическая; например, ‘London’, ‘Berlin’, ‘Paris’).
Для формы поиска в архиве таксономии ‘Living’ мне нужен список всех терминов ‘Location’, связанных с записями в архиве термина таксономии ‘Living’, чтобы вернуть его через селектор в форме поиска. Как я могу, лучше всего в виде списка значений, разделённых запятыми для массива, получить все термины для ‘Location’, использованные в архиве термина ‘Living’?
Ладно, мне кажется, у меня есть что-то для вас! Как вы знаете, у меня была такая же проблема, и когда я перебирал каждую таксономию, я обнаружил, что генерирую от 25 до 35 запросов, что безумие! Поэтому я решил попробовать работать с некоторыми запросами MySQL в таблице отношений терминов, чтобы посмотреть, нет ли более быстрого способа запрашивать данные.
С помощью отличного разработчика, которого я знаю (Mac McDonald http://wordpress.mcdspot.com/), я создал функцию, которая делает один запрос и возвращает массив идентификаторов терминов в “другой” таксономии. Сначала вам нужно подготовить идентификаторы терминов для запроса, вот так:
//таксономия, для которой мы хотим проверить термины
$opposite_taxonomy_terms = get_terms( $taxonomy );
//новый массив, с текущим идентификатором термина, очень важно!
$sibling_term_ids = array( $this_term->term_id );
foreach( $opposite_taxonomy_terms as $term )
{
//собираем все идентификаторы, готовые для создания запроса MySQL
$sibling_term_ids[] = $term->term_id;
}
$imploded = implode(', ', $sibling_term_ids );
$results = rd_get_opposite_terms( $imploded, $this_term->term_id );
Я получаю термины, которые хочу “проверить”, и затем добавляю их в массив, который должен содержать основной идентификатор термина, по которому выполняется запрос. Затем я конкатенирую их, чтобы получить список, разделённый запятыми, для запроса MySQL. Это находится в функции rd_get_opposite_terms()
;
function rd_get_opposite_terms( $imploded = array(), $current_term_id = FALSE )
{
if( empty( $imploded ) || ! $current_term_id )
return FALSE;
global $wpdb;
//выполняем запрос, чтобы найти термины, у которых есть записи как в $current_term_id (из одной таксономии), так и в терминах $imploded (идентификаторы терминов из другой таксономии). Возвращает идентификаторы в виде массива.
return $wpdb->get_col( 'SELECT tr1.term_taxonomy_id FROM wp_term_relationships tr1 WHERE tr1.term_taxonomy_id IN ( ' . $imploded . ' ) AND tr1.object_id IN (SELECT DISTINCT object_id FROM wp_term_relationships tr2 WHERE tr2.term_taxonomy_id = ' . $current_term_id . ' ) GROUP BY tr1.term_taxonomy_id' );
}
Признаюсь, это почти предел моих возможностей разработки на данный момент, но я думаю, это гораздо лучшее решение, чем то, что у меня было изначально, и надеюсь, оно поможет и вам!
Ответ или решение
Ваша задача состоит в том, чтобы получить список терминов таксономии “Локация”, которые ассоциированы с постами в термине “Жильё” таксономии “Цель”. Вы хотите использовать эти данные в поисковой форме для отображения в виде списка с возможностью выбора. Для решения этой задачи можно оптимизировать запросы к базе данных, используя один запрос MySQL, который бы возвращал все необходимые термины в одном из запросов.
Шаги для решения задачи:
-
Подготовка терминов для запроса:
- Первоначально, вы извлекаете все термины таксономии, с которой хотите работать (
get_terms()
), например, "Цель". - Создайте массив идентификаторов терминов, включая идентификатор текущего термина, который вас интересует.
- Первоначально, вы извлекаете все термины таксономии, с которой хотите работать (
-
Создание MySQL запроса:
- Используйте массив идентификаторов терминов для построения списка через
implode()
. Это создаст строку из чисел, разделённых запятыми, которая будет использоваться в запросе. - Далее создайте функцию
rd_get_opposite_terms()
, которая выполнит MySQL запрос для получения терминов таксономии "Локация", связанных с вашими условиями.
- Используйте массив идентификаторов терминов для построения списка через
-
Запрос и получение данных:
- Выполняется запрос к базе данных, который извлекает ID терминов таксономии "Локация", где объект идентичен объекту из термины "Жильё" таксономии "Цель".
- Запрос использует аргумент группы
GROUP BY
для получения уникальных терминов.
Пример кода:
function rd_get_opposite_terms($imploded = array(), $current_term_id = FALSE)
{
if (empty($imploded) || !$current_term_id)
return FALSE;
global $wpdb;
return $wpdb->get_col('SELECT tr1.term_taxonomy_id
FROM wp_term_relationships tr1
WHERE tr1.term_taxonomy_id IN (' . $imploded . ')
AND tr1.object_id IN (SELECT DISTINCT object_id
FROM wp_term_relationships tr2
WHERE tr2.term_taxonomy_id = ' . $current_term_id . ')
GROUP BY tr1.term_taxonomy_id');
}
Рекомендации:
- Убедитесь, что используете
wpdb->prepare()
для защиты от SQL-инъекций, если переменные передаются в запрос напрямую. - Подумайте о кэшировании результатов запроса, чтобы уменьшить нагрузку на базу данных при повторных запросах.
Эта методика позволяет значительно сократить количество запросов к базе данных и повысить производительность вашего WordPress сайта. Надеюсь, что вы найдете это решение полезным и эффективным для вашей задачи.