Заказ постов типа A по пользовательским полям связанного поста типа B

Вопрос или проблема

Я не уверен, возможно ли это вообще (также опубликовано на форуме ACF https://support.advancedcustomfields.com/forums/topic/ordering-by-custom-field-of-relationship-field-object/#post-62454)

У меня есть два пользовательских типа записей: произведения искусства и художники. Произведения искусства имеют поле объекта поста ACF ‘artists_name’, связывающее его с одним художником. У художников есть пользовательские поля ‘artist_last_name’ и ‘artist_first_name’. На архивной странице произведений искусства записи сортируются по meta_value с meta_key ‘artists_name’, но, конечно, она сортирует по ID поста.

Я пытаюсь заставить запрос сортировать по фамилии связанного художника, затем по имени. (Т.е. я хочу использовать значение метаданных из типа записи B для сортировки типа записи A.)

Пока что у меня есть этот запрос, который работает, как и ожидалось:

$args = array(
    'post_type'         => 'artworks',
    'posts_per_page'    => -1,
    'meta_key'          => 'artists_name',
    'orderby'           => 'meta_value'
);

Затем я пытаюсь получить фильтр posts_join, чтобы найти метаданные поста, чей ID поста = meta_value ‘artists_name’

add_filter('posts_join', 'trial_join', 10, 2 );
function trial_join($joins) {
    if(is_post_type_archive('artworks') || (is_admin() && $_GET['post_type'] == 'artworks')) {
    global $wpdb;        
    $joins .= "  INNER JOIN {$wpdb->postmeta} artists_name ON artists_name.post_id={$wpdb->posts}.ID WHERE artists_name.meta_key='artist_last_name'" ;
    $joins .= "  INNER JOIN {$wpdb->postmeta} first_name ON first_name.post_id={$wpdb->posts}.ID WHERE (first_name.meta_key='artist_first_name' AND first_name.post_ID=artists_name.meta_value)";
    $joins .= "  INNER JOIN {$wpdb->postmeta} last_name ON last_name.post_id={$wpdb->posts}.ID WHERE (last_name.meta_key='artist_last_name' AND last_name.post_ID=artists_name.meta_value)";
    }
    return $joins;
}

И затем использовать фильтр posts_orderby:

add_filter('posts_orderby', 'orderby_pages_callback', 10, 2);
function orderby_pages_callback($orderby_statement, $wp_query) {
    $orderby_statement = "last_name.meta_value first_name.meta_value ASC";
    return $orderby_statement;
}

Но это не работает. Я собрал соединение из кучи других сообщений. Есть какие-нибудь предложения?

Это работает. Фильтры привязаны к пользовательскому 'orderby' термину и удаляются после запроса.

$args = array(
    'post_type'         => 'artworks',
    'posts_per_page'    => -1,
    'no_found_rows'     => true,
    'order'             => 'ASC',
    'orderby'           => 'artist_name_artwork_title',
);

add_filter('posts_join', 'name_join', 10, 2 );
add_filter('posts_orderby', 'orderby_artist_name_artwork_title', 10, 2);

// запрос
$wp_query = new WP_Query( $args );
remove_filter('posts_join', 'name_join', 10 );
remove_filter('posts_orderby', 'orderby_artist_name_artwork_title', 10 );

function name_join($joins, $wp_query) {
    if ( $wp_query->get( 'orderby' ) != 'artist_name_artwork_title' ) {
        return $joins;
    }   
    global $wpdb;        
    $joins .= "  LEFT JOIN $wpdb->postmeta name ON name.post_id=$wpdb->posts.ID AND name.meta_key='artists_name'" ;
    $joins .= "  LEFT JOIN $wpdb->postmeta lastname ON lastname.post_id=name.meta_value AND lastname.meta_key='artist_last_name'";
    $joins .= "  LEFT JOIN $wpdb->postmeta firstname ON firstname.post_id=name.meta_value AND firstname.meta_key='artist_first_name'";
    return $joins;
}

function orderby_artist_name_artwork_title($orderby_statement, $wp_query) {
    if ( $wp_query->get( 'orderby' ) != 'artist_name_artwork_title' ) {
        return $orderby_statement;
    }   
    global $wpdb;
    $orderby_statement = "lastname.meta_value, firstname.meta_value, $wpdb->posts.post_title";
    return $orderby_statement;
}

Ответ или решение

Заказ Постов Типа "Искусство" по Пользовательским Полям Связанного Поста Типа "Художники"

В данной статье мы разберем, как упорядочить посты одного пользовательского типа (в данном случае "Искусство") по пользовательским полям, связанным с другим пользовательским типом ("Художники"). Для этого мы воспользуемся специфическими фильтрами во WordPress для изменения SQL-запроса, чтобы извлечь данные из пользовательских полей, принадлежащих связанным записям.

1. Описание проблемы

Вы имеете два пользовательских типа:

  • Искусство (Artworks) с пост объектом artists_name, который связывает его с одним художником.
  • Художники (Artists), содержащими пользовательские поля: artist_last_name и artist_first_name.

При этом вы столкнулись с необходимостью упорядочить посты типа "Искусство" не по ID художника, а по его фамилии и имени, что требует подключения информации из полей другого пользовательского типа.

2. Решение через WP_Query

Ваше начальное решение с использованием WP_Query выглядит следующим образом:

$args = array(
    'post_type'         => 'artworks',
    'posts_per_page'    => -1,
    'meta_key'          => 'artists_name',
    'orderby'           => 'meta_value'
);

3. Использование фильтров posts_join и posts_orderby

Для достижения желаемого упорядочивания необходимо использовать фильтры posts_join и posts_orderby. Давайте разберем реализацию:

3.1. Фильтр posts_join

Этот фильтр позволяет изменить SQL-запрос, добавив необходимые соединения (JOIN) к таблицам метаданных:

add_filter('posts_join', 'name_join', 10, 2);
function name_join($joins, $wp_query) {
    if ($wp_query->get('orderby') != 'artist_name_artwork_title') {
        return $joins;
    }
    global $wpdb;
    $joins .= " LEFT JOIN $wpdb->postmeta AS name ON name.post_id = $wpdb->posts.ID AND name.meta_key = 'artists_name' ";
    $joins .= " LEFT JOIN $wpdb->postmeta AS lastname ON lastname.post_id = name.meta_value AND lastname.meta_key = 'artist_last_name' ";
    $joins .= " LEFT JOIN $wpdb->postmeta AS firstname ON firstname.post_id = name.meta_value AND firstname.meta_key = 'artist_first_name' ";
    return $joins;
}
3.2. Фильтр posts_orderby

Фильтр posts_orderby используется для определения порядка сортировки:

add_filter('posts_orderby', 'orderby_artist_name_artwork_title', 10, 2);
function orderby_artist_name_artwork_title($orderby_statement, $wp_query) {
    if ($wp_query->get('orderby') != 'artist_name_artwork_title') {
        return $orderby_statement;
    }
    global $wpdb;
    $orderby_statement = "lastname.meta_value, firstname.meta_value, $wpdb->posts.post_title";
    return $orderby_statement;
}

4. Завершение запроса

Ваша финальная реализация будет выглядеть следующим образом:

$args = array(
    'post_type'         => 'artworks',
    'posts_per_page'    => -1,
    'no_found_rows'     => true,
    'order'             => 'ASC',
    'orderby'           => 'artist_name_artwork_title',
);

// Выполняем запрос
$wp_query = new WP_Query($args);

// Убираем фильтры после выполнения запроса
remove_filter('posts_join', 'name_join', 10);
remove_filter('posts_orderby', 'orderby_artist_name_artwork_title', 10);

Заключение

Используя предложенные решения, вы сможете настроить упорядочивание постов типа "Искусство" на основе полей поста типа "Художники". Данная методика позволит создать более интуитивный и удобный интерфейс для отображения данных на ваших страницах. Не забывайте тестировать код в безопасной среде перед развертыванием на рабочем сайте, чтобы избежать непредвиденных ошибок и сбоев в работе.

Если у вас остались вопросы или требуется дополнительная помощь, не стесняйтесь обращаться к сообществу или форумах WordPress.

Оцените материал
Добавить комментарий

Капча загружается...